From 4059d50e72bc3aafb260f65efb479beed285997a Mon Sep 17 00:00:00 2001 From: FateJH Date: Wed, 17 Jan 2018 07:51:42 -0500 Subject: [PATCH] shotgun pellet fire modes; fire mode for melee weapons; cleanup code for phoenix (decimator) and handling last phoneix rocket fire; temporary cleanup of grenades --- .../psforever/objects/GlobalDefinitions.scala | 64 ++++----- .../scala/net/psforever/objects/Tool.scala | 13 +- .../equipment/FireModeDefinition.scala | 99 ++++++++++---- .../test/scala/objects/EquipmentTest.scala | 77 ++++++----- .../src/test/scala/objects/FireModeTest.scala | 127 ++++++++++++++++++ .../src/main/scala/WorldSessionActor.scala | 52 ++++++- 6 files changed, 336 insertions(+), 96 deletions(-) create mode 100644 common/src/test/scala/objects/FireModeTest.scala diff --git a/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala b/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala index 03f64231..15c4af9c 100644 --- a/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala +++ b/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala @@ -1028,55 +1028,47 @@ object GlobalDefinitions { private def init_tools() : Unit = { chainblade.Size = EquipmentSize.Melee chainblade.AmmoTypes += melee_ammo - chainblade.FireModes += new FireModeDefinition + chainblade.FireModes += new InfiniteFireModeDefinition chainblade.FireModes.head.AmmoTypeIndices += 0 chainblade.FireModes.head.AmmoSlotIndex = 0 chainblade.FireModes.head.Magazine = 1 - chainblade.FireModes.head.Chamber = 0 - chainblade.FireModes += new FireModeDefinition + chainblade.FireModes += new InfiniteFireModeDefinition chainblade.FireModes(1).AmmoTypeIndices += 0 chainblade.FireModes(1).AmmoSlotIndex = 0 chainblade.FireModes(1).Magazine = 1 - chainblade.FireModes.head.Chamber = 0 magcutter.Size = EquipmentSize.Melee magcutter.AmmoTypes += melee_ammo - magcutter.FireModes += new FireModeDefinition + magcutter.FireModes += new InfiniteFireModeDefinition magcutter.FireModes.head.AmmoTypeIndices += 0 magcutter.FireModes.head.AmmoSlotIndex = 0 magcutter.FireModes.head.Magazine = 1 - magcutter.FireModes.head.Chamber = 0 - magcutter.FireModes += new FireModeDefinition + magcutter.FireModes += new InfiniteFireModeDefinition magcutter.FireModes(1).AmmoTypeIndices += 0 magcutter.FireModes(1).AmmoSlotIndex = 0 magcutter.FireModes(1).Magazine = 1 - magcutter.FireModes.head.Chamber = 0 forceblade.Size = EquipmentSize.Melee forceblade.AmmoTypes += melee_ammo - forceblade.FireModes += new FireModeDefinition + forceblade.FireModes += new InfiniteFireModeDefinition forceblade.FireModes.head.AmmoTypeIndices += 0 forceblade.FireModes.head.AmmoSlotIndex = 0 forceblade.FireModes.head.Magazine = 1 - forceblade.FireModes.head.Chamber = 0 - forceblade.FireModes += new FireModeDefinition + forceblade.FireModes += new InfiniteFireModeDefinition forceblade.FireModes(1).AmmoTypeIndices += 0 forceblade.FireModes(1).AmmoSlotIndex = 0 forceblade.FireModes(1).Magazine = 1 - forceblade.FireModes(1).Chamber = 0 katana.Size = EquipmentSize.Melee katana.AmmoTypes += melee_ammo - katana.FireModes += new FireModeDefinition + katana.FireModes += new InfiniteFireModeDefinition katana.FireModes.head.AmmoTypeIndices += 0 katana.FireModes.head.AmmoSlotIndex = 0 katana.FireModes.head.Magazine = 1 - katana.FireModes.head.Chamber = 0 - katana.FireModes += new FireModeDefinition + katana.FireModes += new InfiniteFireModeDefinition katana.FireModes(1).AmmoTypeIndices += 0 katana.FireModes(1).AmmoSlotIndex = 0 katana.FireModes(1).Magazine = 1 - katana.FireModes(1).Chamber = 0 frag_grenade.Size = EquipmentSize.Pistol frag_grenade.AmmoTypes += frag_grenade_ammo @@ -1127,11 +1119,12 @@ object GlobalDefinitions { isp.Size = EquipmentSize.Pistol isp.AmmoTypes += shotgun_shell isp.AmmoTypes += shotgun_shell_AP - isp.FireModes += new FireModeDefinition + isp.FireModes += new PelletFireModeDefinition isp.FireModes.head.AmmoTypeIndices += 0 isp.FireModes.head.AmmoTypeIndices += 1 isp.FireModes.head.AmmoSlotIndex = 0 isp.FireModes.head.Magazine = 8 + isp.FireModes.head.Chamber = 6 //8 shells x 6 pellets = 48 isp.Tile = InventoryTile.Tile33 beamer.Size = EquipmentSize.Pistol @@ -1190,11 +1183,12 @@ object GlobalDefinitions { flechette.Size = EquipmentSize.Rifle flechette.AmmoTypes += shotgun_shell flechette.AmmoTypes += shotgun_shell_AP - flechette.FireModes += new FireModeDefinition + flechette.FireModes += new PelletFireModeDefinition flechette.FireModes.head.AmmoTypeIndices += 0 flechette.FireModes.head.AmmoTypeIndices += 1 flechette.FireModes.head.AmmoSlotIndex = 0 - flechette.FireModes.head.Magazine = 12 //12 shells * 8 pellets = 96 + flechette.FireModes.head.Magazine = 12 + flechette.FireModes.head.Chamber = 8 //12 shells * 8 pellets = 96 flechette.Tile = InventoryTile.Tile63 cycler.Size = EquipmentSize.Rifle @@ -1239,7 +1233,6 @@ object GlobalDefinitions { anniversary_guna.FireModes(1).AmmoTypeIndices += 0 anniversary_guna.FireModes(1).AmmoSlotIndex = 0 anniversary_guna.FireModes(1).Magazine = 6 - anniversary_guna.FireModes(1).Chamber = 6 anniversary_guna.Tile = InventoryTile.Tile33 anniversary_gun.Size = EquipmentSize.Pistol @@ -1252,7 +1245,6 @@ object GlobalDefinitions { anniversary_gun.FireModes(1).AmmoTypeIndices += 0 anniversary_gun.FireModes(1).AmmoSlotIndex = 0 anniversary_gun.FireModes(1).Magazine = 6 - anniversary_gun.FireModes(1).Chamber = 6 anniversary_gun.Tile = InventoryTile.Tile33 anniversary_gunb.Size = EquipmentSize.Pistol @@ -1265,7 +1257,6 @@ object GlobalDefinitions { anniversary_gunb.FireModes(1).AmmoTypeIndices += 0 anniversary_gunb.FireModes(1).AmmoSlotIndex = 0 anniversary_gunb.FireModes(1).Magazine = 6 - anniversary_gunb.FireModes(1).Chamber = 6 anniversary_gunb.Tile = InventoryTile.Tile33 spiker.Size = EquipmentSize.Pistol @@ -1275,6 +1266,7 @@ object GlobalDefinitions { spiker.FireModes.head.AmmoSlotIndex = 0 spiker.FireModes.head.Magazine = 25 spiker.Tile = InventoryTile.Tile33 + //TODO the spiker is weird mini_chaingun.Size = EquipmentSize.Rifle mini_chaingun.AmmoTypes += bullet_9mm @@ -1289,17 +1281,18 @@ object GlobalDefinitions { r_shotgun.Size = EquipmentSize.Rifle r_shotgun.AmmoTypes += shotgun_shell r_shotgun.AmmoTypes += shotgun_shell_AP - r_shotgun.FireModes += new FireModeDefinition + r_shotgun.FireModes += new PelletFireModeDefinition r_shotgun.FireModes.head.AmmoTypeIndices += 0 r_shotgun.FireModes.head.AmmoTypeIndices += 1 r_shotgun.FireModes.head.AmmoSlotIndex = 0 - r_shotgun.FireModes.head.Magazine = 16 //16 shells * 8 pellets = 128 - r_shotgun.FireModes += new FireModeDefinition + r_shotgun.FireModes.head.Magazine = 16 + r_shotgun.FireModes.head.Chamber = 8 //16 shells * 8 pellets = 128 + r_shotgun.FireModes += new PelletFireModeDefinition r_shotgun.FireModes(1).AmmoTypeIndices += 0 r_shotgun.FireModes(1).AmmoTypeIndices += 1 r_shotgun.FireModes(1).AmmoSlotIndex = 0 - r_shotgun.FireModes(1).Magazine = 16 //16 shells * 8 pellets = 128 - r_shotgun.FireModes(1).Chamber = 3 + r_shotgun.FireModes(1).Magazine = 16 + r_shotgun.FireModes(1).Chamber = 8 //16 shells * 8 pellets = 128 r_shotgun.Tile = InventoryTile.Tile93 lasher.Size = EquipmentSize.Rifle @@ -1329,6 +1322,7 @@ object GlobalDefinitions { maelstrom.FireModes(2).AmmoSlotIndex = 0 maelstrom.FireModes(2).Magazine = 150 maelstrom.Tile = InventoryTile.Tile93 + //TODO the maelstrom is weird phoenix.Size = EquipmentSize.Rifle phoenix.AmmoTypes += phoenix_missile @@ -1387,7 +1381,6 @@ object GlobalDefinitions { rocklet.FireModes(1).AmmoTypeIndices += 1 rocklet.FireModes(1).AmmoSlotIndex = 0 rocklet.FireModes(1).Magazine = 6 - rocklet.FireModes(1).Chamber = 6 rocklet.Tile = InventoryTile.Tile63 thumper.Size = EquipmentSize.Rifle @@ -1454,12 +1447,11 @@ object GlobalDefinitions { flamethrower.FireModes.head.AmmoTypeIndices += 0 flamethrower.FireModes.head.AmmoSlotIndex = 0 flamethrower.FireModes.head.Magazine = 100 - flamethrower.FireModes.head.Chamber = 5 flamethrower.FireModes += new FireModeDefinition flamethrower.FireModes(1).AmmoTypeIndices += 0 flamethrower.FireModes(1).AmmoSlotIndex = 0 flamethrower.FireModes(1).Magazine = 100 - flamethrower.FireModes(1).Chamber = 50 + flamethrower.FireModes(1).Rounds = 50 flamethrower.Tile = InventoryTile.Tile63 trhev_dualcycler.Size = EquipmentSize.Max @@ -1489,18 +1481,21 @@ object GlobalDefinitions { nchev_scattercannon.Size = EquipmentSize.Max nchev_scattercannon.AmmoTypes += scattercannon_ammo - nchev_scattercannon.FireModes += new FireModeDefinition + nchev_scattercannon.FireModes += new PelletFireModeDefinition nchev_scattercannon.FireModes.head.AmmoTypeIndices += 0 nchev_scattercannon.FireModes.head.AmmoSlotIndex = 0 nchev_scattercannon.FireModes.head.Magazine = 40 - nchev_scattercannon.FireModes += new FireModeDefinition + nchev_scattercannon.FireModes.head.Chamber = 10 + nchev_scattercannon.FireModes += new PelletFireModeDefinition nchev_scattercannon.FireModes(1).AmmoTypeIndices += 0 nchev_scattercannon.FireModes(1).AmmoSlotIndex = 0 nchev_scattercannon.FireModes(1).Magazine = 40 - nchev_scattercannon.FireModes += new FireModeDefinition + nchev_scattercannon.FireModes(1).Chamber = 10 + nchev_scattercannon.FireModes += new PelletFireModeDefinition nchev_scattercannon.FireModes(2).AmmoTypeIndices += 0 nchev_scattercannon.FireModes(2).AmmoSlotIndex = 0 nchev_scattercannon.FireModes(2).Magazine = 40 + nchev_scattercannon.FireModes(2).Chamber = 10 nchev_falcon.Size = EquipmentSize.Max nchev_falcon.AmmoTypes += falcon_ammo @@ -1584,11 +1579,10 @@ object GlobalDefinitions { trek.FireModes.head.AmmoTypeIndices += 0 trek.FireModes.head.AmmoSlotIndex = 0 trek.FireModes.head.Magazine = 4 - trek.FireModes += new FireModeDefinition + trek.FireModes += new InfiniteFireModeDefinition trek.FireModes(1).AmmoTypeIndices += 0 trek.FireModes(1).AmmoSlotIndex = 0 trek.FireModes(1).Magazine = 1 - trek.FireModes(1).Chamber = 0 trek.Tile = InventoryTile.Tile33 flail_targeting_laser.Packet = new CommandDetonaterConverter diff --git a/common/src/main/scala/net/psforever/objects/Tool.scala b/common/src/main/scala/net/psforever/objects/Tool.scala index df6c3df1..2b6d122a 100644 --- a/common/src/main/scala/net/psforever/objects/Tool.scala +++ b/common/src/main/scala/net/psforever/objects/Tool.scala @@ -33,6 +33,7 @@ class Tool(private val toolDef : ToolDefinition) extends Equipment with FireMode def NextFireMode : FireModeDefinition = { FireModeIndex = FireModeIndex + 1 + AmmoSlot.Chamber = FireMode.Chamber FireMode } @@ -59,7 +60,9 @@ class Tool(private val toolDef : ToolDefinition) extends Equipment with FireMode def MaxMagazine : Int = FireMode.Magazine - def NextDischarge : Int = math.min(Magazine, FireMode.Chamber) + def Discharge : Int = { + Magazine = FireMode.Discharge(this) + } def AmmoSlot : Tool.FireModeSlot = ammoSlots(FireMode.AmmoSlotIndex) @@ -127,6 +130,7 @@ object Tool { private var ammoTypeIndex : Int = 0 /** a reference to the actual `AmmoBox` of this slot */ private var box : AmmoBox = AmmoBox(AmmoDefinition, fdef.Magazine) + private var chamber = fdef.Chamber def AmmoTypeIndex : Int = ammoTypeIndex @@ -158,6 +162,13 @@ object Tool { Magazine } + def Chamber : Int = chamber + + def Chamber_=(chmbr : Int) : Int = { + chamber = math.min(math.max(0, chmbr), fdef.Chamber) + Chamber + } + def Box : AmmoBox = box def Box_=(toBox : AmmoBox) : Option[AmmoBox] = { diff --git a/common/src/main/scala/net/psforever/objects/equipment/FireModeDefinition.scala b/common/src/main/scala/net/psforever/objects/equipment/FireModeDefinition.scala index 423154bc..631e5e40 100644 --- a/common/src/main/scala/net/psforever/objects/equipment/FireModeDefinition.scala +++ b/common/src/main/scala/net/psforever/objects/equipment/FireModeDefinition.scala @@ -1,16 +1,25 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.equipment +import net.psforever.objects.Tool + import scala.collection.mutable class FireModeDefinition { - private val ammoTypeIndices : mutable.ListBuffer[Int] = mutable.ListBuffer[Int]() //indices pointing to all ammo types used - private var ammoSlotIndex : Int = 0 //ammunition slot number this fire mode utilizes - private var chamber : Int = 1 //how many rounds are queued to be fired at once, e.g., 3 for the Jackhammer's triple burst - private var magazine : Int = 1 //how many rounds are queued for each reload cycle -// private var target : Any = _ //target designation (self? other?) + /** indices pointing to all ammo types used */ + private val ammoTypeIndices : mutable.ListBuffer[Int] = mutable.ListBuffer[Int]() + /** ammunition slot number this fire mode utilizes */ + private var ammoSlotIndex : Int = 0 + /** how many rounds are replenished each reload cycle */ + private var magazine : Int = 1 + /** how much is subtracted from the magazine each fire cycle; + * most weapons will only fire 1 round per fire cycle; the flamethrower, fire mode 1, fires 50 */ + private var rounds : Int = 1 + /** how many sub-rounds are queued per round fired; + * the flechette fires 8 pellets per shell and generates 8 fire reports before the ammo count goes down */ + private var chamber : Int = 1 - //damage modifiers will follow here ... + //damage modifiers will follow here ... ? def AmmoSlotIndex : Int = ammoSlotIndex @@ -25,13 +34,6 @@ class FireModeDefinition { ammoTypeIndices += index } - def Chamber : Int = chamber - - def Chamber_=(inChamber : Int) : Int = { - chamber = inChamber - Chamber - } - def Magazine : Int = magazine def Magazine_=(inMagazine : Int) : Int = { @@ -39,16 +41,67 @@ class FireModeDefinition { Magazine } -// def Target : Any = target -// -// def Target_+(setAsTarget : Any) : Any = { -// target = setAsTarget -// Target -// } -} + def Rounds : Int = rounds -object FireModeDefinition { - def apply() : FireModeDefinition = { - new FireModeDefinition() + def Rounds_=(round : Int) : Int = { + rounds = round + Rounds + } + + def Chamber : Int = chamber + + def Chamber_=(inChamber : Int) : Int = { + chamber = inChamber + Chamber + } + + /** + * Shoot a weapon, remove an anticipated amount of ammunition. + * @param weapon the weapon + * @return the size of the weapon's magazine after discharge + */ + def Discharge(weapon : Tool) : Int = { + weapon.Magazine - Rounds } } + +class PelletFireModeDefinition extends FireModeDefinition { + /** + * Shoot a weapon, remove an anticipated amount of ammunition.
+ *
+ * For a weapon that has a number of sub-rounds chambered, each will generate unique weapon fire per fire cycle. + * Once all of the sub-rounds have been accounted for, the number of rounds for a single fire cycle will subtract. + * Since all fire cycles will abide by this chambered number of sub-rounds, the count is reset. + * @param weapon the weapon + * @return the size of the weapon's magazine after discharge + */ + override def Discharge(weapon : Tool) : Int = { + val ammoSlot = weapon.AmmoSlot + val magazine = weapon.Magazine + val chamber : Int = ammoSlot.Chamber = ammoSlot.Chamber - 1 + if(chamber <= 0) { + ammoSlot.Chamber = Chamber + magazine - Rounds + } + else { + magazine + } + } +} + +class InfiniteFireModeDefinition extends FireModeDefinition { + /** + * Shoot a weapon, remove an anticipated amount of ammunition.
+ *
+ * No rounds will be subtracted ever. + * The weapon can keep firing as much as the user wants. + * Since the PlanetSide client also has an internal understanding of ammo values in weapons, + * it may interfere with the functionality of this fire mode + * if the size of the magazine is not implicitly set per fire cycle. + * Works well with melee weapons. + * @param weapon the weapon + * @return the size of the weapon's magazine after discharge; + * will always return 1 + */ + override def Discharge(weapon : Tool) : Int = 1 +} diff --git a/common/src/test/scala/objects/EquipmentTest.scala b/common/src/test/scala/objects/EquipmentTest.scala index ff44aab7..fe260a3e 100644 --- a/common/src/test/scala/objects/EquipmentTest.scala +++ b/common/src/test/scala/objects/EquipmentTest.scala @@ -2,11 +2,11 @@ package objects import net.psforever.objects._ -import net.psforever.objects.definition._ import net.psforever.objects.equipment.CItem.{DeployedItem, Unit} import net.psforever.objects.equipment._ import net.psforever.objects.inventory.InventoryTile import net.psforever.objects.GlobalDefinitions._ +import net.psforever.objects.definition._ import org.specs2.mutable._ class EquipmentTest extends Specification { @@ -109,12 +109,12 @@ class EquipmentTest extends Specification { obj.Size = EquipmentSize.Rifle obj.AmmoTypes += GlobalDefinitions.shotgun_shell obj.AmmoTypes += GlobalDefinitions.shotgun_shell_AP - obj.FireModes += FireModeDefinition() + obj.FireModes += new FireModeDefinition obj.FireModes.head.AmmoTypeIndices += 0 obj.FireModes.head.AmmoTypeIndices += 1 obj.FireModes.head.AmmoSlotIndex = 0 obj.FireModes.head.Magazine = 18 - obj.FireModes += FireModeDefinition() + obj.FireModes += new FireModeDefinition obj.FireModes(1).AmmoTypeIndices += 0 obj.FireModes(1).AmmoTypeIndices += 1 obj.FireModes(1).AmmoSlotIndex = 1 @@ -162,47 +162,27 @@ class EquipmentTest extends Specification { } "multiple fire modes" in { - //explanation: sample_weapon has two fire modes; adjusting the FireMode changes between them - val tdef = ToolDefinition(1076) - tdef.Size = EquipmentSize.Rifle - tdef.AmmoTypes += GlobalDefinitions.shotgun_shell - tdef.AmmoTypes += GlobalDefinitions.shotgun_shell_AP - tdef.FireModes += new FireModeDefinition - tdef.FireModes.head.AmmoTypeIndices += 0 - tdef.FireModes.head.AmmoSlotIndex = 0 - tdef.FireModes.head.Magazine = 9 - tdef.FireModes += new FireModeDefinition - tdef.FireModes(1).AmmoTypeIndices += 1 - tdef.FireModes(1).AmmoSlotIndex = 1 - tdef.FireModes(1).Magazine = 18 - val obj : Tool = Tool(tdef) + //explanation: sample_weapon has two fire modes; each fire mode has a different ammunition type + val obj : Tool = Tool(punisher) //fmode = 0 obj.FireModeIndex mustEqual 0 - obj.FireMode.Magazine mustEqual 9 - obj.AmmoType mustEqual Ammo.shotgun_shell + obj.FireMode.Magazine mustEqual 30 + obj.AmmoType mustEqual Ammo.bullet_9mm //fmode -> 1 obj.NextFireMode obj.FireModeIndex mustEqual 1 - obj.FireMode.Magazine mustEqual 18 - obj.AmmoType mustEqual Ammo.shotgun_shell_AP + obj.FireMode.Magazine mustEqual 1 + obj.AmmoType mustEqual Ammo.rocket //fmode -> 0 obj.NextFireMode obj.FireModeIndex mustEqual 0 - obj.FireMode.Magazine mustEqual 9 - obj.AmmoType mustEqual Ammo.shotgun_shell + obj.FireMode.Magazine mustEqual 30 + obj.AmmoType mustEqual Ammo.bullet_9mm } "multiple types of ammunition" in { //explanation: obj has one fire mode and two ammunitions; adjusting the AmmoType changes between them - val tdef = ToolDefinition(1076) - tdef.Size = EquipmentSize.Rifle - tdef.AmmoTypes += GlobalDefinitions.shotgun_shell - tdef.AmmoTypes += GlobalDefinitions.shotgun_shell_AP - tdef.FireModes += new FireModeDefinition - tdef.FireModes.head.AmmoTypeIndices += 0 - tdef.FireModes.head.AmmoTypeIndices += 1 - tdef.FireModes.head.AmmoSlotIndex = 0 - val obj : Tool = Tool(tdef) + val obj : Tool = Tool(flechette) //ammo = 0 obj.AmmoTypeIndex mustEqual 0 obj.AmmoType mustEqual Ammo.shotgun_shell @@ -255,6 +235,39 @@ class EquipmentTest extends Specification { obj.AmmoTypeIndex mustEqual 2 obj.AmmoType mustEqual Ammo.rocket } + + "discharge (1)" in { + val obj = Tool(GlobalDefinitions.punisher) + obj.Magazine mustEqual 30 + obj.Discharge + obj.Magazine mustEqual 29 + obj.Discharge + obj.Discharge + obj.Magazine mustEqual 27 + } + + "chamber" in { + val obj = Tool(GlobalDefinitions.flechette) + obj.Magazine mustEqual 12 + obj.AmmoSlot.Chamber mustEqual 8 + + obj.Discharge + obj.Magazine mustEqual 12 + obj.AmmoSlot.Chamber mustEqual 7 + obj.Discharge + obj.Discharge + obj.Magazine mustEqual 12 + obj.AmmoSlot.Chamber mustEqual 5 + obj.Discharge + obj.Discharge + obj.Discharge + obj.Discharge + obj.Magazine mustEqual 12 + obj.AmmoSlot.Chamber mustEqual 1 + obj.Discharge + obj.Magazine mustEqual 11 + obj.AmmoSlot.Chamber mustEqual 8 + } } "Kit" should { diff --git a/common/src/test/scala/objects/FireModeTest.scala b/common/src/test/scala/objects/FireModeTest.scala new file mode 100644 index 00000000..07342393 --- /dev/null +++ b/common/src/test/scala/objects/FireModeTest.scala @@ -0,0 +1,127 @@ +// Copyright (c) 2017 PSForever +package objects + +import net.psforever.objects.definition.ToolDefinition +import net.psforever.objects.{GlobalDefinitions, Tool} +import net.psforever.objects.equipment.{EquipmentSize, FireModeDefinition, InfiniteFireModeDefinition, PelletFireModeDefinition} +import org.specs2.mutable._ + +class FireModeTest extends Specification { + "FireModeDefinition" should { + "construct" in { + val obj = new FireModeDefinition + obj.AmmoTypeIndices mustEqual Nil + obj.AmmoSlotIndex mustEqual 0 + obj.Magazine mustEqual 1 + obj.Rounds mustEqual 1 + obj.Chamber mustEqual 1 + } + + "test configurations" in { + val tdef = ToolDefinition(1076) //fake object id + tdef.Size = EquipmentSize.Rifle + tdef.AmmoTypes += GlobalDefinitions.bullet_9mm + tdef.AmmoTypes += GlobalDefinitions.shotgun_shell + tdef.FireModes += new FireModeDefinition + tdef.FireModes.head.AmmoTypeIndices += 0 + tdef.FireModes.head.AmmoSlotIndex = 0 + tdef.FireModes.head.Magazine = 18 + tdef.FireModes.head.Rounds = 18 + tdef.FireModes.head.Chamber = 2 + tdef.FireModes += new FireModeDefinition + tdef.FireModes(1).AmmoTypeIndices += 1 + tdef.FireModes(1).AmmoTypeIndices += 2 + tdef.FireModes(1).AmmoSlotIndex = 1 + tdef.FireModes(1).Magazine = 9 + tdef.FireModes(1).Rounds = 2 + tdef.FireModes(1).Chamber = 8 + + tdef.AmmoTypes.toList mustEqual List(GlobalDefinitions.bullet_9mm, GlobalDefinitions.shotgun_shell) + tdef.FireModes.size mustEqual 2 + tdef.FireModes.head.AmmoTypeIndices.toList mustEqual List(0) + tdef.FireModes.head.AmmoSlotIndex mustEqual 0 + tdef.FireModes.head.Magazine mustEqual 18 + tdef.FireModes.head.Rounds mustEqual 18 + tdef.FireModes.head.Chamber mustEqual 2 + tdef.FireModes(1).AmmoTypeIndices.toList mustEqual List(1, 2) + tdef.FireModes(1).AmmoSlotIndex mustEqual 1 + tdef.FireModes(1).Magazine mustEqual 9 + tdef.FireModes(1).Rounds mustEqual 2 + tdef.FireModes(1).Chamber mustEqual 8 + } + + "discharge" in { + val obj = Tool(GlobalDefinitions.beamer) //see EquipmentTest + obj.FireMode.isInstanceOf[FireModeDefinition] mustEqual true + obj.Magazine mustEqual 16 + obj.FireMode.Rounds mustEqual 1 + obj.FireMode.Chamber mustEqual 1 + + obj.Magazine mustEqual 16 + obj.Discharge + obj.Magazine mustEqual 15 + obj.Discharge + obj.Discharge + obj.Magazine mustEqual 13 + } + } + + "PelletFireModeDefinition" should { + "construct" in { + val obj = new PelletFireModeDefinition + obj.AmmoTypeIndices mustEqual Nil + obj.AmmoSlotIndex mustEqual 0 + obj.Magazine mustEqual 1 + obj.Rounds mustEqual 1 + obj.Chamber mustEqual 1 + } + + "discharge" in { + val obj = Tool(GlobalDefinitions.flechette) //see EquipmentTest + obj.FireMode.isInstanceOf[PelletFireModeDefinition] mustEqual true + obj.Magazine mustEqual 12 + obj.FireMode.Rounds mustEqual 1 + obj.FireMode.Chamber mustEqual 8 + + obj.Magazine mustEqual 12 + obj.Discharge //1 + obj.Magazine mustEqual 12 + obj.Discharge //2 + obj.Discharge //3 + obj.Magazine mustEqual 12 + obj.Discharge //4 + obj.Discharge //5 + obj.Discharge //6 + obj.Discharge //7 + obj.Magazine mustEqual 12 + obj.Discharge //8 + obj.Magazine mustEqual 11 + } + } + + "InfiniteFireModeDefinition" should { + "construct" in { + val obj = new InfiniteFireModeDefinition + obj.AmmoTypeIndices mustEqual Nil + obj.AmmoSlotIndex mustEqual 0 + obj.Magazine mustEqual 1 + obj.Rounds mustEqual 1 + obj.Chamber mustEqual 1 + } + + "discharge" in { + val obj = Tool(GlobalDefinitions.magcutter) //see EquipmentTest + obj.FireMode.isInstanceOf[InfiniteFireModeDefinition] mustEqual true + obj.Magazine mustEqual 1 + obj.FireMode.Rounds mustEqual 1 + obj.FireMode.Chamber mustEqual 1 + + obj.Magazine mustEqual 1 + obj.Discharge + obj.Magazine mustEqual 1 + obj.Discharge + obj.Discharge + obj.Magazine mustEqual 1 + } + } +} diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala index 17bebda3..8ab2cfcc 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -1116,6 +1116,12 @@ class WorldSessionActor extends Actor with MDCContextAware { player.Certifications += CertificationType.ATV player.Certifications += CertificationType.Harasser // + player.Certifications += CertificationType.InfiltrationSuit + player.Certifications += CertificationType.Sniping + player.Certifications += CertificationType.AntiVehicular + player.Certifications += CertificationType.HeavyAssault + player.Certifications += CertificationType.SpecialAssault + player.Certifications += CertificationType.EliteAssault player.Certifications += CertificationType.GroundSupport player.Certifications += CertificationType.GroundTransport player.Certifications += CertificationType.Flail @@ -1130,7 +1136,6 @@ class WorldSessionActor extends Actor with MDCContextAware { player.Certifications += CertificationType.GalaxyGunship player.Certifications += CertificationType.Phantasm player.Certifications += CertificationType.UniMAX - player.Certifications += CertificationType.InfiltrationSuit AwardBattleExperiencePoints(player, 1000000L) // player.ExoSuit = ExoSuitType.MAX //TODO strange issue; divide number above by 10 when uncommenting player.Slot(0).Equipment = Tool(GlobalDefinitions.StandardPistol(player.Faction)) @@ -1517,9 +1522,31 @@ class WorldSessionActor extends Actor with MDCContextAware { case msg @ ChangeFireStateMessage_Stop(item_guid) => log.info("ChangeFireState_Stop: " + msg) - if(shooting.contains(item_guid)) { + val weapon : Option[Equipment] = if(shooting.contains(item_guid)) { shooting = None avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Stop(player.GUID, item_guid)) + FindWeapon + } + else { + //some weapons, e.g., the decimator, do not send a ChangeFireState_Start on the last shot + FindWeapon match { + case Some(tool : Tool) => + if(tool.Definition == GlobalDefinitions.phoenix) { + avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Start(player.GUID, item_guid)) + avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Stop(player.GUID, item_guid)) + } + Some(tool) + case _ => + log.warn(s"ChangeFireState_Stop: received an unexpected message about $item_guid") + None + } + } + weapon match { + case Some(tool : Tool) => + if(tool.Magazine == 0) { + FireCycleCleanup(tool) + } + case _ => ; } progressBarUpdate.cancel //TODO independent action? @@ -1918,7 +1945,7 @@ class WorldSessionActor extends Actor with MDCContextAware { avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.WeaponDryFire(player.GUID, weapon_guid)) } else { //shooting - tool.Magazine = tool.Magazine - 1 + tool.Discharge //TODO other stuff? } case _ => ; @@ -2253,7 +2280,7 @@ class WorldSessionActor extends Actor with MDCContextAware { ) ) ) - if(0 <= localIndex && localIndex < 5) { + if(localTarget.VisibleSlots.contains(localIndex)) { localService ! AvatarServiceMessage(continent.Id, AvatarAction.EquipmentInHand(localTarget.GUID, localIndex, localObject)) } } @@ -2398,7 +2425,7 @@ class WorldSessionActor extends Actor with MDCContextAware { override def onSuccess() : Unit = { localAnnounce ! ResponseToSelf(PacketCoding.CreateGamePacket(0, ObjectDeleteMessage(localObjectGUID, 0))) - if(0 <= localIndex && localIndex < 5) { + if(localTarget.VisibleSlots.contains(localIndex)) { localService ! AvatarServiceMessage(localContinent, AvatarAction.ObjectDelete(localTarget.GUID, localObjectGUID)) } } @@ -2827,6 +2854,21 @@ class WorldSessionActor extends Actor with MDCContextAware { ) } + /** + * After a weapon has finished shooting, determine if it needs to be sorted in a special way. + * @param tool a weapon + */ + def FireCycleCleanup(tool : Tool) : Unit = { + //TODO this is temporary and will be replaced by more appropriate functionality in the future. + val tdef = tool.Definition + if(GlobalDefinitions.isGrenade(tdef)) { + taskResolver ! RemoveEquipmentFromSlot(player, tool, player.Find(tool).get) + } + else if(tdef == GlobalDefinitions.phoenix) { + taskResolver ! RemoveEquipmentFromSlot(player, tool, player.Find(tool).get) + } + } + /** * A predicate used to determine if an `InventoryItem` object contains `Equipment` that should be dropped. * Used to filter through lists of object data before it is placed into a player's inventory.