|
|
|
@@ -28,6 +28,7 @@ class BasicAttackNativeTest {
|
|
|
|
|
var basic = new games.dmg.fantasystick.combat.BasicAttack(sessions, clock);
|
|
|
|
|
var target = mock(org.bukkit.entity.LivingEntity.class);
|
|
|
|
|
var cancelled = new java.util.concurrent.atomic.AtomicBoolean(true);
|
|
|
|
|
var zero = new java.util.concurrent.atomic.AtomicBoolean(false);
|
|
|
|
|
doAnswer(call -> {
|
|
|
|
|
var source = mock(org.bukkit.damage.DamageSource.class);
|
|
|
|
|
when(source.getCausingEntity()).thenReturn(a.player);
|
|
|
|
@@ -35,6 +36,7 @@ class BasicAttackNativeTest {
|
|
|
|
|
var event = new org.bukkit.event.entity.EntityDamageByEntityEvent(a.player, target,
|
|
|
|
|
org.bukkit.event.entity.EntityDamageEvent.DamageCause.ENTITY_ATTACK, source, (Double) call.getArgument(0));
|
|
|
|
|
event.setCancelled(cancelled.get());
|
|
|
|
|
if (zero.get()) event.setDamage(0);
|
|
|
|
|
basic.acceptedDamage(event);
|
|
|
|
|
return null;
|
|
|
|
|
}).when(target).damage(anyDouble(), same(a.player));
|
|
|
|
@@ -43,12 +45,13 @@ class BasicAttackNativeTest {
|
|
|
|
|
games.dmg.fantasystick.session.ControlInput.Gesture.ATTACK, target, 0, 1,
|
|
|
|
|
() -> sessions.current(active));
|
|
|
|
|
basic.accept(input); // Cancelled: no cadence spent.
|
|
|
|
|
cancelled.set(false);
|
|
|
|
|
basic.accept(input); // Accepted at t=0.
|
|
|
|
|
cancelled.set(false); zero.set(true);
|
|
|
|
|
basic.accept(input); // Zero final damage: no cadence spent.
|
|
|
|
|
zero.set(false); basic.accept(input); // Accepted at t=0.
|
|
|
|
|
clock.advance(java.time.Duration.ofMillis(999)); basic.accept(input);
|
|
|
|
|
verify(target, times(2)).damage(1.0, a.player);
|
|
|
|
|
clock.advance(java.time.Duration.ofMillis(1)); basic.accept(input);
|
|
|
|
|
verify(target, times(3)).damage(1.0, a.player);
|
|
|
|
|
clock.advance(java.time.Duration.ofMillis(1)); basic.accept(input);
|
|
|
|
|
verify(target, times(4)).damage(1.0, a.player);
|
|
|
|
|
a.core.inventory.setItemInOffHand(null); f.changed(a);
|
|
|
|
|
clock.advance(java.time.Duration.ofSeconds(1)); basic.accept(input);
|
|
|
|
|
verifyNoMoreInteractions(target);
|
|
|
|
@@ -88,6 +91,32 @@ class BasicAttackNativeTest {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test void packagedBasicStickUsesBasePlusStrengthModifierAcrossApprovedBoundaries() throws Exception {
|
|
|
|
|
try (var f = new FantasyStickLifecycleNativeTest.Fixture(data)) {
|
|
|
|
|
f.plugin.setEnabled(true);
|
|
|
|
|
int[] strengths = {0, 9, 10, 11, 12, 13, 14, 15};
|
|
|
|
|
double[] expected = {1, 1, 1, 1, 2, 2, 3, 3};
|
|
|
|
|
for (int index = 0; index < strengths.length; index++) {
|
|
|
|
|
var actor = new FantasyStickLifecycleNativeTest.Actor(data);
|
|
|
|
|
withStrength(data, actor, java.math.BigInteger.valueOf(strengths[index]));
|
|
|
|
|
f.players.put(actor.core.id, actor.player); f.activate(actor);
|
|
|
|
|
actor.core.inventory.getInventory().setSelectedSlot(1);
|
|
|
|
|
var target = mock(org.bukkit.entity.LivingEntity.class);
|
|
|
|
|
var attack = new io.papermc.paper.event.player.PrePlayerAttackEntityEvent(actor.player, target, true);
|
|
|
|
|
f.dispatcher.accept(attack);
|
|
|
|
|
assertTrue(attack.isCancelled()); verify(target).damage(expected[index], actor.player);
|
|
|
|
|
actor.core.inventory.setItemInOffHand(null); f.changed(actor); f.awaitCharacterAndReceipt(actor);
|
|
|
|
|
}
|
|
|
|
|
var actor = new FantasyStickLifecycleNativeTest.Actor(data);
|
|
|
|
|
withStrength(data, actor, java.math.BigInteger.TEN.pow(1000));
|
|
|
|
|
f.players.put(actor.core.id, actor.player); f.activate(actor);
|
|
|
|
|
actor.core.inventory.getInventory().setSelectedSlot(1);
|
|
|
|
|
var target = mock(org.bukkit.entity.LivingEntity.class);
|
|
|
|
|
f.dispatcher.accept(new io.papermc.paper.event.player.PrePlayerAttackEntityEvent(actor.player, target, true));
|
|
|
|
|
verify(target).damage(Double.MAX_VALUE, actor.player);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test void packagedBasicStickInputDealsOneLowStrengthHitWithoutVanillaContinuation() throws Exception {
|
|
|
|
|
try (var f = new FantasyStickLifecycleNativeTest.Fixture(data)) {
|
|
|
|
|
f.plugin.setEnabled(true);
|
|
|
|
@@ -106,6 +135,19 @@ class BasicAttackNativeTest {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void withStrength(Path data, FantasyStickLifecycleNativeTest.Actor actor,
|
|
|
|
|
java.math.BigInteger strength) throws Exception {
|
|
|
|
|
var repository = new games.dmg.fantasystick.persistence.YamlCharacterRepository(data);
|
|
|
|
|
var old = repository.load(actor.core.record.id()).orElseThrow();
|
|
|
|
|
var stats = new java.util.EnumMap<>(old.stats());
|
|
|
|
|
stats.put(games.dmg.fantasystick.progression.Stat.STR, strength);
|
|
|
|
|
repository.replace(new games.dmg.fantasystick.persistence.CharacterRecord(old.id(), old.name(),
|
|
|
|
|
old.revision().add(java.math.BigInteger.ONE), stats, old.level(), old.experience(), old.unspentPoints(),
|
|
|
|
|
old.health(), old.learned(), old.loadout(), old.passives(), old.cooldowns(), old.restrictedKills(),
|
|
|
|
|
false, null, null, old.coins(), old.coinsInitialized(), old.rewardReceipts(), old.pvpCoinEscrow(), old.gear()),
|
|
|
|
|
old.revision());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static final class MutableClock extends Clock {
|
|
|
|
|
private Instant now;
|
|
|
|
|
MutableClock(Instant now) { this.now = now; }
|
|
|
|
|