From 8d1d4c9db547981325a2432b497647914a3e4100 Mon Sep 17 00:00:00 2001 From: Ziggy Date: Sat, 21 Mar 2020 23:52:56 +0100 Subject: [PATCH] Fixed being able to buff enemies --- .../objects/swg/creature/CreatureObject.java | 6 +- .../combat/command/CombatCommandBuff.java | 31 +++- .../combat/command/TestCombatCommandBuff.java | 154 ++++++++++++++++++ 3 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 src/test/java/com/projectswg/holocore/services/gameplay/combat/command/TestCombatCommandBuff.java diff --git a/src/main/java/com/projectswg/holocore/resources/support/objects/swg/creature/CreatureObject.java b/src/main/java/com/projectswg/holocore/resources/support/objects/swg/creature/CreatureObject.java index 95bab925d..647b30050 100644 --- a/src/main/java/com/projectswg/holocore/resources/support/objects/swg/creature/CreatureObject.java +++ b/src/main/java/com/projectswg/holocore/resources/support/objects/swg/creature/CreatureObject.java @@ -622,7 +622,11 @@ public class CreatureObject extends TangibleObject { } public WeaponObject getEquippedWeapon() { - return getSlottedObjects().stream().filter(obj -> obj.getObjectId() == creo6.getEquippedWeapon()).map(WeaponObject.class::cast).findFirst().orElse(null); + return getSlottedObjects().stream() + .filter(obj -> obj.getObjectId() == creo6.getEquippedWeapon()) + .map(WeaponObject.class::cast) + .findFirst() + .orElse(null); } public void setEquippedWeapon(WeaponObject weapon) { diff --git a/src/main/java/com/projectswg/holocore/services/gameplay/combat/command/CombatCommandBuff.java b/src/main/java/com/projectswg/holocore/services/gameplay/combat/command/CombatCommandBuff.java index c4fca24b0..3f79b613f 100644 --- a/src/main/java/com/projectswg/holocore/services/gameplay/combat/command/CombatCommandBuff.java +++ b/src/main/java/com/projectswg/holocore/services/gameplay/combat/command/CombatCommandBuff.java @@ -30,8 +30,10 @@ package com.projectswg.holocore.services.gameplay.combat.command; import com.projectswg.common.data.combat.AttackInfo; import com.projectswg.common.data.combat.HitLocation; import com.projectswg.common.data.combat.TrailLocation; +import com.projectswg.common.data.encodables.tangible.PvpStatus; import com.projectswg.common.network.packets.swg.zone.object_controller.combat.CombatAction; import com.projectswg.common.network.packets.swg.zone.object_controller.combat.CombatAction.Defender; +import com.projectswg.holocore.resources.support.data.server_info.loader.combat.FactionLoader; import com.projectswg.holocore.resources.support.global.commands.CombatCommand; import com.projectswg.holocore.resources.support.objects.swg.SWGObject; import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject; @@ -52,9 +54,11 @@ enum CombatCommandBuff implements CombatCommandHitType { return; // Only CreatureObjects have buffs CreatureObject target = (CreatureObject) targetPrecheck; + boolean applyToSelf = isApplyToSelf(source, target); + String buffNameTarget = combatCommand.getBuffNameTarget(); - addBuff(source, target, buffNameTarget); + addBuff(source, applyToSelf ? source : target, buffNameTarget); WeaponObject weapon = source.getEquippedWeapon(); CombatAction combatAction = createCombatAction(source, weapon, TrailLocation.RIGHT_HAND, combatCommand); @@ -67,4 +71,29 @@ enum CombatCommandBuff implements CombatCommandHitType { source.sendObservers(combatAction, createCombatSpam(source, target, weapon, new AttackInfo(), combatCommand)); } + private boolean isApplyToSelf(CreatureObject source, CreatureObject target) { + FactionLoader.Faction sourceFaction = source.getFaction(); + FactionLoader.Faction targetFaction = target.getFaction(); + + if (sourceFaction == null || targetFaction == null) { + return false; + } + + if (target.isAttackable(source)) { + // You can't buff someone you can attack + return true; + } else if (sourceFaction.isEnemy(targetFaction)) { + PvpStatus sourcePvpStatus = source.getPvpStatus(); + PvpStatus targetPvpStatus = target.getPvpStatus(); + + if (sourcePvpStatus == PvpStatus.COMBATANT && targetPvpStatus == PvpStatus.ONLEAVE) { + return false; + } + + return sourcePvpStatus != PvpStatus.ONLEAVE || targetPvpStatus != PvpStatus.ONLEAVE; + } + + return false; + } + } diff --git a/src/test/java/com/projectswg/holocore/services/gameplay/combat/command/TestCombatCommandBuff.java b/src/test/java/com/projectswg/holocore/services/gameplay/combat/command/TestCombatCommandBuff.java new file mode 100644 index 000000000..e61b93415 --- /dev/null +++ b/src/test/java/com/projectswg/holocore/services/gameplay/combat/command/TestCombatCommandBuff.java @@ -0,0 +1,154 @@ +package com.projectswg.holocore.services.gameplay.combat.command; + +import com.projectswg.common.data.encodables.tangible.PvpStatus; +import com.projectswg.holocore.resources.support.data.server_info.loader.ServerData; +import com.projectswg.holocore.resources.support.data.server_info.loader.combat.FactionLoader; +import com.projectswg.holocore.resources.support.global.commands.CombatCommand; +import com.projectswg.holocore.resources.support.global.commands.Command; +import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject; +import com.projectswg.holocore.resources.support.objects.swg.weapon.WeaponObject; +import com.projectswg.holocore.services.gameplay.combat.buffs.BuffService; +import com.projectswg.holocore.test.resources.GenericCreatureObject; +import com.projectswg.holocore.test.runners.TestRunnerSynchronousIntents; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static junit.framework.TestCase.assertTrue; + +@RunWith(Parameterized.class) +public class TestCombatCommandBuff extends TestRunnerSynchronousIntents { + + private CreatureObject source; + private CreatureObject target; + + @Parameterized.Parameters(name = "{0}") + public static Collection data() { + return Arrays.asList( + // Neutral cases + new Input("neutral", PvpStatus.ONLEAVE, "neutral", PvpStatus.ONLEAVE, true), + new Input("neutral", PvpStatus.ONLEAVE, "rebel", PvpStatus.ONLEAVE, true), + new Input("neutral", PvpStatus.ONLEAVE, "rebel", PvpStatus.COMBATANT, true), + new Input("neutral", PvpStatus.ONLEAVE, "rebel", PvpStatus.SPECIALFORCES, true), + new Input("neutral", PvpStatus.ONLEAVE, "imperial", PvpStatus.COMBATANT, true), + new Input("neutral", PvpStatus.ONLEAVE, "imperial", PvpStatus.ONLEAVE, true), + new Input("neutral", PvpStatus.ONLEAVE, "imperial", PvpStatus.SPECIALFORCES, true), + + // Rebel cases + new Input("rebel", PvpStatus.ONLEAVE, "rebel", PvpStatus.ONLEAVE, true), + new Input("rebel", PvpStatus.ONLEAVE, "rebel", PvpStatus.COMBATANT, true), + new Input("rebel", PvpStatus.ONLEAVE, "rebel", PvpStatus.SPECIALFORCES, true), + new Input("rebel", PvpStatus.COMBATANT, "imperial", PvpStatus.ONLEAVE, true), + new Input("rebel", PvpStatus.COMBATANT, "imperial", PvpStatus.COMBATANT, false), + new Input("rebel", PvpStatus.COMBATANT, "imperial", PvpStatus.SPECIALFORCES, false), + new Input("rebel", PvpStatus.SPECIALFORCES, "imperial", PvpStatus.ONLEAVE, false), + new Input("rebel", PvpStatus.SPECIALFORCES, "imperial", PvpStatus.COMBATANT, false), + new Input("rebel", PvpStatus.SPECIALFORCES, "imperial", PvpStatus.SPECIALFORCES, false), + + // Imperial cases + new Input("imperial", PvpStatus.ONLEAVE, "imperial", PvpStatus.ONLEAVE, true), + new Input("imperial", PvpStatus.ONLEAVE, "imperial", PvpStatus.COMBATANT, true), + new Input("imperial", PvpStatus.ONLEAVE, "imperial", PvpStatus.SPECIALFORCES, true), + new Input("imperial", PvpStatus.COMBATANT, "rebel", PvpStatus.ONLEAVE, true), + new Input("imperial", PvpStatus.COMBATANT, "rebel", PvpStatus.COMBATANT, false), + new Input("imperial", PvpStatus.COMBATANT, "rebel", PvpStatus.SPECIALFORCES, false), + new Input("imperial", PvpStatus.SPECIALFORCES, "rebel", PvpStatus.ONLEAVE, false), + new Input("imperial", PvpStatus.SPECIALFORCES, "rebel", PvpStatus.COMBATANT, false), + new Input("imperial", PvpStatus.SPECIALFORCES, "rebel", PvpStatus.SPECIALFORCES, false) + ); + } + + @Parameterized.Parameter // first data value (0) is default + public Input input; + + @Before + public void setup() { + source = new GenericCreatureObject(1, "Source Creature"); + FactionLoader.Faction sourceFaction = ServerData.INSTANCE.getFactions().getFaction(input.getSourceFactionName()); + source.setFaction(sourceFaction); + source.setPvpStatus(input.getSourceStatus()); + + // Create a weapon for the source creature. Is used during buff process and must not be null. + WeaponObject weapon = new WeaponObject(2); + weapon.setArrangement(List.of(List.of("hold_r"))); + weapon.systemMove(source); + source.setEquippedWeapon(weapon); + + target = new GenericCreatureObject(3, "Target Creature"); + FactionLoader.Faction targetFaction = ServerData.INSTANCE.getFactions().getFaction(input.getTargetFactionName()); + target.setFaction(targetFaction); + target.setPvpStatus(input.getTargetStatus()); + + registerService(new BuffService()); + } + + @Test + public void testReceiveBuff() { + String targetBuffName = "hemorrhage"; // Important that the buff actually exists + Command command = Command.builder() + .withName(targetBuffName) + .build(); + + CombatCommand combatCommand = CombatCommand.builder(command) + .withBuffNameSelf("") + .withBuffNameTarget(targetBuffName) + .withDefaultAnimation(new String[]{""}) + .build(); + + CombatCommandBuff.INSTANCE.handle(source, target, combatCommand, ""); + + waitForIntents(); // Let's give the BuffService a chance to process the BuffIntent + + if (input.isExpected()) { + assertTrue("Source should be allowed to buff target", target.hasBuff(targetBuffName)); + } else { + assertTrue("Source should have buffed themselves and not target due to factional restrictions", source.hasBuff(targetBuffName)); + } + } + + private static class Input { + private final String sourceFactionName; + private final PvpStatus sourceStatus; + private final String targetFactionName; + private final PvpStatus targetStatus; + private boolean expected; + + public Input(String sourceFactionName, PvpStatus sourceStatus, String targetFactionName, PvpStatus targetStatus, boolean expected) { + this.sourceFactionName = sourceFactionName; + this.sourceStatus = sourceStatus; + this.targetFactionName = targetFactionName; + this.targetStatus = targetStatus; + this.expected = expected; + } + + public String getSourceFactionName() { + return sourceFactionName; + } + + public PvpStatus getSourceStatus() { + return sourceStatus; + } + + public String getTargetFactionName() { + return targetFactionName; + } + + public PvpStatus getTargetStatus() { + return targetStatus; + } + + public boolean isExpected() { + return expected; + } + + @Override + public String toString() { + return "sourceFaction=" + sourceFactionName + ", sourceStatus=" + sourceStatus + ", targetFaction=" + targetFactionName + ", targetStatus=" + targetStatus + ", expected=" + expected; + } + } +}