@@ -23,17 +23,27 @@ public class ArmourBlocksAnswerForThemselvesE2ETest extends AbstractSharedServer
2323 private static final int Y = 70 , X = 2100 ;
2424 private static final int MIRROR_Z = 1200 , MIRROR_SLUG_Z = 1220 , BETTER_Z = 1240 ;
2525 private static final int REACTIVE_Z = 1260 , REACTIVE_TWICE_Z = 1280 , RAILGUN_Z = 1300 ;
26+ private static final int PRICE_Z = 1320 ;
2627
2728 private static final double SPEED = 0.45D ;
2829 private static final Pattern ID = Pattern .compile ("\" id\" :(-?\\ d+)" );
2930 private static final Pattern VX = Pattern .compile ("\" vx\" :(-?[\\ d.eE+-]+)" );
31+ private static final Pattern STAGE_COST = Pattern .compile ("\" stageCost\" :(-?\\ d+)" );
3032
3133 /**
32- * A mirror returns a beam and lets a slug through, and the difference is the kind in the contact
33- * and nothing else — the same block, the same face, the same energy.
34+ * A mirror returns a beam and is SMASHED by a solid round, and the difference is the kind in the
35+ * contact and nothing else — the same block, the same face, the same energy.
36+ *
37+ * <p>The second half used to read "lets a solid round straight through", and it was pinning a
38+ * defect. A mirror has no OPTICAL opinion about a solid round, and it said so by answering "passed
39+ * through, carrying everything" — which is not "no opinion", it is "through, for free". So the
40+ * round paid nothing, the film was untouched, and the one armour a beam could strip was the one
41+ * kinetic fire could not. The block now DECLINES, and declining hands the meeting to the ordinary
42+ * law: the film is priced off the table and the eighth of a voxel it fills, and it breaks like the
43+ * glass it is.</p>
3444 */
3545 @ Test
36- public void aMirrorReturnsABeamAndLetsASlugStraightThrough () throws Exception {
46+ public void aMirrorReturnsABeamAndIsSmashedByASolidRound () throws Exception {
3747 prepare (MIRROR_Z );
3848 prepare (MIRROR_SLUG_Z );
3949 place ("advancedrocketry:mirrorPlatingAluminium" , MIRROR_Z );
@@ -47,10 +57,13 @@ public void aMirrorReturnsABeamAndLetsASlugStraightThrough() throws Exception {
4757
4858 long slug = fire (MIRROR_SLUG_Z , 3_000 , "KINETIC" );
4959 assertTrue ("the slug was refused" , slug >= 0 );
50- assertTrue ("a solid round bounced off glass and foil: a mirror has no opinion about a slug,"
51- + " and the kind in the contact is the only thing that separates the two cases: "
52- + read (slug ), !awaitTurnedBack (slug ));
53- assertTrue ("the mirror is still standing after a slug went through it" , stillThere (MIRROR_SLUG_Z ));
60+ assertTrue ("a solid round bounced off glass and foil: a mirror has no OPTICAL opinion about"
61+ + " a solid round, and the kind in the contact is the only thing that separates the"
62+ + " two cases: " + read (slug ), !awaitTurnedBack (slug ));
63+ awaitGone (slug );
64+ assertTrue ("the film is still standing after a solid round crossed it: then the round paid"
65+ + " nothing for it, and a mirror is armour that only the weapon it was built to stop"
66+ + " can remove" , !stillThere (MIRROR_SLUG_Z ));
5467 }
5568
5669 /**
@@ -67,16 +80,26 @@ public void aBetterMirrorSurvivesWhatKillsAWorseOne() throws Exception {
6780 // exceeds what the film sheds, and a thirtieth of it does not.
6881 int killsAluminium = 60_000 ;
6982
70- // CONTROL, and the test is worthless without it: the same energy as a SLUG must leave the
71- // plate standing. Ordinary damage does not know one mirror from another, so if it were doing
72- // the work below, this is where it would show — and the first cut of this test passed with the
73- // whole responder switched off, which is exactly what this catches.
74- long slug = fire (BETTER_Z , killsAluminium , "KINETIC" );
75- assertTrue ("the control round was refused" , slug >= 0 );
76- awaitGone (slug );
77- assertTrue ("a slug carrying what the beams below carry destroyed the plating: then what kills"
78- + " a mirror here is ordinary damage, and nothing in this test is about mirrors" ,
79- stillThere (BETTER_Z ));
83+ // CONTROL, and the test is worthless without it — the first cut of this test passed with
84+ // the whole responder switched off. It used to be a solid round carrying the same energy,
85+ // which had to leave the plate standing; that stopped being available the day such a round
86+ // started paying for the film and breaking it, which is correct and kills the old control.
87+ //
88+ // This is the stronger replacement, and it aims at the mechanism rather than at one sample:
89+ // ordinary damage prices the two tiers IDENTICALLY, so it cannot produce a difference between
90+ // them at all. Whatever separates aluminium from gold below is therefore the reflectance, and
91+ // can be nothing else.
92+ placeAt (X + 4 , BETTER_Z , "advancedrocketry:mirrorPlatingGold" );
93+ long aluminiumCost = costOf (exec ("artest damage stage " + DIM + " " + X + " " + Y + " "
94+ + BETTER_Z ));
95+ long goldCost = costOf (exec ("artest damage stage " + DIM + " " + (X + 4 ) + " " + Y + " "
96+ + BETTER_Z ));
97+ assertTrue ("the two mirror tiers cost different amounts to break by ordinary damage"
98+ + " (aluminium=" + aluminiumCost + " gold=" + goldCost + "): then the ladder below can"
99+ + " be produced without any mirror law at all, and this test measures the toughness"
100+ + " table" , aluminiumCost == goldCost );
101+ placeAt (X + 4 , BETTER_Z , "minecraft:air" );
102+
80103 long first = fire (BETTER_Z , killsAluminium , "BEAM" );
81104 assertTrue ("the beam was refused" , first >= 0 );
82105 awaitGone (first );
@@ -143,6 +166,49 @@ public void twiceTheReactiveVolumeEatsMoreOfTheSameImpact() throws Exception {
143166 clean (X + 2 , RAILGUN_Z ));
144167 }
145168
169+ /**
170+ * A mirror film is priced as the glass and foil it is, not as the hull plate its MATERIAL says.
171+ *
172+ * <p>Both plating families are declared {@code Material.IRON} — which is what they are mined and
173+ * sounded like — and the damage table resolves by material when nothing has written a row. That
174+ * priced a mirror film as solid hull.</p>
175+ *
176+ * <p><b>The comparator is REACTIVE plating, and the choice is the whole test.</b> The obvious
177+ * comparison — a film against a solid block of iron — passes whether or not the mirror has a row
178+ * of its own, because a film fills an eighth of its voxel and the volume alone makes it cheaper.
179+ * It would measure the occupancy factor and report it as evidence about the table. Reactive
180+ * plating is the same class, the same thickness and the same declared material, and it
181+ * deliberately has NO row: its casing IS metal, and what makes it interesting is the charge rather
182+ * than what the charge is wrapped in. So the two differ in exactly one thing, and a difference in
183+ * price can come from exactly one place.</p>
184+ *
185+ * <p>Only the ORDERING is claimed. The numbers behind it are balance and will move; an assertion
186+ * on them would go red the first time anyone retunes the table without breaking anything a player
187+ * would notice.</p>
188+ */
189+ @ Test
190+ public void aMirrorFilmCostsLessToBreakThanTheMetalItsMaterialClaims () throws Exception {
191+ prepare (PRICE_Z );
192+ place ("advancedrocketry:mirrorPlatingAluminium" , PRICE_Z );
193+ placeAt (X + 4 , PRICE_Z , "advancedrocketry:reactivePlate" );
194+
195+ String film = exec ("artest damage stage " + DIM + " " + X + " " + Y + " " + PRICE_Z );
196+ String metal = exec ("artest damage stage " + DIM + " " + (X + 4 ) + " " + Y + " " + PRICE_Z );
197+ long filmCost = costOf (film ), metalCost = costOf (metal );
198+
199+ assertTrue ("a mirror film costs what the identically shaped plating beside it costs (film="
200+ + filmCost + " reactive=" + metalCost + "): the two differ only in that one has a row"
201+ + " of its own, so this says the row is not being read at all and glass with foil on"
202+ + " it still resists like hull plate. film=" + film + " reactive=" + metal ,
203+ filmCost < metalCost );
204+ }
205+
206+ private static long costOf (String json ) {
207+ Matcher m = STAGE_COST .matcher (json );
208+ assertTrue ("no stageCost in: " + json , m .find ());
209+ return Long .parseLong (m .group (1 ));
210+ }
211+
146212 // ---- driving
147213
148214 private long fire (int lane , int energy , String kind ) throws Exception {
0 commit comments