From 776d2249e832ddf7781e6ab3ddac0e3c6ba0f5d7 Mon Sep 17 00:00:00 2001 From: Jack Date: Wed, 23 Sep 2015 17:57:12 -0700 Subject: [PATCH 1/6] Created rifle class --- .../com/pipai/wf/battle/weapon/Rifle.java | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100755 core/src/main/java/com/pipai/wf/battle/weapon/Rifle.java diff --git a/core/src/main/java/com/pipai/wf/battle/weapon/Rifle.java b/core/src/main/java/com/pipai/wf/battle/weapon/Rifle.java new file mode 100755 index 0000000..b33bdce --- /dev/null +++ b/core/src/main/java/com/pipai/wf/battle/weapon/Rifle.java @@ -0,0 +1,68 @@ +package com.pipai.wf.battle.weapon; + +import com.pipai.wf.battle.action.RangedWeaponAttackAction; +import com.pipai.wf.battle.action.TargetedAction; +import com.pipai.wf.battle.action.TargetedActionable; +import com.pipai.wf.battle.agent.Agent; +import com.pipai.wf.math.LinearFunction; + +public class Rifle extends Weapon implements TargetedActionable { + + @Override + public int flatAimModifier() { + return 0; + } + + @Override + public int rangeAimModifier(float distance) { + int minOptimalRange = 7; + int maxRangePenalty = -20; + + if (distance <= minOptimalRange) { + return (int) (new LinearFunction(minOptimalRange, 0, 0, maxRangePenalty).eval(distance)); + } + + return 0; + } + + @Override + public int flatCritProbabilityModifier() { + return 20; + } + + @Override + public int rangeCritModifier(float distance) { + return 0; + } + + @Override + public int minBaseDamage() { + return 4; + } + + @Override + public int maxBaseDamage() { + return 6; + } + + @Override + public boolean needsAmmunition() { + return true; + } + + @Override + public int baseAmmoCapacity() { + return 3; + } + + @Override + public String name() { + return "Rifle"; + } + + @Override + public TargetedAction getAction(Agent performer, Agent target) { + return new RangedWeaponAttackAction(performer, target); + } + +} From 1fce5ce8e7afaa0ab86a7312faed7afed1eec237 Mon Sep 17 00:00:00 2001 From: Jack Date: Wed, 23 Sep 2015 17:58:47 -0700 Subject: [PATCH 2/6] Created Snap Shot passive ability --- .../wf/unit/ability/SnapShotAbility.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100755 core/src/main/java/com/pipai/wf/unit/ability/SnapShotAbility.java diff --git a/core/src/main/java/com/pipai/wf/unit/ability/SnapShotAbility.java b/core/src/main/java/com/pipai/wf/unit/ability/SnapShotAbility.java new file mode 100755 index 0000000..c1eab0e --- /dev/null +++ b/core/src/main/java/com/pipai/wf/unit/ability/SnapShotAbility.java @@ -0,0 +1,24 @@ +package com.pipai.wf.unit.ability; + +public class SnapShotAbility extends PassiveAbility { + + public SnapShotAbility() { + super(0); + } + + @Override + public String name() { + return "Snap Shot"; + } + + @Override + public String description() { + return "Can fire rifle after moving with -10 to-hit penalty"; + } + + @Override + public Ability clone() { + return new SnapShotAbility(); + } + +} From d33087ebd2bab13eb03bab1874e53446631a4d37 Mon Sep 17 00:00:00 2001 From: Jack Date: Wed, 23 Sep 2015 18:25:12 -0700 Subject: [PATCH 3/6] Created rifle attack action --- .../wf/battle/action/RifleAttackAction.java | 52 +++++++++++++++++++ .../wf/battle/action/WeaponActionFactory.java | 7 +++ .../java/com/pipai/wf/battle/agent/Agent.java | 4 ++ .../com/pipai/wf/battle/weapon/Rifle.java | 4 +- 4 files changed, 65 insertions(+), 2 deletions(-) create mode 100755 core/src/main/java/com/pipai/wf/battle/action/RifleAttackAction.java diff --git a/core/src/main/java/com/pipai/wf/battle/action/RifleAttackAction.java b/core/src/main/java/com/pipai/wf/battle/action/RifleAttackAction.java new file mode 100755 index 0000000..86f428e --- /dev/null +++ b/core/src/main/java/com/pipai/wf/battle/action/RifleAttackAction.java @@ -0,0 +1,52 @@ +package com.pipai.wf.battle.action; + +import com.pipai.wf.battle.agent.Agent; +import com.pipai.wf.battle.damage.DamageCalculator; +import com.pipai.wf.battle.damage.DamageResult; +import com.pipai.wf.battle.damage.PercentageModifier; +import com.pipai.wf.battle.damage.PercentageModifierList; +import com.pipai.wf.battle.damage.TargetedActionCalculator; +import com.pipai.wf.battle.damage.WeaponDamageFunction; +import com.pipai.wf.battle.log.BattleEvent; +import com.pipai.wf.battle.weapon.Weapon; +import com.pipai.wf.exception.IllegalActionException; +import com.pipai.wf.unit.ability.SnapShotAbility; + +public class RifleAttackAction extends RangedWeaponAttackAction{ + + public RifleAttackAction(Agent performerAgent, Agent targetAgent) { + super(performerAgent, targetAgent); + } + + @Override + public PercentageModifierList getHitCalculation() { + Agent a = getPerformer(); + Agent target = getTarget(); + PercentageModifierList p = TargetedActionCalculator.baseHitCalculation(a, target); + if (a.hasUsedAP() && a.getAbilities().hasAbility(SnapShotAbility.class)) { + p.add(new PercentageModifier("Snap Shot", -10)); + } + return p; + } + + @Override + protected void performImpl() throws IllegalActionException { + Agent a = getPerformer(); + Agent target = getTarget(); + Weapon w = a.getCurrentWeapon(); + if (!a.getAbilities().hasAbility(SnapShotAbility.class) && a.hasUsedAP()) + { + throw new IllegalActionException("Cannot fire rifle after moving"); + } + if (w.needsAmmunition() && w.currentAmmo() == 0) { + throw new IllegalActionException("Not enough ammo to fire " + w.name()); + } + if (a.hasUsedAP()) { + + } + DamageResult result = DamageCalculator.rollDamageGeneral(this, new WeaponDamageFunction(w), 0); + a.setAP(0); + target.takeDamage(result.damage); + log(BattleEvent.rangedWeaponAttackEvent(a, target, w, result)); + } +} diff --git a/core/src/main/java/com/pipai/wf/battle/action/WeaponActionFactory.java b/core/src/main/java/com/pipai/wf/battle/action/WeaponActionFactory.java index 5d6fcae..7233e31 100755 --- a/core/src/main/java/com/pipai/wf/battle/action/WeaponActionFactory.java +++ b/core/src/main/java/com/pipai/wf/battle/action/WeaponActionFactory.java @@ -1,6 +1,7 @@ package com.pipai.wf.battle.action; import com.pipai.wf.battle.agent.Agent; +import com.pipai.wf.battle.weapon.Rifle; import com.pipai.wf.battle.weapon.SpellWeapon; import com.pipai.wf.battle.weapon.Weapon; @@ -10,6 +11,8 @@ public static TargetedWithAccuracyActionOWCapable defaultWeaponAction(Agent perf Weapon weapon = performer.getCurrentWeapon(); if (weapon instanceof SpellWeapon) { return new TargetedSpellWeaponAction(performer, target); + } else if (weapon instanceof Rifle) { + return new RifleAttackAction(performer, target); } else { return new RangedWeaponAttackAction(performer, target); } @@ -19,6 +22,8 @@ public static Class defaultWeapon Weapon weapon = performer.getCurrentWeapon(); if (weapon instanceof SpellWeapon) { return TargetedSpellWeaponAction.class; + } else if (weapon instanceof Rifle) { + return RifleAttackAction.class; } else { return RangedWeaponAttackAction.class; } @@ -28,6 +33,8 @@ public static String defaultWeaponActionName(Agent performer) { Weapon weapon = performer.getCurrentWeapon(); if (weapon instanceof SpellWeapon) { return new TargetedSpellWeaponAction(performer, null).name(); + } else if (weapon instanceof Rifle) { + return new RifleAttackAction(performer, null).name(); } else { return new RangedWeaponAttackAction(performer, null).name(); } diff --git a/core/src/main/java/com/pipai/wf/battle/agent/Agent.java b/core/src/main/java/com/pipai/wf/battle/agent/Agent.java index 2abe98c..3cb6f59 100755 --- a/core/src/main/java/com/pipai/wf/battle/agent/Agent.java +++ b/core/src/main/java/com/pipai/wf/battle/agent/Agent.java @@ -103,6 +103,10 @@ public int getMaxAP() { return this.maxAP; } + public boolean hasUsedAP() { + return (this.ap < this.maxAP); + } + public int getHP() { return this.hp; } diff --git a/core/src/main/java/com/pipai/wf/battle/weapon/Rifle.java b/core/src/main/java/com/pipai/wf/battle/weapon/Rifle.java index b33bdce..eea04cd 100755 --- a/core/src/main/java/com/pipai/wf/battle/weapon/Rifle.java +++ b/core/src/main/java/com/pipai/wf/battle/weapon/Rifle.java @@ -1,6 +1,6 @@ package com.pipai.wf.battle.weapon; -import com.pipai.wf.battle.action.RangedWeaponAttackAction; +import com.pipai.wf.battle.action.RifleAttackAction; import com.pipai.wf.battle.action.TargetedAction; import com.pipai.wf.battle.action.TargetedActionable; import com.pipai.wf.battle.agent.Agent; @@ -62,7 +62,7 @@ public String name() { @Override public TargetedAction getAction(Agent performer, Agent target) { - return new RangedWeaponAttackAction(performer, target); + return new RifleAttackAction(performer, target); } } From ef47ab94fb5ddd7cdcf5ff1ad464a64651993353 Mon Sep 17 00:00:00 2001 From: Jack Date: Wed, 23 Sep 2015 20:04:34 -0700 Subject: [PATCH 4/6] Added Snap Shot unit test --- .../com/pipai/wf/test/battle/AbilityTest.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/core/src/test/java/com/pipai/wf/test/battle/AbilityTest.java b/core/src/test/java/com/pipai/wf/test/battle/AbilityTest.java index 6e9d0ed..a8cb8b1 100755 --- a/core/src/test/java/com/pipai/wf/test/battle/AbilityTest.java +++ b/core/src/test/java/com/pipai/wf/test/battle/AbilityTest.java @@ -10,18 +10,24 @@ import com.pipai.wf.battle.Team; import com.pipai.wf.battle.action.PrecisionShotAction; import com.pipai.wf.battle.action.ReloadAction; +import com.pipai.wf.battle.action.TargetedWithAccuracyActionOWCapable; import com.pipai.wf.battle.agent.Agent; import com.pipai.wf.battle.agent.AgentState; import com.pipai.wf.battle.agent.AgentStateFactory; +import com.pipai.wf.battle.log.BattleEvent; import com.pipai.wf.battle.map.BattleMap; import com.pipai.wf.battle.map.GridPosition; import com.pipai.wf.battle.spell.FireballSpell; import com.pipai.wf.battle.weapon.Pistol; +import com.pipai.wf.battle.weapon.Rifle; import com.pipai.wf.exception.IllegalActionException; +import com.pipai.wf.test.MockGUIObserver; import com.pipai.wf.unit.ability.FireballAbility; import com.pipai.wf.unit.ability.PrecisionShotAbility; import com.pipai.wf.unit.ability.QuickReloadAbility; import com.pipai.wf.unit.ability.RegenerationAbility; +import com.pipai.wf.unit.ability.SnapShotAbility; +import com.pipai.wf.util.UtilFunctions; public class AbilityTest { @@ -125,4 +131,69 @@ public void testPrecisionShotCooldown() { fail(e.getMessage()); } } + + @Test + public void testNoSnapShot() { + BattleMap map = new BattleMap(5, 5); + GridPosition playerPos = new GridPosition(1, 1); + GridPosition enemyPos = new GridPosition(2, 1); + AgentState playerState = AgentStateFactory.newBattleAgentState(Team.PLAYER, playerPos, 3, 5, 2, 5, 1000, 0); + playerState.weapons.add(new Rifle()); + map.addAgent(playerState); + map.addAgent(AgentStateFactory.newBattleAgentState(Team.ENEMY, enemyPos, 3, 5, 2, 5, 65, 0)); + BattleController battle = new BattleController(map); + MockGUIObserver observer = new MockGUIObserver(); + battle.registerObserver(observer); + Agent player = map.getAgentAtPos(playerPos); + Agent enemy = map.getAgentAtPos(enemyPos); + assertFalse(player == null || enemy == null); + assertFalse(player.hasUsedAP()); + player.useAP(1); + assertTrue(player.hasUsedAP()); + TargetedWithAccuracyActionOWCapable atk = (TargetedWithAccuracyActionOWCapable) ((Rifle) player.getCurrentWeapon()).getAction(player, enemy); + assertTrue(atk.toHit() == 100); + try { + battle.performAction(atk); + fail("Expected exception not thrown"); + } catch (IllegalActionException e) { + } + } + + @Test + public void testSnapShot() { + BattleMap map = new BattleMap(5, 5); + GridPosition playerPos = new GridPosition(1, 1); + GridPosition enemyPos = new GridPosition(2, 1); + AgentState playerState = AgentStateFactory.newBattleAgentState(Team.PLAYER, playerPos, 3, 5, 2, 5, 1000, 0); + playerState.abilities.add(new SnapShotAbility()); + playerState.weapons.add(new Rifle()); + map.addAgent(playerState); + map.addAgent(AgentStateFactory.newBattleAgentState(Team.ENEMY, enemyPos, 3, 5, 2, 5, 65, 0)); + BattleController battle = new BattleController(map); + MockGUIObserver observer = new MockGUIObserver(); + battle.registerObserver(observer); + Agent player = map.getAgentAtPos(playerPos); + Agent enemy = map.getAgentAtPos(enemyPos); + assertFalse(player == null || enemy == null); + assertFalse(player.hasUsedAP()); + player.useAP(1); + assertTrue(player.hasUsedAP()); + TargetedWithAccuracyActionOWCapable atk = (TargetedWithAccuracyActionOWCapable) ((Rifle) player.getCurrentWeapon()).getAction(player, enemy); + assertTrue(atk.toHit() == 100); + try { + battle.performAction(atk); + } catch (IllegalActionException e) { + fail(e.getMessage()); + } + BattleEvent ev = observer.ev; + assertTrue(ev.getType() == BattleEvent.Type.RANGED_WEAPON_ATTACK); + assertTrue(ev.getPerformer() == player); + assertTrue(ev.getTarget() == enemy); + assertTrue(ev.getChainEvents().size() == 0); + // Player has 1000 aim, cannot miss + assertTrue(ev.getDamageResult().hit); + int expectedHP = UtilFunctions.clamp(0, enemy.getMaxHP(), enemy.getMaxHP() - ev.getDamage()); + assertTrue(enemy.getHP() == expectedHP); + assertTrue(player.getHP() == player.getMaxHP()); + } } From 8daf90f31c3037f70b9877aee74ebc7bbd0742bb Mon Sep 17 00:00:00 2001 From: Jack Date: Wed, 23 Sep 2015 20:24:41 -0700 Subject: [PATCH 5/6] Added rifle requirement to Precision Shot --- .../java/com/pipai/wf/battle/action/PrecisionShotAction.java | 4 ++++ core/src/main/java/com/pipai/wf/gui/BattleGui.java | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/pipai/wf/battle/action/PrecisionShotAction.java b/core/src/main/java/com/pipai/wf/battle/action/PrecisionShotAction.java index 016a28b..0c6943a 100755 --- a/core/src/main/java/com/pipai/wf/battle/action/PrecisionShotAction.java +++ b/core/src/main/java/com/pipai/wf/battle/action/PrecisionShotAction.java @@ -8,6 +8,7 @@ import com.pipai.wf.battle.damage.TargetedActionCalculator; import com.pipai.wf.battle.damage.WeaponDamageFunction; import com.pipai.wf.battle.log.BattleEvent; +import com.pipai.wf.battle.weapon.Rifle; import com.pipai.wf.battle.weapon.Weapon; import com.pipai.wf.exception.IllegalActionException; import com.pipai.wf.unit.ability.Ability; @@ -57,6 +58,9 @@ protected void performImpl() throws IllegalActionException { } Agent target = getTarget(); Weapon w = a.getCurrentWeapon(); + if (!(w instanceof Rifle)) { + throw new IllegalActionException("Rifle needed to use Precision Shot"); + } if (w.needsAmmunition() && w.currentAmmo() == 0) { throw new IllegalActionException("Not enough ammo to fire " + w.name()); } diff --git a/core/src/main/java/com/pipai/wf/gui/BattleGui.java b/core/src/main/java/com/pipai/wf/gui/BattleGui.java index 61c5a4d..602b1b6 100755 --- a/core/src/main/java/com/pipai/wf/gui/BattleGui.java +++ b/core/src/main/java/com/pipai/wf/gui/BattleGui.java @@ -36,6 +36,7 @@ import com.pipai.wf.battle.map.MapGraph; import com.pipai.wf.battle.spell.FireballSpell; import com.pipai.wf.battle.vision.FogOfWar; +import com.pipai.wf.battle.weapon.Rifle; import com.pipai.wf.battle.weapon.SpellWeapon; import com.pipai.wf.battle.weapon.Weapon; import com.pipai.wf.exception.IllegalActionException; @@ -639,7 +640,7 @@ public void onKeyDown(int keycode) { // Skill if (this.mode == Mode.MOVE) { for (Ability a : selectedAgent.getAgent().getAbilities()) { - if (a instanceof PrecisionShotAbility && !a.isOnCooldown()) { + if (a instanceof PrecisionShotAbility && !a.isOnCooldown() && selectedAgent.getAgent().getCurrentWeapon() instanceof Rifle) { this.switchToTargetMode((PrecisionShotAbility) a); break; } From a364097e4224f7e93f3e71ee9c3e4a494cbefa88 Mon Sep 17 00:00:00 2001 From: Jack Date: Thu, 24 Sep 2015 18:33:03 -0700 Subject: [PATCH 6/6] Added Precision Shot weapon requirement unit test --- .../wf/battle/action/RifleAttackAction.java | 6 +---- .../com/pipai/wf/test/battle/AbilityTest.java | 23 ++++++++++++++++++- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/com/pipai/wf/battle/action/RifleAttackAction.java b/core/src/main/java/com/pipai/wf/battle/action/RifleAttackAction.java index 86f428e..06719dc 100755 --- a/core/src/main/java/com/pipai/wf/battle/action/RifleAttackAction.java +++ b/core/src/main/java/com/pipai/wf/battle/action/RifleAttackAction.java @@ -34,15 +34,11 @@ protected void performImpl() throws IllegalActionException { Agent a = getPerformer(); Agent target = getTarget(); Weapon w = a.getCurrentWeapon(); - if (!a.getAbilities().hasAbility(SnapShotAbility.class) && a.hasUsedAP()) - { + if (!a.getAbilities().hasAbility(SnapShotAbility.class) && a.hasUsedAP()) { throw new IllegalActionException("Cannot fire rifle after moving"); } if (w.needsAmmunition() && w.currentAmmo() == 0) { throw new IllegalActionException("Not enough ammo to fire " + w.name()); - } - if (a.hasUsedAP()) { - } DamageResult result = DamageCalculator.rollDamageGeneral(this, new WeaponDamageFunction(w), 0); a.setAP(0); diff --git a/core/src/test/java/com/pipai/wf/test/battle/AbilityTest.java b/core/src/test/java/com/pipai/wf/test/battle/AbilityTest.java index a8cb8b1..8235101 100755 --- a/core/src/test/java/com/pipai/wf/test/battle/AbilityTest.java +++ b/core/src/test/java/com/pipai/wf/test/battle/AbilityTest.java @@ -103,7 +103,7 @@ public void testPrecisionShotCooldown() { GridPosition enemyPos = new GridPosition(2, 2); AgentState playerState = AgentStateFactory.newBattleAgentState(Team.PLAYER, playerPos, 3, 5, 2, 5, 65, 0); playerState.abilities.add(new PrecisionShotAbility()); - playerState.weapons.add(new Pistol()); + playerState.weapons.add(new Rifle()); map.addAgent(playerState); map.addAgent(AgentStateFactory.newBattleAgentState(Team.ENEMY, enemyPos, 3, 5, 2, 5, 65, 0)); BattleController battle = new BattleController(map); @@ -132,6 +132,27 @@ public void testPrecisionShotCooldown() { } } + @Test + public void testPrecisionShotWeaponReq() { + BattleMap map = new BattleMap(3, 4); + GridPosition playerPos = new GridPosition(1, 0); + GridPosition enemyPos = new GridPosition(2, 2); + AgentState playerState = AgentStateFactory.newBattleAgentState(Team.PLAYER, playerPos, 3, 5, 2, 5, 65, 0); + playerState.abilities.add(new PrecisionShotAbility()); + playerState.weapons.add(new Pistol()); + map.addAgent(playerState); + map.addAgent(AgentStateFactory.newBattleAgentState(Team.ENEMY, enemyPos, 3, 5, 2, 5, 65, 0)); + BattleController battle = new BattleController(map); + Agent agent = map.getAgentAtPos(playerPos); + Agent target = map.getAgentAtPos(enemyPos); + try { + battle.performAction(new PrecisionShotAction(agent, target)); + fail("Expected exception not thrown"); + } catch (IllegalActionException e) { + } + } + + @Test public void testNoSnapShot() { BattleMap map = new BattleMap(5, 5);