Добавить production-каталог опасностей
This commit is contained in:
@@ -45,6 +45,15 @@ public final class DeterministicInputTapeTest {
|
||||
ReplayStateSignature.of(puzzle, false, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void productionTeachingLevelsCanOwnVersionedInputTapes() {
|
||||
DeterministicInputTape tape = DeterministicInputTape.builder(14)
|
||||
.record(false, true, true, 250L)
|
||||
.build();
|
||||
|
||||
assertEquals(14, tape.levelNumber());
|
||||
}
|
||||
|
||||
private static final class FakeTarget implements DeterministicInputTape.Target {
|
||||
private int level;
|
||||
private long ticks;
|
||||
|
||||
@@ -27,13 +27,16 @@ public final class GameStringsTest {
|
||||
assertEquals("Русский", russian.languageName());
|
||||
assertEquals("Рыцарь-доброволец", russian.levelTitle(1));
|
||||
assertEquals("Последнее шествие", russian.levelTitle(10));
|
||||
assertEquals("Паровой заряд", russian.levelTitle(14));
|
||||
assertEquals("Page 2 of 2", english.pageIndicator(2, 2));
|
||||
assertEquals("Страница 2 из 2", russian.pageIndicator(2, 2));
|
||||
assertEquals("Добровольцы 2 Время 00:07", russian.hudStats(2, 7_000L));
|
||||
assertEquals("✓ 2 добровольца · 00:07", russian.levelBestStats(2, 7_000L));
|
||||
assertEquals("★ 2 / 3 добровольца", russian.completionDeaths(true, 2, 3));
|
||||
assertEquals("Смерть — это инструмент", russian.tutorialWelcomeTitle());
|
||||
assertFalse(russian.tutorialSacrificeBody().trim().isEmpty());
|
||||
|
||||
for (int level = 1; level <= 10; level++) {
|
||||
for (int level = 1; level <= LevelCatalog.all().size(); level++) {
|
||||
assertFalse(russian.levelTitle(level).trim().isEmpty());
|
||||
assertFalse(russian.levelHint(level).trim().isEmpty());
|
||||
assertNotEquals(english.levelTitle(level), russian.levelTitle(level));
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.projectsacrifice.game;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public final class HazardRuntimeTest {
|
||||
@Test
|
||||
public void crusherActiveWindowRepeatsOnItsDataDrivenCycle() {
|
||||
LevelDefinition.Hazard definition = new LevelDefinition.Hazard(
|
||||
LevelDefinition.HazardType.CRUSHER,
|
||||
new LevelDefinition.Box(620f, 690f, 150f, 190f),
|
||||
null, 0f, 180f, 4f, 1.25f, 0f, 0f,
|
||||
"brass-press", "crusher-impact");
|
||||
HazardRuntime runtime = new HazardRuntime(definition);
|
||||
|
||||
assertTrue(runtime.active());
|
||||
runtime.update(1.2f);
|
||||
assertTrue(runtime.active());
|
||||
runtime.update(0.1f);
|
||||
assertFalse(runtime.active());
|
||||
runtime.update(2.7f);
|
||||
assertTrue(runtime.active());
|
||||
runtime.update(4f);
|
||||
assertTrue(runtime.active());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void projectileMovesFromItsSpawnBoxAndWrapsAtTheConfiguredCycle() {
|
||||
LevelDefinition.Hazard definition = new LevelDefinition.Hazard(
|
||||
LevelDefinition.HazardType.PROJECTILE,
|
||||
new LevelDefinition.Box(620f, 790f, 48f, 48f),
|
||||
null, 420f, -120f, 3f, 0f, 360f, 0f,
|
||||
"clockwork-bolt", "projectile-hit");
|
||||
HazardRuntime runtime = new HazardRuntime(definition);
|
||||
|
||||
runtime.update(1f);
|
||||
assertTrue(runtime.currentBox().x == 980f);
|
||||
runtime.update(2f);
|
||||
assertTrue(runtime.currentBox().x == 620f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void explosionHasADataDrivenBlastAndRestWindow() {
|
||||
LevelDefinition.Hazard definition = new LevelDefinition.Hazard(
|
||||
LevelDefinition.HazardType.EXPLOSION,
|
||||
new LevelDefinition.Box(620f, 740f, 140f, 140f),
|
||||
null, 550f, -500f, 4f, 2f, 0f, 0f,
|
||||
"steam-blast", "explosion-blast");
|
||||
HazardRuntime runtime = new HazardRuntime(definition);
|
||||
|
||||
assertTrue(runtime.active());
|
||||
runtime.update(2.1f);
|
||||
assertFalse(runtime.active());
|
||||
runtime.update(1.9f);
|
||||
assertTrue(runtime.active());
|
||||
}
|
||||
}
|
||||
@@ -12,9 +12,9 @@ import java.util.Set;
|
||||
|
||||
public final class LevelCatalogTest {
|
||||
@Test
|
||||
public void verticalSliceContainsTenSequentialLevels() {
|
||||
public void productionCatalogContainsFourHazardTeachingLevelsAfterTheVerticalSlice() {
|
||||
List<LevelDefinition> levels = LevelCatalog.all();
|
||||
assertEquals(10, levels.size());
|
||||
assertEquals(14, levels.size());
|
||||
Set<String> titles = new HashSet<>();
|
||||
for (int i = 0; i < levels.size(); i++) {
|
||||
LevelDefinition level = levels.get(i);
|
||||
@@ -22,6 +22,10 @@ public final class LevelCatalogTest {
|
||||
assertTrue(titles.add(level.title));
|
||||
assertFalse(level.hint.trim().isEmpty());
|
||||
}
|
||||
assertTrue(levels.get(10).containsMechanic(LevelDefinition.HazardType.CRUSHER));
|
||||
assertTrue(levels.get(11).containsMechanic(LevelDefinition.HazardType.FIRE));
|
||||
assertTrue(levels.get(12).containsMechanic(LevelDefinition.HazardType.PROJECTILE));
|
||||
assertTrue(levels.get(13).containsMechanic(LevelDefinition.HazardType.EXPLOSION));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -126,6 +126,94 @@ public final class LevelJsonLoaderTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void crusherLoadsItsCycleImpulseAudioAndVisualSettingsFromData() {
|
||||
String json = validLevelJson(1).replace(
|
||||
"\"hazards\":[],\"switches\":[],\"doors\":[]",
|
||||
"\"hazards\":[{\"type\":\"CRUSHER\","
|
||||
+ "\"box\":{\"x\":620,\"y\":690,\"width\":150,\"height\":190},"
|
||||
+ "\"impulseX\":0,\"impulseY\":180,"
|
||||
+ "\"cycleSeconds\":4,\"activeSeconds\":1.25,"
|
||||
+ "\"speedX\":0,\"speedY\":0,"
|
||||
+ "\"visualStyle\":\"brass-press\",\"audioCue\":\"crusher-impact\"}],"
|
||||
+ "\"switches\":[],\"doors\":[]");
|
||||
|
||||
LevelDefinition.Hazard crusher = LevelJsonLoader.load(
|
||||
new StringReader(json), "crusher.json").hazards.get(0);
|
||||
|
||||
assertEquals(LevelDefinition.HazardType.CRUSHER, crusher.type);
|
||||
assertEquals(4f, crusher.cycleSeconds, 0f);
|
||||
assertEquals(1.25f, crusher.activeSeconds, 0f);
|
||||
assertEquals(180f, crusher.impulseY, 0f);
|
||||
assertEquals("brass-press", crusher.visualStyle);
|
||||
assertEquals("crusher-impact", crusher.audioCue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fireLoadsItsCorpseImpulseAudioAndVisualSettingsFromData() {
|
||||
String json = validLevelJson(1).replace(
|
||||
"\"hazards\":[],\"switches\":[],\"doors\":[]",
|
||||
"\"hazards\":[{\"type\":\"FIRE\","
|
||||
+ "\"box\":{\"x\":700,\"y\":790,\"width\":120,\"height\":90},"
|
||||
+ "\"impulseX\":160,\"impulseY\":-220,"
|
||||
+ "\"visualStyle\":\"blue-flame\",\"audioCue\":\"fire-burst\"}],"
|
||||
+ "\"switches\":[],\"doors\":[]");
|
||||
|
||||
LevelDefinition.Hazard fire = LevelJsonLoader.load(
|
||||
new StringReader(json), "fire.json").hazards.get(0);
|
||||
|
||||
assertEquals(LevelDefinition.HazardType.FIRE, fire.type);
|
||||
assertEquals(160f, fire.impulseX, 0f);
|
||||
assertEquals(-220f, fire.impulseY, 0f);
|
||||
assertEquals("blue-flame", fire.visualStyle);
|
||||
assertEquals("fire-burst", fire.audioCue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void projectileLoadsItsVelocityCycleAudioAndVisualSettingsFromData() {
|
||||
String json = validLevelJson(1).replace(
|
||||
"\"hazards\":[],\"switches\":[],\"doors\":[]",
|
||||
"\"hazards\":[{\"type\":\"PROJECTILE\","
|
||||
+ "\"box\":{\"x\":620,\"y\":790,\"width\":48,\"height\":48},"
|
||||
+ "\"impulseX\":420,\"impulseY\":-120,"
|
||||
+ "\"cycleSeconds\":3,\"activeSeconds\":0,"
|
||||
+ "\"speedX\":360,\"speedY\":0,"
|
||||
+ "\"visualStyle\":\"clockwork-bolt\",\"audioCue\":\"projectile-hit\"}],"
|
||||
+ "\"switches\":[],\"doors\":[]");
|
||||
|
||||
LevelDefinition.Hazard projectile = LevelJsonLoader.load(
|
||||
new StringReader(json), "projectile.json").hazards.get(0);
|
||||
|
||||
assertEquals(LevelDefinition.HazardType.PROJECTILE, projectile.type);
|
||||
assertEquals(3f, projectile.cycleSeconds, 0f);
|
||||
assertEquals(360f, projectile.speedX, 0f);
|
||||
assertEquals("clockwork-bolt", projectile.visualStyle);
|
||||
assertEquals("projectile-hit", projectile.audioCue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void explosionLoadsItsRequiredImpulseAudioAndVisualSettingsFromData() {
|
||||
String json = validLevelJson(1).replace(
|
||||
"\"hazards\":[],\"switches\":[],\"doors\":[]",
|
||||
"\"hazards\":[{\"type\":\"EXPLOSION\","
|
||||
+ "\"box\":{\"x\":720,\"y\":740,\"width\":140,\"height\":140},"
|
||||
+ "\"impulseX\":520,\"impulseY\":-380,"
|
||||
+ "\"cycleSeconds\":4,\"activeSeconds\":2,"
|
||||
+ "\"visualStyle\":\"steam-blast\",\"audioCue\":\"explosion-blast\"}],"
|
||||
+ "\"switches\":[],\"doors\":[]");
|
||||
|
||||
LevelDefinition.Hazard explosion = LevelJsonLoader.load(
|
||||
new StringReader(json), "explosion.json").hazards.get(0);
|
||||
|
||||
assertEquals(LevelDefinition.HazardType.EXPLOSION, explosion.type);
|
||||
assertEquals(520f, explosion.impulseX, 0f);
|
||||
assertEquals(-380f, explosion.impulseY, 0f);
|
||||
assertEquals(4f, explosion.cycleSeconds, 0f);
|
||||
assertEquals(2f, explosion.activeSeconds, 0f);
|
||||
assertEquals("steam-blast", explosion.visualStyle);
|
||||
assertEquals("explosion-blast", explosion.audioCue);
|
||||
}
|
||||
|
||||
static String validLevelJson(int formatVersion) {
|
||||
return "{"
|
||||
+ "\"formatVersion\":" + formatVersion + ","
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.projectsacrifice.game;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public final class LevelPageTest {
|
||||
@Test
|
||||
public void fourteenLevelsUseTwoBoundedTenCardPages() {
|
||||
LevelPage page = new LevelPage(14, 10);
|
||||
|
||||
assertEquals(2, page.pageCount());
|
||||
assertEquals(0, page.firstIndex());
|
||||
assertEquals(10, page.endExclusive());
|
||||
assertFalse(page.hasPrevious());
|
||||
assertTrue(page.hasNext());
|
||||
|
||||
page.next();
|
||||
assertEquals(10, page.firstIndex());
|
||||
assertEquals(14, page.endExclusive());
|
||||
assertTrue(page.hasPrevious());
|
||||
assertFalse(page.hasNext());
|
||||
|
||||
page.next();
|
||||
assertEquals(1, page.pageIndex());
|
||||
page.selectIndex(3);
|
||||
assertEquals(0, page.pageIndex());
|
||||
page.selectIndex(13);
|
||||
assertEquals(1, page.pageIndex());
|
||||
}
|
||||
}
|
||||
@@ -58,6 +58,22 @@ public final class VersionedSessionCodecTest {
|
||||
assertNull(future.snapshot());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void productionTeachingLevelSnapshotRoundTrips() {
|
||||
GameSessionSnapshot snapshot = GameSessionSnapshot.builder(14)
|
||||
.elapsedSeconds(3f)
|
||||
.player(new GameSessionSnapshot.PlayerData(
|
||||
130f, 760f, 0f, 0f, true, true,
|
||||
0f, 0f, -1, 1))
|
||||
.build();
|
||||
|
||||
VersionedSessionCodec.DecodeResult decoded = VersionedSessionCodec.decode(
|
||||
VersionedSessionCodec.encode(snapshot));
|
||||
|
||||
assertEquals(VersionedSessionCodec.Status.RESTORED, decoded.status());
|
||||
assertEquals(14, decoded.snapshot().levelNumber());
|
||||
}
|
||||
|
||||
private static GameSessionSnapshot sampleSnapshot() {
|
||||
return GameSessionSnapshot.builder(5)
|
||||
.elapsedSeconds(12.75f)
|
||||
|
||||
Reference in New Issue
Block a user