diff --git a/common/src/main/scala/net/psforever/objects/AmmoBox.scala b/common/src/main/scala/net/psforever/objects/AmmoBox.scala index 0b5e8181..624230c6 100644 --- a/common/src/main/scala/net/psforever/objects/AmmoBox.scala +++ b/common/src/main/scala/net/psforever/objects/AmmoBox.scala @@ -3,6 +3,7 @@ package net.psforever.objects import net.psforever.objects.definition.AmmoBoxDefinition import net.psforever.objects.equipment.{Ammo, Equipment} +import net.psforever.types.PlanetSideEmpire class AmmoBox(private val ammoDef : AmmoBoxDefinition, cap : Option[Int] = None @@ -22,6 +23,8 @@ class AmmoBox(private val ammoDef : AmmoBoxDefinition, def Definition : AmmoBoxDefinition = ammoDef + override def Faction_=(fact : PlanetSideEmpire.Value) : PlanetSideEmpire.Value = Faction + override def toString : String = { AmmoBox.toString(this) } diff --git a/common/src/main/scala/net/psforever/objects/Avatar.scala b/common/src/main/scala/net/psforever/objects/Avatar.scala index 9452a6a6..1307ee58 100644 --- a/common/src/main/scala/net/psforever/objects/Avatar.scala +++ b/common/src/main/scala/net/psforever/objects/Avatar.scala @@ -3,8 +3,9 @@ package net.psforever.objects import net.psforever.objects.avatar.DeployableToolbox import net.psforever.objects.definition.{AvatarDefinition, ImplantDefinition} -import net.psforever.objects.equipment.EquipmentSize +import net.psforever.objects.equipment.{EquipmentSize, EquipmentSlot} import net.psforever.objects.loadouts.Loadout +import net.psforever.packet.game.objectcreate.Cosmetics import net.psforever.types._ import scala.annotation.tailrec @@ -15,6 +16,8 @@ class Avatar(val name : String, val faction : PlanetSideEmpire.Value, val sex : private var bep : Long = 0 /** Command Experience Points */ private var cep : Long = 0 + /** Cosmetics **/ + private var pStyle : Option[Cosmetics] = None /** Certifications */ private val certs : mutable.Set[CertificationType.Value] = mutable.Set[CertificationType.Value]() /** Implants
@@ -56,6 +59,13 @@ class Avatar(val name : String, val faction : PlanetSideEmpire.Value, val sex : CEP } + def PersonalStyleFeatures : Option[Cosmetics] = pStyle + + def PersonalStyleFeatures_=(app : Cosmetics) : Option[Cosmetics] = { + pStyle = Some(app) + pStyle + } + /** * Retrieve the three implant slots for this player. * @return an `Array` of `ImplantSlot` objects @@ -166,12 +176,14 @@ class Avatar(val name : String, val faction : PlanetSideEmpire.Value, val sex : } } - def LoadLoadout(line : Int) : Option[Loadout] = loadouts.lift(line).getOrElse(None) + def LoadLoadout(line : Int) : Option[Loadout] = loadouts.lift(line).flatten def DeleteLoadout(line : Int) : Unit = { loadouts(line) = None } + def Loadouts : Seq[(Int, Loadout)] = loadouts.zipWithIndex.collect { case(Some(loadout), index) => (index, loadout) } toSeq + def Locker : LockerContainer = locker def FifthSlot : EquipmentSlot = { diff --git a/common/src/main/scala/net/psforever/objects/BoomerTrigger.scala b/common/src/main/scala/net/psforever/objects/BoomerTrigger.scala index dfc3fec3..bef7ea3b 100644 --- a/common/src/main/scala/net/psforever/objects/BoomerTrigger.scala +++ b/common/src/main/scala/net/psforever/objects/BoomerTrigger.scala @@ -2,5 +2,8 @@ package net.psforever.objects import net.psforever.objects.equipment.RemoteUnit +import net.psforever.types.PlanetSideEmpire -class BoomerTrigger extends SimpleItem(GlobalDefinitions.boomer_trigger) with RemoteUnit +class BoomerTrigger extends SimpleItem(GlobalDefinitions.boomer_trigger) with RemoteUnit { + override def Faction_=(fact : PlanetSideEmpire.Value) : PlanetSideEmpire.Value = Faction +} diff --git a/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala b/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala index f777096c..ef41576d 100644 --- a/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala +++ b/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala @@ -17,8 +17,8 @@ import net.psforever.objects.serverobject.tube.SpawnTubeDefinition import net.psforever.objects.serverobject.resourcesilo.ResourceSiloDefinition import net.psforever.objects.serverobject.turret.{TurretDefinition, TurretUpgrade} import net.psforever.objects.vehicles.{DestroyedVehicle, SeatArmorRestriction, UtilityType} -import net.psforever.objects.vital.{DamageType, StandardResolutions} -import net.psforever.types.{CertificationType, PlanetSideEmpire, Vector3} +import net.psforever.objects.vital.{DamageType, StandardMaxDamage, StandardResolutions} +import net.psforever.types.{CertificationType, ExoSuitType, PlanetSideEmpire, Vector3} import scala.collection.mutable import scala.concurrent.duration._ @@ -29,6 +29,71 @@ object GlobalDefinitions { */ val avatar = new AvatarDefinition(121) /* + Exo-suits + */ + val Standard = ExoSuitDefinition(ExoSuitType.Standard) + Standard.Name = "standard" + Standard.MaxArmor = 50 + Standard.InventoryScale = InventoryTile.Tile96 + Standard.InventoryOffset = 6 + Standard.Holster(0, EquipmentSize.Pistol) + Standard.Holster(2, EquipmentSize.Rifle) + Standard.Holster(4, EquipmentSize.Melee) + Standard.ResistanceDirectHit = 4 + Standard.ResistanceSplash = 15 + Standard.ResistanceAggravated = 8 + + val Agile = ExoSuitDefinition(ExoSuitType.Agile) + Agile.Name = "agile" + Agile.MaxArmor = 100 + Agile.InventoryScale = InventoryTile.Tile99 + Agile.InventoryOffset = 6 + Agile.Holster(0, EquipmentSize.Pistol) + Agile.Holster(1, EquipmentSize.Pistol) + Agile.Holster(2, EquipmentSize.Rifle) + Agile.Holster(4, EquipmentSize.Melee) + Agile.ResistanceDirectHit = 6 + Agile.ResistanceSplash = 25 + Agile.ResistanceAggravated = 10 + + val Reinforced = ExoSuitDefinition(ExoSuitType.Reinforced) + Reinforced.Name = "reinforced" + Reinforced.Permissions = List(CertificationType.ReinforcedExoSuit) + Reinforced.MaxArmor = 200 + Reinforced.InventoryScale = InventoryTile.Tile1209 + Reinforced.InventoryOffset = 6 + Reinforced.Holster(0, EquipmentSize.Pistol) + Reinforced.Holster(1, EquipmentSize.Pistol) + Reinforced.Holster(2, EquipmentSize.Rifle) + Reinforced.Holster(3, EquipmentSize.Rifle) + Reinforced.Holster(4, EquipmentSize.Melee) + Reinforced.ResistanceDirectHit = 10 + Reinforced.ResistanceSplash = 35 + Reinforced.ResistanceAggravated = 12 + + val Infiltration = ExoSuitDefinition(ExoSuitType.Infiltration) + Infiltration.Name = "infiltration_suit" + Infiltration.Permissions = List(CertificationType.InfiltrationSuit) + Infiltration.MaxArmor = 0 + Infiltration.InventoryScale = InventoryTile.Tile66 + Infiltration.InventoryOffset = 6 + Infiltration.Holster(0, EquipmentSize.Pistol) + Infiltration.Holster(4, EquipmentSize.Melee) + + val MAX = SpecialExoSuitDefinition(ExoSuitType.MAX) + MAX.Permissions = List(CertificationType.AIMAX,CertificationType.AVMAX, CertificationType.AAMAX, CertificationType.UniMAX) + MAX.MaxArmor = 650 + MAX.InventoryScale = InventoryTile.Tile1612 + MAX.InventoryOffset = 6 + MAX.Holster(0, EquipmentSize.Max) + MAX.Holster(4, EquipmentSize.Melee) + MAX.Subtract.Damage1 = -2 + MAX.ResistanceDirectHit = 6 + MAX.ResistanceSplash = 35 + MAX.ResistanceAggravated = 10 + MAX.Damage = StandardMaxDamage + MAX.Model = StandardResolutions.Max + /* Implants */ val advanced_regen = ImplantDefinition(0) @@ -880,37 +945,44 @@ object GlobalDefinitions { /* Miscellaneous */ - val order_terminal = new OrderTerminalDefinition val ams_respawn_tube = new SpawnTubeDefinition(49) + val matrix_terminala = new MatrixTerminalDefinition(517) + + val matrix_terminalb = new MatrixTerminalDefinition(518) + val matrix_terminalc = new MatrixTerminalDefinition(519) - val order_terminala = new OrderTerminalABDefinition(613) + val spawn_terminal = new MatrixTerminalDefinition(812) - val order_terminalb = new OrderTerminalABDefinition(614) + val order_terminal = new OrderTerminalDefinition(612) - val cert_terminal = new CertTerminalDefinition + val order_terminala = new OrderTerminalDefinition(613) + + val order_terminalb = new OrderTerminalDefinition(614) + + val cert_terminal = new OrderTerminalDefinition(171) val implant_terminal_mech = new ImplantTerminalMechDefinition - val implant_terminal_interface = new ImplantTerminalInterfaceDefinition + val implant_terminal_interface = new OrderTerminalDefinition(409) - val ground_vehicle_terminal = new GroundVehicleTerminalDefinition + val ground_vehicle_terminal = new OrderTerminalDefinition(386) - val air_vehicle_terminal = new AirVehicleTerminalDefinition + val air_vehicle_terminal = new OrderTerminalDefinition(43) - val dropship_vehicle_terminal = new DropshipVehicleTerminalDefinition + val dropship_vehicle_terminal = new OrderTerminalDefinition(263) - val vehicle_terminal_combined = new VehicleTerminalCombinedDefinition + val vehicle_terminal_combined = new OrderTerminalDefinition(952) - val spawn_terminal = new MatrixTerminalDefinition(812) + val bfr_terminal = new OrderTerminalDefinition(143) val respawn_tube = new SpawnTubeDefinition(732) val respawn_tube_tower = new SpawnTubeDefinition(733) - val teleportpad_terminal = new TeleportPadTerminalDefinition + val teleportpad_terminal = new OrderTerminalDefinition(853) val adv_med_terminal = new MedicalTerminalDefinition(38) @@ -944,13 +1016,13 @@ object GlobalDefinitions { val lodestar_repair_terminal = new MedicalTerminalDefinition(461) - val multivehicle_rearm_terminal = new _OrderTerminalDefinition(576) + val multivehicle_rearm_terminal = new OrderTerminalDefinition(576) - val bfr_rearm_terminal = new _OrderTerminalDefinition(142) + val bfr_rearm_terminal = new OrderTerminalDefinition(142) - val air_rearm_terminal = new _OrderTerminalDefinition(42) + val air_rearm_terminal = new OrderTerminalDefinition(42) - val ground_rearm_terminal = new _OrderTerminalDefinition(384) + val ground_rearm_terminal = new OrderTerminalDefinition(384) val manned_turret = new TurretDefinition(480) initMiscellaneous() @@ -1338,6 +1410,68 @@ object GlobalDefinitions { super_staminakit.Name = "super_staminakit" } + /** + * Initialize `ExoSuitType` globals. + */ + private def init_exosuit() : Unit = { + Standard.Name = "standard" + Standard.MaxArmor = 50 + Standard.InventoryScale = InventoryTile.Tile96 + Standard.InventoryOffset = 6 + Standard.Holster(0, EquipmentSize.Pistol) + Standard.Holster(2, EquipmentSize.Rifle) + Standard.Holster(4, EquipmentSize.Melee) + Standard.ResistanceDirectHit = 4 + Standard.ResistanceSplash = 15 + Standard.ResistanceAggravated = 8 + + Agile.Name = "lite_armor" + Agile.MaxArmor = 100 + Agile.InventoryScale = InventoryTile.Tile99 + Agile.InventoryOffset = 6 + Agile.Holster(0, EquipmentSize.Pistol) + Agile.Holster(1, EquipmentSize.Pistol) + Agile.Holster(2, EquipmentSize.Rifle) + Agile.Holster(4, EquipmentSize.Melee) + Agile.ResistanceDirectHit = 6 + Agile.ResistanceSplash = 25 + Agile.ResistanceAggravated = 10 + + Reinforced.Name = "med_armor" + Reinforced.Permissions = List(CertificationType.ReinforcedExoSuit) + Reinforced.MaxArmor = 200 + Reinforced.InventoryScale = InventoryTile.Tile1209 + Reinforced.InventoryOffset = 6 + Reinforced.Holster(0, EquipmentSize.Pistol) + Reinforced.Holster(1, EquipmentSize.Pistol) + Reinforced.Holster(2, EquipmentSize.Rifle) + Reinforced.Holster(3, EquipmentSize.Rifle) + Reinforced.Holster(4, EquipmentSize.Melee) + Reinforced.ResistanceDirectHit = 10 + Reinforced.ResistanceSplash = 35 + Reinforced.ResistanceAggravated = 12 + + Infiltration.Name = "infiltration_suit" + Infiltration.Permissions = List(CertificationType.InfiltrationSuit) + Infiltration.MaxArmor = 0 + Infiltration.InventoryScale = InventoryTile.Tile66 + Infiltration.InventoryOffset = 6 + Infiltration.Holster(0, EquipmentSize.Pistol) + Infiltration.Holster(4, EquipmentSize.Melee) + + MAX.Permissions = List(CertificationType.AIMAX,CertificationType.AVMAX, CertificationType.AAMAX, CertificationType.UniMAX) + MAX.MaxArmor = 650 + MAX.InventoryScale = InventoryTile.Tile1612 + MAX.InventoryOffset = 6 + MAX.Holster(0, EquipmentSize.Max) + MAX.Holster(4, EquipmentSize.Melee) + MAX.Subtract.Damage1 = -2 + MAX.ResistanceDirectHit = 6 + MAX.ResistanceSplash = 35 + MAX.ResistanceAggravated = 10 + MAX.Damage = StandardMaxDamage + MAX.Model = StandardResolutions.Max + } /** * Initialize `AmmoBoxDefinition` globals. */ @@ -5578,7 +5712,7 @@ object GlobalDefinitions { deployable_shield_generator.MaxHealth = 1700 deployable_shield_generator.DeployTime = Duration.create(6000, "ms") deployable_shield_generator.Model = StandardResolutions.ComplexDeployables - + router_telepad_deployable.Name = "router_telepad_deployable" router_telepad_deployable.MaxHealth = 100 router_telepad_deployable.DeployTime = Duration.create(1, "ms") @@ -5595,6 +5729,67 @@ object GlobalDefinitions { * Initialize `Miscellaneous` globals. */ private def initMiscellaneous() : Unit = { + matrix_terminala.Name = "matrix_terminala" + + matrix_terminalb.Name = "matrix_terminalb" + + matrix_terminalc.Name = "matrix_terminalc" + + spawn_terminal.Name = "spawn_terminal" + + order_terminal.Name = "order_terminal" + order_terminal.Tab += 0 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.infantryAmmunition ++ EquipmentTerminalDefinition.infantryWeapons) + order_terminal.Tab += 1 -> OrderTerminalDefinition.ArmorWithAmmoPage(EquipmentTerminalDefinition.suits ++ EquipmentTerminalDefinition.maxSuits, EquipmentTerminalDefinition.maxAmmo) + order_terminal.Tab += 2 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.supportAmmunition ++ EquipmentTerminalDefinition.supportWeapons) + order_terminal.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition) + order_terminal.Tab += 4 -> OrderTerminalDefinition.InfantryLoadoutPage() + order_terminal.SellEquipmentByDefault = true + + order_terminala.Name = "order_terminala" + order_terminala.Tab += 0 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.infantryAmmunition ++ EquipmentTerminalDefinition.infantryWeapons) + order_terminala.Tab += 1 -> OrderTerminalDefinition.ArmorWithAmmoPage(EquipmentTerminalDefinition.suits, EquipmentTerminalDefinition.maxAmmo) + order_terminala.Tab += 2 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.supportAmmunition ++ EquipmentTerminalDefinition.supportWeapons) + order_terminala.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition) + order_terminala.Tab += 4 -> OrderTerminalDefinition.InfantryLoadoutPage() + order_terminala.SellEquipmentByDefault = true + + order_terminalb.Name = "order_terminalb" + order_terminalb.Tab += 0 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.infantryAmmunition ++ EquipmentTerminalDefinition.infantryWeapons) + order_terminalb.Tab += 1 -> OrderTerminalDefinition.ArmorWithAmmoPage(EquipmentTerminalDefinition.suits, EquipmentTerminalDefinition.maxAmmo) + order_terminalb.Tab += 2 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.supportAmmunition ++ EquipmentTerminalDefinition.supportWeapons) + order_terminalb.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition) + order_terminalb.Tab += 4 -> OrderTerminalDefinition.InfantryLoadoutPage() + order_terminalb.SellEquipmentByDefault = true + + cert_terminal.Name = "cert_terminal" + cert_terminal.Tab += 0 -> OrderTerminalDefinition.CertificationPage(CertTerminalDefinition.certs) + + implant_terminal_interface.Name = "implant_terminal_interface" + implant_terminal_interface.Tab += 0 -> OrderTerminalDefinition.ImplantPage(ImplantTerminalDefinition.implants) + + ground_vehicle_terminal.Name = "ground_vehicle_terminal" + ground_vehicle_terminal.Tab += 46769 -> OrderTerminalDefinition.VehiclePage(VehicleTerminalDefinition.groundVehicles, VehicleTerminalDefinition.trunk) + ground_vehicle_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage() + + air_vehicle_terminal.Name = "air_vehicle_terminal" + air_vehicle_terminal.Tab += 46769 -> OrderTerminalDefinition.VehiclePage(VehicleTerminalDefinition.flight1Vehicles, VehicleTerminalDefinition.trunk) + air_vehicle_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage() + + dropship_vehicle_terminal.Name = "dropship_vehicle_terminal" + dropship_vehicle_terminal.Tab += 46769 -> OrderTerminalDefinition.VehiclePage(VehicleTerminalDefinition.flight1Vehicles ++ VehicleTerminalDefinition.flight2Vehicles, VehicleTerminalDefinition.trunk) + dropship_vehicle_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage() + + vehicle_terminal_combined.Name = "vehicle_terminal_combined" + vehicle_terminal_combined.Tab += 46769 -> OrderTerminalDefinition.VehiclePage(VehicleTerminalDefinition.flight1Vehicles ++ VehicleTerminalDefinition.groundVehicles, VehicleTerminalDefinition.trunk) + vehicle_terminal_combined.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage() + + bfr_terminal.Name = "bfr_terminal" + bfr_terminal.Tab += 46769 -> OrderTerminalDefinition.VehiclePage(VehicleTerminalDefinition.bfrVehicles, VehicleTerminalDefinition.trunk) + bfr_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage() + + teleportpad_terminal.Name = "teleportpad_terminal" + teleportpad_terminal.Tab += 0 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.routerTerminal) + adv_med_terminal.Name = "adv_med_terminal" adv_med_terminal.Interval = 500 adv_med_terminal.HealAmount = 8 @@ -5653,20 +5848,24 @@ object GlobalDefinitions { lodestar_repair_terminal.TargetValidation += ProximityTarget.Vehicle -> ProximityTerminalControl.Validation.RepairSilo multivehicle_rearm_terminal.Name = "multivehicle_rearm_terminal" - multivehicle_rearm_terminal.Page += 3 -> _OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition) - multivehicle_rearm_terminal.Page += 4 -> _OrderTerminalDefinition.VehicleLoadoutPage() + multivehicle_rearm_terminal.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition) + multivehicle_rearm_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage() + multivehicle_rearm_terminal.SellEquipmentByDefault = true //TODO ? bfr_rearm_terminal.Name = "bfr_rearm_terminal" - bfr_rearm_terminal.Page += 3 -> _OrderTerminalDefinition.EquipmentPage(Map.empty[String, ()=>Equipment]) //TODO add stock to page - bfr_rearm_terminal.Page += 4 -> _OrderTerminalDefinition.VehicleLoadoutPage() + bfr_rearm_terminal.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(Map.empty[String, ()=>Equipment]) //TODO add stock to page + bfr_rearm_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage() + bfr_rearm_terminal.SellEquipmentByDefault = true //TODO ? air_rearm_terminal.Name = "air_rearm_terminal" - air_rearm_terminal.Page += 3 -> _OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition) - air_rearm_terminal.Page += 4 -> _OrderTerminalDefinition.VehicleLoadoutPage() + air_rearm_terminal.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition) + air_rearm_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage() + air_rearm_terminal.SellEquipmentByDefault = true //TODO ? ground_rearm_terminal.Name = "ground_rearm_terminal" - ground_rearm_terminal.Page += 3 -> _OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition) - ground_rearm_terminal.Page += 4 -> _OrderTerminalDefinition.VehicleLoadoutPage() + ground_rearm_terminal.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition) + ground_rearm_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage() + ground_rearm_terminal.SellEquipmentByDefault = true //TODO ? manned_turret.Name = "manned_turret" manned_turret.MaxHealth = 3600 diff --git a/common/src/main/scala/net/psforever/objects/OffhandEquipmentSlot.scala b/common/src/main/scala/net/psforever/objects/OffhandEquipmentSlot.scala index 0d9a5151..e6045467 100644 --- a/common/src/main/scala/net/psforever/objects/OffhandEquipmentSlot.scala +++ b/common/src/main/scala/net/psforever/objects/OffhandEquipmentSlot.scala @@ -1,7 +1,7 @@ // Copyright (c) 2017 PSForever package net.psforever.objects -import net.psforever.objects.equipment.EquipmentSize +import net.psforever.objects.equipment.{EquipmentSize, EquipmentSlot} /** * A size-checked unit of storage (or mounting) for `Equipment`. diff --git a/common/src/main/scala/net/psforever/objects/Player.scala b/common/src/main/scala/net/psforever/objects/Player.scala index aa5dff72..e1e015f2 100644 --- a/common/src/main/scala/net/psforever/objects/Player.scala +++ b/common/src/main/scala/net/psforever/objects/Player.scala @@ -1,8 +1,8 @@ // Copyright (c) 2017 PSForever package net.psforever.objects -import net.psforever.objects.definition.AvatarDefinition -import net.psforever.objects.equipment.{Equipment, EquipmentSize} +import net.psforever.objects.definition.{AvatarDefinition, ExoSuitDefinition, SpecialExoSuitDefinition} +import net.psforever.objects.equipment.{Equipment, EquipmentSize, EquipmentSlot} import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem} import net.psforever.objects.loadouts.Loadout import net.psforever.objects.serverobject.affinity.FactionAffinity @@ -10,6 +10,7 @@ import net.psforever.objects.vital.resistance.ResistanceProfile import net.psforever.objects.vital.{DamageResistanceModel, Vitality} import net.psforever.objects.zones.ZoneAware import net.psforever.packet.game.PlanetSideGUID +import net.psforever.packet.game.objectcreate.{Cosmetics, DetailedCharacterData, PersonalStyle} import net.psforever.types._ import scala.annotation.tailrec @@ -29,18 +30,18 @@ class Player(private val core : Avatar) extends PlanetSideGameObject private var maxHealth : Int = 100 //TODO affected by empire benefits, territory benefits, and bops private var maxStamina : Int = 100 //does anything affect this? - private var exosuit : ExoSuitDefinition = ExoSuitDefinition.Standard + private var exosuit : ExoSuitDefinition = GlobalDefinitions.Standard private val freeHand : EquipmentSlot = new OffhandEquipmentSlot(EquipmentSize.Inventory) private val holsters : Array[EquipmentSlot] = Array.fill[EquipmentSlot](5)(new EquipmentSlot) private val inventory : GridInventory = GridInventory() private var drawnSlot : Int = Player.HandsDownSlot private var lastDrawnSlot : Int = Player.HandsDownSlot + private var backpackAccess : Option[PlanetSideGUID] = None private var facingYawUpper : Float = 0f private var crouching : Boolean = false private var jumping : Boolean = false private var cloaked : Boolean = false - private var backpackAccess : Option[PlanetSideGUID] = None private var vehicleSeated : Option[PlanetSideGUID] = None private var vehicleOwned : Option[PlanetSideGUID] = None @@ -347,7 +348,71 @@ class Player(private val core : Avatar) extends PlanetSideGameObject Cloaked } - private var usingSpecial : (SpecialExoSuitDefinition.Mode.Value)=>SpecialExoSuitDefinition.Mode.Value = DefaultUsingSpecial + def PersonalStyleFeatures : Option[Cosmetics] = core.PersonalStyleFeatures + + def AddToPersonalStyle(value : PersonalStyle.Value) : (Option[Cosmetics], Option[Cosmetics]) = { + val original = core.PersonalStyleFeatures + if(DetailedCharacterData.isBR24(core.BEP)) { + core.PersonalStyleFeatures = original match { + case Some(cosmetic) => + cosmetic + value + case None => + Cosmetics(value) + } + (original, core.PersonalStyleFeatures) + } + else { + (None, None) + } + } + + def RemoveFromPersonalStyle(value : PersonalStyle.Value) : (Option[Cosmetics], Option[Cosmetics]) = { + val original = core.PersonalStyleFeatures + original match { + case Some(cosmetics) => + (original, core.PersonalStyleFeatures = cosmetics - value) + case None => + (None, None) + } + } + + private def BasicFeatureToggle(feature : PersonalStyle.Value) : (Option[Cosmetics], Option[Cosmetics]) = core.PersonalStyleFeatures match { + case Some(c : Cosmetics) => + if(c.Styles.contains(feature)) { + RemoveFromPersonalStyle(feature) + } + else { + AddToPersonalStyle(feature) + } + case None => + AddToPersonalStyle(feature) + } + + def ToggleHelmet : (Option[Cosmetics], Option[Cosmetics]) = BasicFeatureToggle(PersonalStyle.NoHelmet) + + def ToggleShades : (Option[Cosmetics], Option[Cosmetics]) = BasicFeatureToggle(PersonalStyle.Sunglasses) + + def ToggleEarpiece : (Option[Cosmetics], Option[Cosmetics]) = BasicFeatureToggle(PersonalStyle.Earpiece) + + def ToggleHat : (Option[Cosmetics], Option[Cosmetics]) = { + core.PersonalStyleFeatures match { + case Some(c : Cosmetics) => + if(c.Styles.contains(PersonalStyle.BrimmedCap)) { + (RemoveFromPersonalStyle(PersonalStyle.BrimmedCap)._1, + AddToPersonalStyle(PersonalStyle.Beret)._2) + } + else if(c.Styles.contains(PersonalStyle.Beret)) { + RemoveFromPersonalStyle(PersonalStyle.Beret) + } + else { + AddToPersonalStyle(PersonalStyle.BrimmedCap) + } + case None => + AddToPersonalStyle(PersonalStyle.BrimmedCap) + } + } + + private var usingSpecial : SpecialExoSuitDefinition.Mode.Value=>SpecialExoSuitDefinition.Mode.Value = DefaultUsingSpecial private var gettingSpecial : ()=>SpecialExoSuitDefinition.Mode.Value = DefaultGettingSpecial diff --git a/common/src/main/scala/net/psforever/objects/Vehicle.scala b/common/src/main/scala/net/psforever/objects/Vehicle.scala index 3057d4db..c552177b 100644 --- a/common/src/main/scala/net/psforever/objects/Vehicle.scala +++ b/common/src/main/scala/net/psforever/objects/Vehicle.scala @@ -3,7 +3,7 @@ package net.psforever.objects import akka.actor.ActorRef import net.psforever.objects.definition.VehicleDefinition -import net.psforever.objects.equipment.{Equipment, EquipmentSize} +import net.psforever.objects.equipment.{Equipment, EquipmentSize, EquipmentSlot} import net.psforever.objects.inventory.{Container, GridInventory, InventoryTile} import net.psforever.objects.serverobject.mount.Mountable import net.psforever.objects.serverobject.PlanetSideServerObject diff --git a/common/src/main/scala/net/psforever/objects/ExoSuitDefinition.scala b/common/src/main/scala/net/psforever/objects/definition/ExoSuitDefinition.scala similarity index 60% rename from common/src/main/scala/net/psforever/objects/ExoSuitDefinition.scala rename to common/src/main/scala/net/psforever/objects/definition/ExoSuitDefinition.scala index e96e4a9d..7cc43ad4 100644 --- a/common/src/main/scala/net/psforever/objects/ExoSuitDefinition.scala +++ b/common/src/main/scala/net/psforever/objects/definition/ExoSuitDefinition.scala @@ -1,24 +1,27 @@ // Copyright (c) 2017 PSForever -package net.psforever.objects +package net.psforever.objects.definition +import net.psforever.objects.GlobalDefinitions import net.psforever.objects.equipment.EquipmentSize import net.psforever.objects.inventory.InventoryTile import net.psforever.objects.vital._ import net.psforever.objects.vital.resistance.ResistanceProfileMutators -import net.psforever.types.ExoSuitType +import net.psforever.types.{CertificationType, ExoSuitType} /** * A definition for producing the personal armor the player wears. * Players are influenced by the exo-suit they wear in a variety of ways, with speed and available equipment slots being major differences. * @param suitType the `Enumeration` corresponding to this exo-suit */ -class ExoSuitDefinition(private val suitType : ExoSuitType.Value) extends ResistanceProfileMutators +class ExoSuitDefinition(private val suitType : ExoSuitType.Value) extends BasicDefinition + with ResistanceProfileMutators with DamageResistanceModel { - protected var permission : Int = 0 //TODO certification type? + protected var permissions : List[CertificationType.Value] = List.empty protected var maxArmor : Int = 0 protected val holsters : Array[EquipmentSize.Value] = Array.fill[EquipmentSize.Value](5)(EquipmentSize.Blocked) protected var inventoryScale : InventoryTile = InventoryTile.Tile11 //override with custom InventoryTile protected var inventoryOffset : Int = 0 + Name = "exo-suit" Damage = StandardInfantryDamage Resistance = StandardInfantryResistance Model = StandardResolutions.Infantry @@ -67,10 +70,19 @@ class ExoSuitDefinition(private val suitType : ExoSuitType.Value) extends Resist } } + def Permissions : List[CertificationType.Value] = permissions + + def Permissions_=(certs : List[CertificationType.Value]) : List[CertificationType.Value] = { + permissions = certs + Permissions + } + def Use : ExoSuitDefinition = this } class SpecialExoSuitDefinition(private val suitType : ExoSuitType.Value) extends ExoSuitDefinition(suitType) { + Name = "heavy_armor" + private var activatedSpecial : SpecialExoSuitDefinition.Mode.Value = SpecialExoSuitDefinition.Mode.Normal def UsingSpecial : SpecialExoSuitDefinition.Mode.Value = activatedSpecial @@ -118,65 +130,6 @@ object SpecialExoSuitDefinition { } object ExoSuitDefinition { - final val Standard = ExoSuitDefinition(ExoSuitType.Standard) - Standard.MaxArmor = 50 - Standard.InventoryScale = InventoryTile.Tile96 - Standard.InventoryOffset = 6 - Standard.Holster(0, EquipmentSize.Pistol) - Standard.Holster(2, EquipmentSize.Rifle) - Standard.Holster(4, EquipmentSize.Melee) - Standard.ResistanceDirectHit = 4 - Standard.ResistanceSplash = 15 - Standard.ResistanceAggravated = 8 - - final val Agile = ExoSuitDefinition(ExoSuitType.Agile) - Agile.MaxArmor = 100 - Agile.InventoryScale = InventoryTile.Tile99 - Agile.InventoryOffset = 6 - Agile.Holster(0, EquipmentSize.Pistol) - Agile.Holster(1, EquipmentSize.Pistol) - Agile.Holster(2, EquipmentSize.Rifle) - Agile.Holster(4, EquipmentSize.Melee) - Agile.ResistanceDirectHit = 6 - Agile.ResistanceSplash = 25 - Agile.ResistanceAggravated = 10 - - final val Reinforced = ExoSuitDefinition(ExoSuitType.Reinforced) - Reinforced.permission = 1 - Reinforced.MaxArmor = 200 - Reinforced.InventoryScale = InventoryTile.Tile1209 - Reinforced.InventoryOffset = 6 - Reinforced.Holster(0, EquipmentSize.Pistol) - Reinforced.Holster(1, EquipmentSize.Pistol) - Reinforced.Holster(2, EquipmentSize.Rifle) - Reinforced.Holster(3, EquipmentSize.Rifle) - Reinforced.Holster(4, EquipmentSize.Melee) - Reinforced.ResistanceDirectHit = 10 - Reinforced.ResistanceSplash = 35 - Reinforced.ResistanceAggravated = 12 - - final val Infiltration = ExoSuitDefinition(ExoSuitType.Infiltration) - Infiltration.permission = 1 - Infiltration.MaxArmor = 0 - Infiltration.InventoryScale = InventoryTile.Tile66 - Infiltration.InventoryOffset = 6 - Infiltration.Holster(0, EquipmentSize.Pistol) - Infiltration.Holster(4, EquipmentSize.Melee) - - final val MAX = SpecialExoSuitDefinition(ExoSuitType.MAX) - MAX.permission = 1 - MAX.MaxArmor = 650 - MAX.InventoryScale = InventoryTile.Tile1612 - MAX.InventoryOffset = 6 - MAX.Holster(0, EquipmentSize.Max) - MAX.Holster(4, EquipmentSize.Melee) - MAX.Subtract.Damage1 = -2 - MAX.ResistanceDirectHit = 6 - MAX.ResistanceSplash = 35 - MAX.ResistanceAggravated = 10 - MAX.Damage = StandardMaxDamage - MAX.Model = StandardResolutions.Max - def apply(suitType : ExoSuitType.Value) : ExoSuitDefinition = { new ExoSuitDefinition(suitType) } @@ -188,11 +141,11 @@ object ExoSuitDefinition { */ def Select(suit : ExoSuitType.Value) : ExoSuitDefinition = { suit match { - case ExoSuitType.Agile => ExoSuitDefinition.Agile.Use - case ExoSuitType.Infiltration => ExoSuitDefinition.Infiltration.Use - case ExoSuitType.MAX => ExoSuitDefinition.MAX.Use - case ExoSuitType.Reinforced => ExoSuitDefinition.Reinforced.Use - case _ => ExoSuitDefinition.Standard.Use + case ExoSuitType.Agile => GlobalDefinitions.Agile.Use + case ExoSuitType.Infiltration => GlobalDefinitions.Infiltration.Use + case ExoSuitType.MAX => GlobalDefinitions.MAX.Use + case ExoSuitType.Reinforced => GlobalDefinitions.Reinforced.Use + case _ => GlobalDefinitions.Standard.Use } } } diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/ACEConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/ACEConverter.scala index d45acda1..da288462 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/ACEConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/ACEConverter.scala @@ -2,16 +2,45 @@ package net.psforever.objects.definition.converter import net.psforever.objects.ConstructionItem -import net.psforever.packet.game.objectcreate.{ACEData, DetailedACEData} +import net.psforever.packet.game.PlanetSideGUID +import net.psforever.packet.game.objectcreate.{CommonFieldData, DetailedConstructionToolData, HandheldData} import scala.util.{Success, Try} class ACEConverter extends ObjectCreateConverter[ConstructionItem]() { - override def ConstructorData(obj : ConstructionItem) : Try[ACEData] = { - Success(ACEData(0,0)) + override def ConstructorData(obj : ConstructionItem) : Try[HandheldData] = { + Success( + HandheldData( + CommonFieldData( + obj.Faction, + false, + false, + true, + None, + false, + None, + None, + PlanetSideGUID(0) + ) + ) + ) } - override def DetailedConstructorData(obj : ConstructionItem) : Try[DetailedACEData] = { - Success(DetailedACEData(0)) + override def DetailedConstructorData(obj : ConstructionItem) : Try[DetailedConstructionToolData] = { + Success( + DetailedConstructionToolData( + CommonFieldData( + obj.Faction, + false, + false, + true, + None, + false, + None, + None, + PlanetSideGUID(0) + ) + ) + ) } } diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/AmmoBoxConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/AmmoBoxConverter.scala index 890a9963..84a5a81b 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/AmmoBoxConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/AmmoBoxConverter.scala @@ -2,16 +2,33 @@ package net.psforever.objects.definition.converter import net.psforever.objects.AmmoBox -import net.psforever.packet.game.objectcreate.{AmmoBoxData, DetailedAmmoBoxData} +import net.psforever.packet.game.PlanetSideGUID +import net.psforever.packet.game.objectcreate.{CommonFieldData, DetailedAmmoBoxData} +import net.psforever.types.PlanetSideEmpire import scala.util.{Success, Try} class AmmoBoxConverter extends ObjectCreateConverter[AmmoBox] { - override def ConstructorData(obj : AmmoBox) : Try[AmmoBoxData] = { - Success(AmmoBoxData()) + override def ConstructorData(obj : AmmoBox) : Try[CommonFieldData] = { + Success(CommonFieldData()(false)) } override def DetailedConstructorData(obj : AmmoBox) : Try[DetailedAmmoBoxData] = { - Success(DetailedAmmoBoxData(8, obj.Capacity)) + Success( + DetailedAmmoBoxData( + CommonFieldData( + PlanetSideEmpire.NEUTRAL, + bops = false, + alternate = false, + true, + None, + false, + None, + None, + PlanetSideGUID(0) + ), + obj.Capacity + ) + ) } } diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala index 24e80263..a141529c 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala @@ -1,8 +1,9 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.definition.converter -import net.psforever.objects.{EquipmentSlot, Player} -import net.psforever.objects.equipment.Equipment +import net.psforever.objects.Player +import net.psforever.objects.equipment.{Equipment, EquipmentSlot} +import net.psforever.packet.game.PlanetSideGUID import net.psforever.packet.game.objectcreate._ import net.psforever.types.{ExoSuitType, GrenadeState, ImplantType} @@ -63,18 +64,22 @@ object AvatarConverter { * @param obj the `Player` game object * @return the resulting `CharacterAppearanceData` */ - def MakeAppearanceData(obj : Player) : (Int)=>CharacterAppearanceData = { + def MakeAppearanceData(obj : Player) : Int=>CharacterAppearanceData = { val alt_model_flag : Boolean = obj.isBackpack val aa : Int=>CharacterAppearanceA = CharacterAppearanceA( BasicCharacterData(obj.Name, obj.Faction, obj.Sex, obj.Head, obj.Voice), - black_ops = false, - alt_model_flag, - false, - None, - jammered = false, + CommonFieldData( + obj.Faction, + bops = false, + alt_model_flag, + false, + None, + false, + None, + v5 = None, + PlanetSideGUID(0) + ), obj.ExoSuit, - None, - 0, 0, 0L, 0, @@ -108,22 +113,22 @@ object AvatarConverter { def MakeCharacterData(obj : Player) : (Boolean,Boolean)=>CharacterData = { val MaxArmor = obj.MaxArmor CharacterData( - 255 * obj.Health / obj.MaxHealth, + StatConverter.Health(obj.Health, obj.MaxHealth), if(MaxArmor == 0) { 0 } else { - 255 * obj.Armor / MaxArmor + StatConverter.Health(obj.Armor, MaxArmor) }, DressBattleRank(obj), 0, DressCommandRank(obj), MakeImplantEffectList(obj.Implants), - MakeCosmetics(obj.BEP) + MakeCosmetics(obj) ) } - def MakeDetailedCharacterData(obj : Player) : (Option[Int])=>DetailedCharacterData = { + def MakeDetailedCharacterData(obj : Player) : Option[Int]=>DetailedCharacterData = { val bep : Long = obj.BEP val maxOpt : Option[Long] = if(obj.ExoSuit == ExoSuitType.MAX) { Some(0L) } else { None } val ba : DetailedCharacterA = DetailedCharacterA( @@ -149,9 +154,9 @@ object AvatarConverter { 0L, 0L, 0L, 0L, 0L, Some(DCDExtra2(0, 0)), Nil, Nil, false, - MakeCosmetics(bep) + MakeCosmetics(obj) ) - (pad_length : Option[Int]) => DetailedCharacterData(ba, bb(bep, pad_length))(pad_length) + pad_length : Option[Int] => DetailedCharacterData(ba, bb(bep, pad_length))(pad_length) } def MakeInventoryData(obj : Player) : InventoryData = { @@ -219,8 +224,8 @@ object AvatarConverter { * @see `ImplantEntry` in `DetailedCharacterData` */ private def MakeImplantEntries(obj : Player) : List[ImplantEntry] = { - val numImplants : Int = DetailedCharacterData.numberOfImplantSlots(obj.BEP) - val implants = obj.Implants + //val numImplants : Int = DetailedCharacterData.numberOfImplantSlots(obj.BEP) + //val implants = obj.Implants obj.Implants.map({ case(implant, initialization, _) => if(initialization == 0) { ImplantEntry(implant, None) @@ -238,7 +243,7 @@ object AvatarConverter { */ private def MakeImplantEffectList(implants : Seq[(ImplantType.Value, Long, Boolean)]) : List[ImplantEffects.Value] = { implants.collect { - case ((implant,_,true)) => + case (implant,_,true) => implant match { case ImplantType.AdvancedRegen => ImplantEffects.RegenEffects @@ -253,14 +258,16 @@ object AvatarConverter { } /** - * Should this player be of battle rank 24 or higher, they will have a mandatory cosmetics object. - * @param bep battle experience points + * Should this player be of battle rank 24 or higher, they will have a mandatory cosmetics object in their bitstream. + * Players that have not yet set any cosmetic personal effects will still have this field recorded as `None` + * but it must be represented nonetheless. + * @param obj the `Player` game object * @see `Cosmetics` * @return the `Cosmetics` options */ - def MakeCosmetics(bep : Long) : Option[Cosmetics] = - if(DetailedCharacterData.isBR24(bep)) { - Some(Cosmetics(false, false, false, false, false)) + def MakeCosmetics(obj : Player) : Option[Cosmetics] = + if(DetailedCharacterData.isBR24(obj.BEP)) { + obj.PersonalStyleFeatures.orElse(Some(Cosmetics())) } else { None @@ -290,7 +297,7 @@ object AvatarConverter { * @param builder the function used to transform to the decoded packet form * @return a list of all items that were in the holsters in decoded packet form */ - private def MakeHolsters(obj : Player, builder : ((Int, Equipment) => InternalSlot)) : List[InternalSlot] = { + private def MakeHolsters(obj : Player, builder : (Int, Equipment) => InternalSlot) : List[InternalSlot] = { recursiveMakeHolsters(obj.Holsters().iterator, builder) } @@ -338,7 +345,7 @@ object AvatarConverter { * @param index which holster is currently being explored * @return the `List` of inventory data created from the holsters */ - @tailrec private def recursiveMakeHolsters(iter : Iterator[EquipmentSlot], builder : ((Int, Equipment) => InternalSlot), list : List[InternalSlot] = Nil, index : Int = 0) : List[InternalSlot] = { + @tailrec private def recursiveMakeHolsters(iter : Iterator[EquipmentSlot], builder : (Int, Equipment) => InternalSlot, list : List[InternalSlot] = Nil, index : Int = 0) : List[InternalSlot] = { if(!iter.hasNext) { list } diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/BoomerTriggerConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/BoomerTriggerConverter.scala index 6f817afe..2d1ef391 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/BoomerTriggerConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/BoomerTriggerConverter.scala @@ -2,16 +2,20 @@ package net.psforever.objects.definition.converter import net.psforever.objects.SimpleItem -import net.psforever.packet.game.objectcreate.{BoomerTriggerData, DetailedBoomerTriggerData} +import net.psforever.packet.game.PlanetSideGUID +import net.psforever.packet.game.objectcreate.{CommonFieldData, DetailedConstructionToolData, HandheldData} +import net.psforever.types.PlanetSideEmpire import scala.util.{Success, Try} class BoomerTriggerConverter extends ObjectCreateConverter[SimpleItem]() { - override def ConstructorData(obj : SimpleItem) : Try[BoomerTriggerData] = { - Success(BoomerTriggerData()) + override def ConstructorData(obj : SimpleItem) : Try[HandheldData] = { + Success(HandheldData(CommonFieldData())) } - override def DetailedConstructorData(obj : SimpleItem) : Try[DetailedBoomerTriggerData] = { - Success(DetailedBoomerTriggerData()) + override def DetailedConstructorData(obj : SimpleItem) : Try[DetailedConstructionToolData] = { + Success(DetailedConstructionToolData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)) + )) } } diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/CharacterSelectConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/CharacterSelectConverter.scala index 9812e6a6..7a4414a5 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/CharacterSelectConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/CharacterSelectConverter.scala @@ -1,8 +1,9 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.definition.converter -import net.psforever.objects.{EquipmentSlot, Player} -import net.psforever.objects.equipment.Equipment +import net.psforever.objects.Player +import net.psforever.objects.equipment.{Equipment, EquipmentSlot} +import net.psforever.packet.game.PlanetSideGUID import net.psforever.packet.game.objectcreate._ import net.psforever.types._ @@ -35,17 +36,21 @@ class CharacterSelectConverter extends AvatarConverter { * @see `AvatarConverter.MakeAppearanceData` * @return the resulting `CharacterAppearanceData` */ - private def MakeAppearanceData(obj : Player) : (Int)=>CharacterAppearanceData = { + private def MakeAppearanceData(obj : Player) : Int=>CharacterAppearanceData = { val aa : Int=>CharacterAppearanceA = CharacterAppearanceA( BasicCharacterData(obj.Name, obj.Faction, obj.Sex, obj.Head, CharacterVoice.Mute), - black_ops = false, - false, - false, - None, - jammered = false, + CommonFieldData( + obj.Faction, + bops = false, + false, + false, + None, + false, + None, + v5 = None, + PlanetSideGUID(0) + ), obj.ExoSuit, - None, - 0, 0, 0L, 0, @@ -76,7 +81,7 @@ class CharacterSelectConverter extends AvatarConverter { CharacterAppearanceData(aa, ab, RibbonBars()) } - private def MakeDetailedCharacterData(obj : Player) : (Option[Int]=>DetailedCharacterData) = { + private def MakeDetailedCharacterData(obj : Player) : Option[Int]=>DetailedCharacterData = { val bep : Long = obj.BEP val maxOpt : Option[Long] = if(obj.ExoSuit == ExoSuitType.MAX) { Some(0L) } else { None } val ba : DetailedCharacterA = DetailedCharacterA( @@ -102,9 +107,9 @@ class CharacterSelectConverter extends AvatarConverter { 0L, 0L, 0L, 0L, 0L, Some(DCDExtra2(0, 0)), Nil, Nil, false, - AvatarConverter.MakeCosmetics(bep) + AvatarConverter.MakeCosmetics(obj) ) - (pad_length : Option[Int]) => DetailedCharacterData(ba, bb(bep, pad_length))(pad_length) + pad_length : Option[Int] => DetailedCharacterData(ba, bb(bep, pad_length))(pad_length) } /** diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/CommandDetonaterConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/CommandDetonaterConverter.scala index 014d5bd8..0ce8e21c 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/CommandDetonaterConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/CommandDetonaterConverter.scala @@ -2,16 +2,46 @@ package net.psforever.objects.definition.converter import net.psforever.objects.SimpleItem -import net.psforever.packet.game.objectcreate.{CommandDetonaterData, DetailedCommandDetonaterData} +import net.psforever.packet.game.PlanetSideGUID +import net.psforever.packet.game.objectcreate.{CommonFieldData, DetailedCommandDetonaterData, HandheldData} +import net.psforever.types.PlanetSideEmpire import scala.util.{Success, Try} class CommandDetonaterConverter extends ObjectCreateConverter[SimpleItem]() { - override def ConstructorData(obj : SimpleItem) : Try[CommandDetonaterData] = { - Success(CommandDetonaterData()) + override def ConstructorData(obj : SimpleItem) : Try[HandheldData] = { + Success( + HandheldData( + CommonFieldData( + obj.Faction, + false, + false, + false, + None, + false, + None, + None, + PlanetSideGUID(0) + ) + ) + ) } override def DetailedConstructorData(obj : SimpleItem) : Try[DetailedCommandDetonaterData] = { - Success(DetailedCommandDetonaterData()) + Success( + DetailedCommandDetonaterData( + CommonFieldData( + obj.Faction, + false, + false, + false, + None, + false, + None, + None, + PlanetSideGUID(0) + ) + ) + ) } } diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/CorpseConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/CorpseConverter.scala index e108fc22..bef8593a 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/CorpseConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/CorpseConverter.scala @@ -1,8 +1,9 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.definition.converter -import net.psforever.objects.{EquipmentSlot, Player} -import net.psforever.objects.equipment.Equipment +import net.psforever.objects.Player +import net.psforever.objects.equipment.{Equipment, EquipmentSlot} +import net.psforever.packet.game.PlanetSideGUID import net.psforever.packet.game.objectcreate._ import net.psforever.types._ @@ -30,17 +31,21 @@ class CorpseConverter extends AvatarConverter { * @param obj the `Player` game object * @return the resulting `CharacterAppearanceData` */ - private def MakeAppearanceData(obj : Player) : (Int)=>CharacterAppearanceData = { + private def MakeAppearanceData(obj : Player) : Int=>CharacterAppearanceData = { val aa : Int=>CharacterAppearanceA = CharacterAppearanceA( BasicCharacterData(obj.Name, obj.Faction, CharacterGender.Male, 0, CharacterVoice.Mute), - black_ops = false, - altModel = true, - false, - None, - jammered = false, + CommonFieldData( + obj.Faction, + bops = false, + alternate = true, + false, + None, + false, + None, + v5 = None, + PlanetSideGUID(0) + ), obj.ExoSuit, - None, - 0, 0, 0L, 0, @@ -71,7 +76,7 @@ class CorpseConverter extends AvatarConverter { CharacterAppearanceData(aa, ab, RibbonBars()) } - private def MakeDetailedCharacterData(obj : Player) : (Option[Int]=>DetailedCharacterData) = { + private def MakeDetailedCharacterData(obj : Player) : Option[Int]=>DetailedCharacterData = { val maxOpt : Option[Long] = if(obj.ExoSuit == ExoSuitType.MAX) { Some(0L) } else { None } val ba : DetailedCharacterA = DetailedCharacterA( bep = 0L, diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/FieldTurretConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/FieldTurretConverter.scala index 0139069d..9ced731e 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/FieldTurretConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/FieldTurretConverter.scala @@ -11,22 +11,26 @@ import scala.util.{Failure, Success, Try} class FieldTurretConverter extends ObjectCreateConverter[TurretDeployable]() { override def ConstructorData(obj : TurretDeployable) : Try[OneMannedFieldTurretData] = { - val health = 255 * obj.Health / obj.MaxHealth //TODO not precise + val health = StatConverter.Health(obj.Health, obj.MaxHealth) if(health > 3) { Success( OneMannedFieldTurretData( - SmallDeployableData( + CommonFieldDataWithPlacement( PlacementData(obj.Position, obj.Orientation), - obj.Faction, - bops = false, - destroyed = false, - unk1 = 0, - obj.Jammered, - unk2 = false, - obj.Owner match { - case Some(owner) => owner - case None => PlanetSideGUID(0) - } + CommonFieldData( + obj.Faction, + bops = false, + alternate = false, + true, + None, + false, + Some(false), + None, + obj.Owner match { + case Some(owner) => owner + case None => PlanetSideGUID(0) + } + ) ), health, Some(InventoryData(FieldTurretConverter.MakeMountings(obj))) @@ -36,18 +40,21 @@ class FieldTurretConverter extends ObjectCreateConverter[TurretDeployable]() { else { Success( OneMannedFieldTurretData( - SmallDeployableData( + CommonFieldDataWithPlacement( PlacementData(obj.Position, obj.Orientation), - obj.Faction, - bops = false, - destroyed = true, - unk1 = 0, - jammered = false, - unk2 = false, - owner_guid = PlanetSideGUID(0) + CommonFieldData( + obj.Faction, + bops = false, + alternate = true, + true, + None, + false, + Some(false), + None, + PlanetSideGUID(0) + ) ), - 0, - None + 0 ) ) } @@ -60,7 +67,7 @@ class FieldTurretConverter extends ObjectCreateConverter[TurretDeployable]() { object FieldTurretConverter { private def MakeMountings(obj : WeaponTurret) : List[InventoryItemData.InventoryItem] = { obj.Weapons.map({ - case((index, slot)) => + case(index, slot) => val equip : Equipment = slot.Equipment.get val equipDef = equip.Definition InventoryItemData(equipDef.ObjectId, equip.GUID, index, equipDef.Packet.ConstructorData(equip).get) diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/ImplantTerminalInterfaceConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/ImplantTerminalInterfaceConverter.scala deleted file mode 100644 index d27d167a..00000000 --- a/common/src/main/scala/net/psforever/objects/definition/converter/ImplantTerminalInterfaceConverter.scala +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.objects.definition.converter - -import net.psforever.objects.serverobject.terminals.Terminal -import net.psforever.packet.game.objectcreate.CommonTerminalData - -import scala.util.{Failure, Success, Try} - -class ImplantTerminalInterfaceConverter extends ObjectCreateConverter[Terminal]() { - override def DetailedConstructorData(obj : Terminal) : Try[CommonTerminalData] = - Failure(new Exception("ImplantTerminalInterfaceConverter should not be used to generate detailed CommonTerminalData")) - - override def ConstructorData(obj : Terminal) : Try[CommonTerminalData] = - Success(CommonTerminalData(net.psforever.types.PlanetSideEmpire.VS)) //TODO shortcut -} diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/InternalTelepadDeployableConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/InternalTelepadDeployableConverter.scala index a2b50cf9..780d5f89 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/InternalTelepadDeployableConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/InternalTelepadDeployableConverter.scala @@ -3,12 +3,39 @@ package net.psforever.objects.definition.converter import net.psforever.objects.PlanetSideGameObject import net.psforever.objects.ce.TelepadLike +import net.psforever.packet.game.PlanetSideGUID import net.psforever.packet.game.objectcreate._ +import net.psforever.types.PlanetSideEmpire -import scala.util.{Success, Try} +import scala.util.{Failure, Success, Try} class InternalTelepadDeployableConverter extends ObjectCreateConverter[PlanetSideGameObject with TelepadLike]() { - override def ConstructorData(obj : PlanetSideGameObject with TelepadLike) : Try[ContainedTelepadDeployableData] = { - Success(ContainedTelepadDeployableData(101, obj.Router.get)) + override def ConstructorData(obj : PlanetSideGameObject with TelepadLike) : Try[TelepadDeployableData] = { + obj.Router match { + case Some(PlanetSideGUID(0)) => + Failure(new IllegalStateException("InternalTelepadDeployableConverter: knowledge of parent Router is null")) + + case Some(router) => + Success( + TelepadDeployableData( + CommonFieldData( + PlanetSideEmpire.NEUTRAL, + bops = false, + alternate = false, + true, + None, + false, + None, + Some(router.guid), + PlanetSideGUID(0) + ), + unk1 = 128, + unk2 = 0 + ) + ) + + case None => + Failure(new IllegalStateException("InternalTelepadDeployableConverter: telepad needs to know id of its parent Router")) + } } } diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/KitConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/KitConverter.scala index 1b0e137d..31176a73 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/KitConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/KitConverter.scala @@ -2,13 +2,13 @@ package net.psforever.objects.definition.converter import net.psforever.objects.Kit -import net.psforever.packet.game.objectcreate.{AmmoBoxData, DetailedAmmoBoxData} +import net.psforever.packet.game.objectcreate.{CommonFieldData, DetailedAmmoBoxData} import scala.util.{Success, Try} class KitConverter extends ObjectCreateConverter[Kit]() { - override def ConstructorData(obj : Kit) : Try[AmmoBoxData] = { - Success(AmmoBoxData()) + override def ConstructorData(obj : Kit) : Try[CommonFieldData] = { + Success(CommonFieldData()(false)) } override def DetailedConstructorData(obj : Kit) : Try[DetailedAmmoBoxData] = { diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala index 124a4c97..5a4a2083 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala @@ -4,21 +4,34 @@ package net.psforever.objects.definition.converter import net.psforever.objects.LockerContainer import net.psforever.objects.equipment.Equipment import net.psforever.objects.inventory.GridInventory +import net.psforever.packet.game.PlanetSideGUID import net.psforever.packet.game.objectcreate._ +import net.psforever.types.PlanetSideEmpire import scala.util.{Success, Try} class LockerContainerConverter extends ObjectCreateConverter[LockerContainer]() { override def ConstructorData(obj : LockerContainer) : Try[LockerContainerData] = { - Success(LockerContainerData(InventoryData(MakeInventory(obj.Inventory)))) + MakeInventory(obj.Inventory) match { + case Nil => + Success(LockerContainerData(None)) + case list => + Success(LockerContainerData(InventoryData(list))) + } } override def DetailedConstructorData(obj : LockerContainer) : Try[DetailedLockerContainerData] = { if(obj.Inventory.Size > 0) { - Success(DetailedLockerContainerData(8, Some(InventoryData(MakeDetailedInventory(obj.Inventory))))) + Success(DetailedLockerContainerData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), + Some(InventoryData(MakeDetailedInventory(obj.Inventory))) + )) } else { - Success(DetailedLockerContainerData(8, None)) + Success(DetailedLockerContainerData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), + None + )) } } diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/REKConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/REKConverter.scala index b35c789a..79446b2a 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/REKConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/REKConverter.scala @@ -2,16 +2,45 @@ package net.psforever.objects.definition.converter import net.psforever.objects.SimpleItem -import net.psforever.packet.game.objectcreate.{DetailedREKData, REKData} +import net.psforever.packet.game.PlanetSideGUID +import net.psforever.packet.game.objectcreate.{CommonFieldData, DetailedREKData, REKData} +import net.psforever.types.PlanetSideEmpire import scala.util.{Success, Try} class REKConverter extends ObjectCreateConverter[SimpleItem]() { override def ConstructorData(obj : SimpleItem) : Try[REKData] = { - Success(REKData(8,0)) + Success( + REKData( + CommonFieldData( + PlanetSideEmpire.NEUTRAL, //TODO faction affinity + false, + false, + true, + None, + false, + Some(false), + None, + PlanetSideGUID(0)) + ) + ) } override def DetailedConstructorData(obj : SimpleItem) : Try[DetailedREKData] = { - Success(DetailedREKData(8)) + Success( + DetailedREKData( + CommonFieldData( + PlanetSideEmpire.NEUTRAL, //TODO faction affinity + false, + false, + true, + None, + false, + Some(false), + None, + PlanetSideGUID(0) + ) + ) + ) } -} \ No newline at end of file +} diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/ShieldGeneratorConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/ShieldGeneratorConverter.scala index 559d4152..75b77a9c 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/ShieldGeneratorConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/ShieldGeneratorConverter.scala @@ -9,21 +9,26 @@ import scala.util.{Failure, Success, Try} class ShieldGeneratorConverter extends ObjectCreateConverter[ShieldGeneratorDeployable]() { override def ConstructorData(obj : ShieldGeneratorDeployable) : Try[AegisShieldGeneratorData] = { - val health = 255 * obj.Health / obj.MaxHealth //TODO not precise + val health = StatConverter.Health(obj.Health, obj.MaxHealth) if(health > 0) { Success( AegisShieldGeneratorData( - CommonFieldData( + CommonFieldDataWithPlacement( PlacementData(obj.Position, obj.Orientation), - obj.Faction, - bops = false, - destroyed = false, - unk = 0, - jammered = false, - obj.Owner match { - case Some(owner) => owner - case None => PlanetSideGUID(0) - } + CommonFieldData( + obj.Faction, + bops = false, + alternate = false, + v1 = false, + v2 = None, + v3 = false, + None, + None, + obj.Owner match { + case Some(owner) => owner + case None => PlanetSideGUID(0) + } + ) ), health ) @@ -32,14 +37,19 @@ class ShieldGeneratorConverter extends ObjectCreateConverter[ShieldGeneratorDepl else { Success( AegisShieldGeneratorData( - CommonFieldData( + CommonFieldDataWithPlacement( PlacementData(obj.Position, obj.Orientation), - obj.Faction, - bops = false, - destroyed = true, - unk = 0, - jammered = false, - player_guid = PlanetSideGUID(0) + CommonFieldData( + obj.Faction, + bops = false, + alternate = true, + v1 = false, + v2 = None, + v3 = false, + None, + None, + PlanetSideGUID(0) + ) ), 0 ) diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/SmallDeployableConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/SmallDeployableConverter.scala index bd327b21..7b10159b 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/SmallDeployableConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/SmallDeployableConverter.scala @@ -4,29 +4,33 @@ package net.psforever.objects.definition.converter import net.psforever.objects.ce.Deployable import net.psforever.objects.PlanetSideGameObject import net.psforever.packet.game.PlanetSideGUID -import net.psforever.packet.game.objectcreate.{PlacementData, SmallDeployableData} +import net.psforever.packet.game.objectcreate._ import scala.util.{Failure, Success, Try} class SmallDeployableConverter extends ObjectCreateConverter[PlanetSideGameObject with Deployable]() { - override def ConstructorData(obj : PlanetSideGameObject with Deployable) : Try[SmallDeployableData] = { + override def ConstructorData(obj : PlanetSideGameObject with Deployable) : Try[CommonFieldDataWithPlacement] = { Success( - SmallDeployableData( + CommonFieldDataWithPlacement( PlacementData(obj.Position, obj.Orientation), - obj.Faction, - bops = false, - destroyed = false, - unk1 = 0, - jammered = false, - unk2 = false, - obj.Owner match { - case Some(owner) => owner - case None => PlanetSideGUID(0) - } + CommonFieldData( + obj.Faction, + false, + false, + false, + None, + false, + Some(false), + None, + obj.Owner match { + case Some(owner) => owner + case None => PlanetSideGUID(0) + } + ) ) ) } - override def DetailedConstructorData(obj : PlanetSideGameObject with Deployable) : Try[SmallDeployableData] = - Failure(new Exception("converter should not be used to generate detailed SmallDeployableData")) + override def DetailedConstructorData(obj : PlanetSideGameObject with Deployable) : Try[CommonFieldDataWithPlacement] = + Failure(new Exception("converter should not be used to generate detailed small deployable data")) } \ No newline at end of file diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/SmallTurretConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/SmallTurretConverter.scala index 25e74d52..ec01eccc 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/SmallTurretConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/SmallTurretConverter.scala @@ -11,22 +11,26 @@ import scala.util.{Failure, Success, Try} class SmallTurretConverter extends ObjectCreateConverter[TurretDeployable]() { override def ConstructorData(obj : TurretDeployable) : Try[SmallTurretData] = { - val health = 255 * obj.Health / obj.MaxHealth //TODO not precise + val health = StatConverter.Health(obj.Health, obj.MaxHealth) if(health > 0) { Success( SmallTurretData( - SmallDeployableData( + CommonFieldDataWithPlacement( PlacementData(obj.Position, obj.Orientation), - obj.Faction, - bops = false, - destroyed = false, - unk1 = 0, - obj.Jammered, - unk2 = false, - obj.Owner match { - case Some(owner) => owner - case None => PlanetSideGUID(0) - } + CommonFieldData( + obj.Faction, + bops = false, + alternate = false, + false, + None, + false, + Some(true), + None, + obj.Owner match { + case Some(owner) => owner + case None => PlanetSideGUID(0) + } + ) ), health, Some(InventoryData(SmallTurretConverter.MakeMountings(obj))) @@ -36,18 +40,21 @@ class SmallTurretConverter extends ObjectCreateConverter[TurretDeployable]() { else { Success( SmallTurretData( - SmallDeployableData( + CommonFieldDataWithPlacement( PlacementData(obj.Position, obj.Orientation), - obj.Faction, - bops = false, - destroyed = true, - unk1 = 0, - jammered = false, - unk2 = false, - owner_guid = PlanetSideGUID(0) + CommonFieldData( + obj.Faction, + bops = false, + alternate = true, + false, + None, + false, + Some(false), + None, + PlanetSideGUID(0) + ) ), - 0, - None + 0 ) ) } diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/SpawnTubeConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/SpawnTubeConverter.scala index 56671f98..25957ae3 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/SpawnTubeConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/SpawnTubeConverter.scala @@ -2,10 +2,10 @@ package net.psforever.objects.definition.converter import net.psforever.objects.serverobject.tube.SpawnTube -import net.psforever.packet.game.objectcreate.CommonTerminalData +import net.psforever.packet.game.objectcreate.CommonFieldData import scala.util.{Success, Try} class SpawnTubeConverter extends ObjectCreateConverter[SpawnTube]() { - override def ConstructorData(obj : SpawnTube) : Try[CommonTerminalData] = { Success(CommonTerminalData(obj.Faction)) } + override def ConstructorData(obj : SpawnTube) : Try[CommonFieldData] = { Success(CommonFieldData(obj.Faction)(false)) } } diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/StatConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/StatConverter.scala new file mode 100644 index 00000000..aa204fd6 --- /dev/null +++ b/common/src/main/scala/net/psforever/objects/definition/converter/StatConverter.scala @@ -0,0 +1,20 @@ +package net.psforever.objects.definition.converter + +object StatConverter { + /** + * Takes a measure of a value against the maximum possible value and + * transforms it to a scaled number that can be written within a specific domain.
+ *
+ * The default (and absolutely common) situation writes a scaled number that can be represented by an unsigned `8u`. + * The maximum value is 255, or 2^8^ - 1. + * The minimum value is 0; + * but, due to how game models are represented at various health, + * the representable minimum value is allowed to plateau at 3. + * Any result less than 3 creates the same situation as if the result were 0. + */ + def Health(health : Int, maxHealth : Int, min : Int = 3, max : Int = 255) : Int = + if(health < 1) 0 + else if(health <= min || min >= max) min + else if(health >= maxHealth) max + else math.floor(max * health / maxHealth).toInt +} diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/TRAPConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/TRAPConverter.scala index 3bcfa303..3c423a17 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/TRAPConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/TRAPConverter.scala @@ -9,22 +9,26 @@ import scala.util.{Failure, Success, Try} class TRAPConverter extends ObjectCreateConverter[TrapDeployable]() { override def ConstructorData(obj : TrapDeployable) : Try[TRAPData] = { - val health = 255 * obj.Health / obj.MaxHealth //TODO not precise + val health = StatConverter.Health(obj.Health, obj.MaxHealth) if(health > 0) { Success( TRAPData( - SmallDeployableData( + CommonFieldDataWithPlacement( PlacementData(obj.Position, obj.Orientation), - obj.Faction, - bops = false, - destroyed = false, - unk1 = 0, - jammered = false, - unk2 = false, - obj.Owner match { - case Some(owner) => owner - case None => PlanetSideGUID(0) - } + CommonFieldData( + obj.Faction, + bops = false, + alternate = false, + true, + None, + false, + Some(true), + None, + obj.Owner match { + case Some(owner) => owner + case None => PlanetSideGUID(0) + } + ) ), health ) @@ -33,15 +37,19 @@ class TRAPConverter extends ObjectCreateConverter[TrapDeployable]() { else { Success( TRAPData( - SmallDeployableData( + CommonFieldDataWithPlacement( PlacementData(obj.Position, obj.Orientation), - obj.Faction, - bops = false, - destroyed = true, - unk1 = 0, - jammered = false, - unk2 = false, - owner_guid = PlanetSideGUID(0) + CommonFieldData( + obj.Faction, + bops = false, + alternate = true, + true, + None, + false, + Some(true), + None, + PlanetSideGUID(0) + ) ), 0 ) diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/TelepadConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/TelepadConverter.scala index 4a0b9094..07114a3b 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/TelepadConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/TelepadConverter.scala @@ -2,24 +2,53 @@ package net.psforever.objects.definition.converter import net.psforever.objects.Telepad -import net.psforever.packet.game.objectcreate._ +import net.psforever.packet.game.PlanetSideGUID +import net.psforever.packet.game.objectcreate.{CommonFieldData, DetailedConstructionToolData, HandheldData} import scala.util.{Failure, Success, Try} class TelepadConverter extends ObjectCreateConverter[Telepad]() { - override def ConstructorData(obj : Telepad) : Try[TelepadData] = { + override def ConstructorData(obj : Telepad) : Try[HandheldData] = { obj.Router match { - case Some(_) => - Success(TelepadData (0, obj.Router)) + case Some(router) => + Success( + HandheldData( + CommonFieldData( + obj.Faction, + false, + false, + false, + None, + false, + None, + Some(router.guid), + PlanetSideGUID(0) + ) + ) + ) case None => Failure(new IllegalStateException("TelepadConverter: telepad needs to know id of its router")) } } - override def DetailedConstructorData(obj : Telepad) : Try[DetailedTelepadData] = { + override def DetailedConstructorData(obj : Telepad) : Try[DetailedConstructionToolData] = { obj.Router match { - case Some(_) => - Success(DetailedTelepadData (0, obj.Router)) + case Some(router) => + Success( + DetailedConstructionToolData( + CommonFieldData( + obj.Faction, + false, + false, + true, + None, + false, + None, + Some(router.guid), + PlanetSideGUID(0) + ) + ) + ) case None => Failure(new IllegalStateException("TelepadConverter: telepad needs to know id of its router")) } diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/TelepadDeployableConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/TelepadDeployableConverter.scala index b424b070..9971940d 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/TelepadDeployableConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/TelepadDeployableConverter.scala @@ -8,39 +8,59 @@ import net.psforever.packet.game.objectcreate._ import scala.util.{Failure, Success, Try} class TelepadDeployableConverter extends ObjectCreateConverter[TelepadDeployable]() { - override def ConstructorData(obj : TelepadDeployable) : Try[TelepadDeployableData] = { - if(obj.Router.isEmpty || obj.Router.contains(PlanetSideGUID(0))) { - Failure(new IllegalStateException("TelepadDeployableConverter: telepad deployable needs to know id of its router")) - } - else { - if(obj.Health > 0) { - Success(TelepadDeployableData( - PlacementData(obj.Position, obj.Orientation), - obj.Faction, - bops = false, - destroyed = false, - unk1 = 2, - unk2 = true, - obj.Router.get, - obj.Owner.getOrElse(PlanetSideGUID(0)), - unk3 = 87, - unk4 = 12 - )) - } - else { - Success(TelepadDeployableData( - PlacementData(obj.Position, obj.Orientation), - obj.Faction, - bops = false, - destroyed = true, - unk1 = 2, - unk2 = true, - obj.Router.get, - owner_guid = PlanetSideGUID(0), - unk3 = 0, - unk4 = 6 - )) - } + override def ConstructorData(obj : TelepadDeployable) : Try[DroppedItemData[TelepadDeployableData]] = { + obj.Router match { + case Some(PlanetSideGUID(0)) => + Failure(new IllegalStateException("TelepadDeployableConverter: knowledge of associated Router is null")) + + case Some(router) => + if(obj.Health > 0) { + Success( + DroppedItemData( + PlacementData(obj.Position, obj.Orientation), + TelepadDeployableData( + CommonFieldData( + obj.Faction, + bops = false, + alternate = false, + true, + None, + false, + None, + Some(router.guid), + obj.Owner.getOrElse(PlanetSideGUID(0)) + ), + unk1 = 87, + unk2 = 12 + ) + ) + ) + } + else { + Success( + DroppedItemData( + PlacementData(obj.Position, obj.Orientation), + TelepadDeployableData( + CommonFieldData( + obj.Faction, + bops = false, + alternate = true, + true, + None, + false, + None, + Some(router.guid), + PlanetSideGUID(0) + ), + unk1 = 0, + unk2 = 6 + ) + ) + ) + } + + case None => + Failure(new IllegalStateException("TelepadDeployableConverter: telepad needs to know id of its associated Router")) } } } diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/TerminalConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/TerminalConverter.scala index 440d8329..888c2e30 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/TerminalConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/TerminalConverter.scala @@ -2,10 +2,10 @@ package net.psforever.objects.definition.converter import net.psforever.objects.serverobject.terminals.Terminal -import net.psforever.packet.game.objectcreate.CommonTerminalData +import net.psforever.packet.game.objectcreate.CommonFieldData import scala.util.{Success, Try} class TerminalConverter extends ObjectCreateConverter[Terminal]() { - override def ConstructorData(obj : Terminal) : Try[CommonTerminalData] = { Success(CommonTerminalData(obj.Faction)) } + override def ConstructorData(obj : Terminal) : Try[CommonFieldData] = { Success(CommonFieldData(obj.Faction)(false)) } } diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/ToolConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/ToolConverter.scala index 5718ff16..a7886d44 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/ToolConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/ToolConverter.scala @@ -2,29 +2,57 @@ package net.psforever.objects.definition.converter import net.psforever.objects.Tool -import net.psforever.packet.game.objectcreate.{DetailedWeaponData, InternalSlot, WeaponData} +import net.psforever.packet.game.PlanetSideGUID +import net.psforever.packet.game.objectcreate.{CommonFieldData, DetailedWeaponData, InternalSlot, WeaponData} -import scala.collection.mutable.ListBuffer import scala.util.{Success, Try} class ToolConverter extends ObjectCreateConverter[Tool]() { override def ConstructorData(obj : Tool) : Try[WeaponData] = { - val maxSlot : Int = obj.MaxAmmoSlot - val slots : ListBuffer[InternalSlot] = ListBuffer[InternalSlot]() - (0 until maxSlot).foreach(index => { + val slots : List[InternalSlot] = (0 until obj.MaxAmmoSlot).map(index => { val box = obj.AmmoSlots(index).Box - slots += InternalSlot(box.Definition.ObjectId, box.GUID, index, box.Definition.Packet.ConstructorData(box).get) - }) - Success(WeaponData(4,8, obj.FireModeIndex, slots.toList)(maxSlot)) + InternalSlot(box.Definition.ObjectId, box.GUID, index, box.Definition.Packet.ConstructorData(box).get) + }).toList + Success( + WeaponData( + CommonFieldData( + obj.Faction, + bops = false, + alternate = false, + true, + None, + false, + None, + None, + PlanetSideGUID(0) + ), + obj.FireModeIndex, + slots + ) + ) } override def DetailedConstructorData(obj : Tool) : Try[DetailedWeaponData] = { - val maxSlot : Int = obj.MaxAmmoSlot - val slots : ListBuffer[InternalSlot] = ListBuffer[InternalSlot]() - (0 until maxSlot).foreach(index => { + val slots : List[InternalSlot] = (0 until obj.MaxAmmoSlot).map(index => { val box = obj.AmmoSlots(index).Box - slots += InternalSlot(box.Definition.ObjectId, box.GUID, index, box.Definition.Packet.DetailedConstructorData(box).get) - }) - Success(DetailedWeaponData(4,8, obj.FireModeIndex, slots.toList)(maxSlot)) + InternalSlot(box.Definition.ObjectId, box.GUID, index, box.Definition.Packet.DetailedConstructorData(box).get) + }).toList + Success( + DetailedWeaponData( + CommonFieldData( + obj.Faction, + bops = false, + alternate = false, + true, + None, + false, + None, + None, + PlanetSideGUID(0) + ), + obj.FireModeIndex, + slots + ) + ) } } diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/VehicleConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/VehicleConverter.scala index 0a11eba0..e0eb5461 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/VehicleConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/VehicleConverter.scala @@ -4,7 +4,7 @@ package net.psforever.objects.definition.converter import net.psforever.objects.equipment.Equipment import net.psforever.objects.Vehicle import net.psforever.packet.game.PlanetSideGUID -import net.psforever.packet.game.objectcreate.{InventoryData, InventoryItemData, ObjectClass, PlacementData, SpecificVehicleData, VehicleData, VehicleFormat} +import net.psforever.packet.game.objectcreate._ import net.psforever.types.DriveState import scala.util.{Failure, Success, Try} @@ -14,21 +14,25 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() { Failure(new Exception("VehicleConverter should not be used to generate detailed VehicleData (nothing should)")) override def ConstructorData(obj : Vehicle) : Try[VehicleData] = { - val health = 255 * obj.Health / obj.MaxHealth //TODO not precise + val health = StatConverter.Health(obj.Health, obj.MaxHealth) if(health > 0) { //active Success( VehicleData( PlacementData(obj.Position, obj.Orientation, obj.Velocity), - obj.Faction, - bops = false, - destroyed = false, - unk1 = 0, - obj.Jammered, - unk2 = false, - obj.Owner match { - case Some(owner) => owner - case None => PlanetSideGUID(0) - }, + CommonFieldData( + obj.Faction, + bops = false, + alternate = false, + v1 = false, + v2 = None, + v3 = false, + v4 = Some(false), + v5 = None, + obj.Owner match { + case Some(owner) => owner + case None => PlanetSideGUID(0) + } + ), unk3 = false, health, unk4 = false, @@ -46,13 +50,17 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() { Success( VehicleData( PlacementData(obj.Position, obj.Orientation), - obj.Faction, - bops = false, - destroyed = true, - unk1 = 0, - jammered = false, - unk2 = false, - owner_guid = PlanetSideGUID(0), + CommonFieldData( + obj.Faction, + bops = false, + alternate = true, + v1 = false, + v2 = None, + v3 = false, + v4 = Some(false), + v5 = None, + guid = PlanetSideGUID(0) + ), unk3 = false, health = 0, unk4 = false, @@ -80,7 +88,7 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() { private def MakeMountings(obj : Vehicle) : List[InventoryItemData.InventoryItem] = { obj.Weapons.map({ - case((index, slot)) => + case(index, slot) => val equip : Equipment = slot.Equipment.get val equipDef = equip.Definition InventoryItemData(equipDef.ObjectId, equip.GUID, index, equipDef.Packet.ConstructorData(equip).get) diff --git a/common/src/main/scala/net/psforever/objects/equipment/CItem.scala b/common/src/main/scala/net/psforever/objects/equipment/CItem.scala index 0989207a..eda138d3 100644 --- a/common/src/main/scala/net/psforever/objects/equipment/CItem.scala +++ b/common/src/main/scala/net/psforever/objects/equipment/CItem.scala @@ -1,6 +1,9 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.equipment +/** + * An `Enumeration` of all the construction tool objects in the game, paired with their object id as the `Value`. + */ object CItem extends Enumeration { final val ace = Value(32) final val advanced_ace = Value(39) //fdu diff --git a/common/src/main/scala/net/psforever/objects/equipment/Equipment.scala b/common/src/main/scala/net/psforever/objects/equipment/Equipment.scala index 54e67a70..13ccaa80 100644 --- a/common/src/main/scala/net/psforever/objects/equipment/Equipment.scala +++ b/common/src/main/scala/net/psforever/objects/equipment/Equipment.scala @@ -4,6 +4,8 @@ package net.psforever.objects.equipment import net.psforever.objects.PlanetSideGameObject import net.psforever.objects.definition.EquipmentDefinition import net.psforever.objects.inventory.InventoryTile +import net.psforever.objects.serverobject.affinity.FactionAffinity +import net.psforever.types.PlanetSideEmpire /** * `Equipment` is anything that can be: @@ -12,7 +14,17 @@ import net.psforever.objects.inventory.InventoryTile * and, special carried (like a lattice logic unit); * and, dropped on the ground in the game world and render where it was deposited. */ -abstract class Equipment extends PlanetSideGameObject { +abstract class Equipment extends PlanetSideGameObject + with FactionAffinity { + private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL + + def Faction : PlanetSideEmpire.Value = faction + + override def Faction_=(fact : PlanetSideEmpire.Value) : PlanetSideEmpire.Value = { + faction = fact + Faction + } + def Size : EquipmentSize.Value = Definition.Size def Tile : InventoryTile = Definition.Tile diff --git a/common/src/main/scala/net/psforever/objects/equipment/EquipmentSize.scala b/common/src/main/scala/net/psforever/objects/equipment/EquipmentSize.scala index 564dca62..fca75943 100644 --- a/common/src/main/scala/net/psforever/objects/equipment/EquipmentSize.scala +++ b/common/src/main/scala/net/psforever/objects/equipment/EquipmentSize.scala @@ -1,6 +1,10 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.equipment +/** + * An `Enumeration` of common equipment sizes in the game. + * Check the comments for originating use. + */ object EquipmentSize extends Enumeration { val Blocked, diff --git a/common/src/main/scala/net/psforever/objects/EquipmentSlot.scala b/common/src/main/scala/net/psforever/objects/equipment/EquipmentSlot.scala similarity index 94% rename from common/src/main/scala/net/psforever/objects/EquipmentSlot.scala rename to common/src/main/scala/net/psforever/objects/equipment/EquipmentSlot.scala index dd2d4ab6..57b678f3 100644 --- a/common/src/main/scala/net/psforever/objects/EquipmentSlot.scala +++ b/common/src/main/scala/net/psforever/objects/equipment/EquipmentSlot.scala @@ -1,7 +1,5 @@ // Copyright (c) 2017 PSForever -package net.psforever.objects - -import net.psforever.objects.equipment.{Equipment, EquipmentSize} +package net.psforever.objects.equipment /** * A size-checked unit of storage (or mounting) for `Equipment`. diff --git a/common/src/main/scala/net/psforever/objects/equipment/SItem.scala b/common/src/main/scala/net/psforever/objects/equipment/SItem.scala index 8aea0f85..d8890e7b 100644 --- a/common/src/main/scala/net/psforever/objects/equipment/SItem.scala +++ b/common/src/main/scala/net/psforever/objects/equipment/SItem.scala @@ -1,6 +1,9 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.equipment +/** + * An `Enumeration` of some activation-type `Equipment` in the game, paired with their object id as the `Value`. + */ object SItem extends Enumeration { final val boomer_trigger = Value(149) final val command_detonater = Value(213) //cud diff --git a/common/src/main/scala/net/psforever/objects/guid/GUIDTask.scala b/common/src/main/scala/net/psforever/objects/guid/GUIDTask.scala index dd104f5a..3443ad96 100644 --- a/common/src/main/scala/net/psforever/objects/guid/GUIDTask.scala +++ b/common/src/main/scala/net/psforever/objects/guid/GUIDTask.scala @@ -3,7 +3,7 @@ package net.psforever.objects.guid import akka.actor.ActorRef import net.psforever.objects.entity.IdentifiableEntity -import net.psforever.objects.equipment.Equipment +import net.psforever.objects.equipment.{Equipment, EquipmentSlot} import net.psforever.objects._ import net.psforever.objects.inventory.Container import net.psforever.objects.serverobject.turret.WeaponTurret diff --git a/common/src/main/scala/net/psforever/objects/inventory/Container.scala b/common/src/main/scala/net/psforever/objects/inventory/Container.scala index 72450076..a75261eb 100644 --- a/common/src/main/scala/net/psforever/objects/inventory/Container.scala +++ b/common/src/main/scala/net/psforever/objects/inventory/Container.scala @@ -1,8 +1,8 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.inventory -import net.psforever.objects.equipment.Equipment -import net.psforever.objects.{EquipmentSlot, OffhandEquipmentSlot} +import net.psforever.objects.equipment.{Equipment, EquipmentSlot} +import net.psforever.objects.OffhandEquipmentSlot import net.psforever.packet.game.PlanetSideGUID import scala.util.Try diff --git a/common/src/main/scala/net/psforever/objects/inventory/GridInventory.scala b/common/src/main/scala/net/psforever/objects/inventory/GridInventory.scala index a0694493..c7a5a28a 100644 --- a/common/src/main/scala/net/psforever/objects/inventory/GridInventory.scala +++ b/common/src/main/scala/net/psforever/objects/inventory/GridInventory.scala @@ -3,8 +3,7 @@ package net.psforever.objects.inventory import java.util.concurrent.atomic.AtomicInteger -import net.psforever.objects.equipment.Equipment -import net.psforever.objects.EquipmentSlot +import net.psforever.objects.equipment.{Equipment, EquipmentSlot} import net.psforever.packet.game.PlanetSideGUID import scala.annotation.tailrec diff --git a/common/src/main/scala/net/psforever/objects/loadouts/Loadout.scala b/common/src/main/scala/net/psforever/objects/loadouts/Loadout.scala index 5bcf4125..12e0cf41 100644 --- a/common/src/main/scala/net/psforever/objects/loadouts/Loadout.scala +++ b/common/src/main/scala/net/psforever/objects/loadouts/Loadout.scala @@ -3,7 +3,7 @@ package net.psforever.objects.loadouts import net.psforever.objects._ import net.psforever.objects.definition._ -import net.psforever.objects.equipment.Equipment +import net.psforever.objects.equipment.{Equipment, EquipmentSlot} import net.psforever.objects.inventory.InventoryItem import scala.annotation.tailrec diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/AirVehicleTerminalDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/AirVehicleTerminalDefinition.scala deleted file mode 100644 index f10f646d..00000000 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/AirVehicleTerminalDefinition.scala +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.objects.serverobject.terminals - -class AirVehicleTerminalDefinition extends VehicleTerminalDefinition(43) { - vehicles = flight1Vehicles - Name = "air_vehicle_terminal" -} diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/BFRTerminalDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/BFRTerminalDefinition.scala deleted file mode 100644 index 61b651b2..00000000 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/BFRTerminalDefinition.scala +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.objects.serverobject.terminals - -class BFRTerminalDefinition extends VehicleTerminalDefinition(143) { - vehicles = bfrVehicles - Name = "bfr_terminal" -} diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/CertTerminalDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/CertTerminalDefinition.scala index 1143b2d8..fe288791 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/CertTerminalDefinition.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/CertTerminalDefinition.scala @@ -1,22 +1,14 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.serverobject.terminals -import net.psforever.objects.Player -import net.psforever.packet.game.ItemTransactionMessage import net.psforever.types.CertificationType -/** - * The definition for any `Terminal` that is of a type "cert_terminal" (certification terminal). - * `Learn` and `Sell` `CertificationType` entries, gaining access to different `Equipment` and `Vehicles`. - */ -class CertTerminalDefinition extends TerminalDefinition(171) { - Name = "cert_terminal" - +object CertTerminalDefinition { /** * The certifications available. * All entries are listed on page (tab) number 0. */ - private val certificationList : Map[String, CertificationType.Value] = Map( + val certs : Map[String, CertificationType.Value] = Map( "medium_assault" -> CertificationType.MediumAssault, "reinforced_armor" -> CertificationType.ReinforcedExoSuit, "quad_all" -> CertificationType.ATV, @@ -59,34 +51,4 @@ class CertTerminalDefinition extends TerminalDefinition(171) { "advanced_medical" -> CertificationType.AdvancedMedical //TODO bfr certification entries ) - - /** - * Process a `TransactionType.Learn` action by the user. - * @param player the player - * @param msg the original packet carrying the request - * @return an actionable message that explains how to process the request - */ - def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { //Learn - certificationList.get(msg.item_name) match { - case Some(cert) => - Terminal.LearnCertification(cert) - case None => - Terminal.NoDeal() - } - } - - /** - * Process a `TransactionType.Sell` action by the user. - * @param player the player - * @param msg the original packet carrying the request - * @return an actionable message that explains how to process the request - */ - override def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { - certificationList.get(msg.item_name) match { - case Some(cert) => - Terminal.SellCertification(cert) - case None => - Terminal.NoDeal() - } - } } diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/DropshipVehicleTerminalDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/DropshipVehicleTerminalDefinition.scala deleted file mode 100644 index 02b56027..00000000 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/DropshipVehicleTerminalDefinition.scala +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.objects.serverobject.terminals - -class DropshipVehicleTerminalDefinition extends VehicleTerminalDefinition(263) { - vehicles = flight1Vehicles ++ flight2Vehicles - Name = "dropship_vehicle_terminal" -} diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/EquipmentTerminalDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/EquipmentTerminalDefinition.scala index 91500a70..2f1d56c7 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/EquipmentTerminalDefinition.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/EquipmentTerminalDefinition.scala @@ -10,24 +10,6 @@ import net.psforever.types.ExoSuitType import scala.annotation.switch -abstract class EquipmentTerminalDefinition(objId : Int) extends TerminalDefinition(objId) { - Name = "equipment_terminal" - - /** - * Process a `TransactionType.Sell` action by the user. - * There is no specific tab associated with this action. - * It is a common button on the terminal interface window. - * Additionally, the equipment to be sold ia almost always in the player's `FreeHand` slot. - * Selling `Equipment` is always permitted. - * @param player the player - * @param msg the original packet carrying the request - * @return an actionable message that explains how to process the request - */ - override def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { - Terminal.SellEquipment() - } -} - object EquipmentTerminalDefinition { private[this] val log = org.log4s.getLogger("TerminalDefinition") diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/GroundVehicleTerminalDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/GroundVehicleTerminalDefinition.scala deleted file mode 100644 index aa61fba1..00000000 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/GroundVehicleTerminalDefinition.scala +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.objects.serverobject.terminals - -class GroundVehicleTerminalDefinition extends VehicleTerminalDefinition(386) { - vehicles = groundVehicles - Name = "ground_vehicle_terminal" -} diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/ImplantTerminalDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/ImplantTerminalDefinition.scala new file mode 100644 index 00000000..3efe5dd6 --- /dev/null +++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/ImplantTerminalDefinition.scala @@ -0,0 +1,27 @@ +// Copyright (c) 2017 PSForever +package net.psforever.objects.serverobject.terminals + +import net.psforever.objects.GlobalDefinitions +import net.psforever.objects.definition.ImplantDefinition + +/** + * Data for the `Definition` for any `Terminal` that is of a type "implant_terminal_interface." + * Implant terminals are composed of two components. + * This `Definition` constructs the invisible interface component (interacted with as a game window). + * Unlike other `Terminal` objects in the game, this one must be constructed on the client and + * attached as a child of the visible implant terminal component - the "implant_terminal_mech." + */ +object ImplantTerminalDefinition { + val implants : Map[String, ImplantDefinition] = Map ( + "advanced_regen" -> GlobalDefinitions.advanced_regen, + "targeting" -> GlobalDefinitions.targeting, + "audio_amplifier" -> GlobalDefinitions.audio_amplifier, + "darklight_vision" -> GlobalDefinitions.darklight_vision, + "melee_booster" -> GlobalDefinitions.melee_booster, + "personal_shield" -> GlobalDefinitions.personal_shield, + "range_magnifier" -> GlobalDefinitions.range_magnifier, + "second_wind" -> GlobalDefinitions.second_wind, + "silent_run" -> GlobalDefinitions.silent_run, + "surge" -> GlobalDefinitions.surge + ) +} diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/ImplantTerminalInterfaceDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/ImplantTerminalInterfaceDefinition.scala deleted file mode 100644 index 51c62e4e..00000000 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/ImplantTerminalInterfaceDefinition.scala +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.objects.serverobject.terminals - -import net.psforever.objects.{GlobalDefinitions, Player} -import net.psforever.objects.definition.ImplantDefinition -import net.psforever.objects.definition.converter.ImplantTerminalInterfaceConverter -import net.psforever.packet.game.ItemTransactionMessage -import net.psforever.packet.game.objectcreate.ObjectClass - -/** - * The `Definition` for any `Terminal` that is of a type "implant_terminal_interface." - * Implant terminals are composed of two components. - * This `Definition` constructs the invisible interface component (interacted with as a game window). - * Unlike other `Terminal` objects in the game, this one must be constructed on the client and - * attached as a child of the visible implant terminal component - the "implant_terminal_mech." - */ -class ImplantTerminalInterfaceDefinition extends TerminalDefinition(ObjectClass.implant_terminal_interface) { - Packet = new ImplantTerminalInterfaceConverter - Name = "implant_terminal_interface" - - private val implants : Map[String, ImplantDefinition] = Map ( - "advanced_regen" -> GlobalDefinitions.advanced_regen, - "targeting" -> GlobalDefinitions.targeting, - "audio_amplifier" -> GlobalDefinitions.audio_amplifier, - "darklight_vision" -> GlobalDefinitions.darklight_vision, - "melee_booster" -> GlobalDefinitions.melee_booster, - "personal_shield" -> GlobalDefinitions.personal_shield, - "range_magnifier" -> GlobalDefinitions.range_magnifier, - "second_wind" -> GlobalDefinitions.second_wind, - "silent_run" -> GlobalDefinitions.silent_run, - "surge" -> GlobalDefinitions.surge - ) - - def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { - implants.get(msg.item_name) match { - case Some(implant) => - Terminal.LearnImplant(implant) - case None => - Terminal.NoDeal() - } - } - - override def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { - implants.get(msg.item_name) match { - case Some(implant) => - Terminal.SellImplant(implant) - case None => - Terminal.NoDeal() - } - } -} diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/MatrixTerminalDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/MatrixTerminalDefinition.scala index 292e30b2..a669de7f 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/MatrixTerminalDefinition.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/MatrixTerminalDefinition.scala @@ -4,29 +4,19 @@ package net.psforever.objects.serverobject.terminals import akka.actor.ActorContext import net.psforever.objects.Player import net.psforever.objects.serverobject.structures.Amenity -import net.psforever.packet.game.ItemTransactionMessage /** * The definition for any `Terminal` that is of a type "matrix_terminal". + * Matrix terminal objects are used to create anchor points in the game environment + * in reference to a working set of spawn points attached to a `Building` object or `Vehicle` object + * depending on the spawn group. + * @see `SpawnTube` + * @see `Zone.CreateSpawnGroups` + * @see `Zone.SpawnGroups` + * @param objectId the object's identifier number */ -class MatrixTerminalDefinition(object_id : Int) extends TerminalDefinition(object_id) { - Name = if(object_id == 517) { - "matrix_terminala" - } - else if(object_id == 518) { - "matrix_terminalb" - } - else if(object_id == 519) { - "matrix_terminalc" - } - else if(object_id == 812) { - "spawn_terminal" - } - else { - throw new IllegalArgumentException("terminal must be object id 517-519 or 812") - } - - override def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal() +class MatrixTerminalDefinition(objectId : Int) extends TerminalDefinition(objectId) { + def Request(player : Player, msg : Any) : Terminal.Exchange = Terminal.NoDeal() } object MatrixTerminalDefinition { diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/MedicalTerminalDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/MedicalTerminalDefinition.scala index a1b26e03..29386a79 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/MedicalTerminalDefinition.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/MedicalTerminalDefinition.scala @@ -1,6 +1,8 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.serverobject.terminals +import net.psforever.objects.Player + import scala.concurrent.duration.{Duration, FiniteDuration} /** @@ -8,7 +10,7 @@ import scala.concurrent.duration.{Duration, FiniteDuration} * This includes the functionality of the formal medical terminals and some of the cavern crystals. * Do not confuse the game's internal "medical_terminal" object category and the actual `medical_terminal` object (529). */ -class MedicalTerminalDefinition(objectId : Int) extends TerminalDefinition(objectId) with ProximityDefinition { +class MedicalTerminalDefinition(objectId : Int) extends ProximityTerminalDefinition(objectId) { private var interval : FiniteDuration = Duration(0, "seconds") private var healAmount : Int = 0 private var armorAmount : Int = 0 @@ -37,4 +39,6 @@ class MedicalTerminalDefinition(objectId : Int) extends TerminalDefinition(objec armorAmount = amount ArmorAmount } + + override def Request(player : Player, msg : Any) : Terminal.Exchange = Terminal.NoDeal() } diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/OrderTerminalABDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/OrderTerminalABDefinition.scala deleted file mode 100644 index c90aca31..00000000 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/OrderTerminalABDefinition.scala +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.objects.serverobject.terminals - -import akka.actor.ActorContext -import net.psforever.objects.Player -import net.psforever.objects.loadouts.InfantryLoadout -import net.psforever.objects.inventory.InventoryItem -import net.psforever.objects.serverobject.structures.Amenity -import net.psforever.packet.game.ItemTransactionMessage -import net.psforever.objects.serverobject.terminals.EquipmentTerminalDefinition._ -import net.psforever.types.ExoSuitType - -/** - * The definition for any `Terminal` that is of a type "ams_order_terminal". - * As the name indicates, paired on the flanks of an advanced mobile spawn vehicle.
- *
- * `Buy` and `Sell` `Equipment` items and `AmmoBox` items. - * Change `ExoSuitType` and retrieve `Loadout` entries. - * Changing into mechanized assault exo-suits (MAXes) is not permitted. - */ -class OrderTerminalABDefinition(object_id : Int) extends EquipmentTerminalDefinition(object_id) { - if(object_id == 613) { - Name = "order_terminala" - } - else if(object_id == 614) { - Name = "order_terminalb" - } - else { - throw new IllegalArgumentException("terminal must be either object id 613 or object id 614") - } - - /** - * The `Equipment` available from this `Terminal` on specific pages. - */ - private val buyFunc : (Player, ItemTransactionMessage)=>Terminal.Exchange = - EquipmentTerminalDefinition.Buy( - infantryAmmunition ++ infantryWeapons, - supportAmmunition ++ supportWeapons, - suits - ) - - override def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = buyFunc(player, msg) - - /** - * Process a `TransactionType.Loadout` action by the user. - * `Loadout` objects are blueprints composed of exo-suit specifications and simplified `Equipment`-to-slot mappings. - * If a valid loadout is found, its data is transformed back into actual `Equipment` for return to the user. - * Loadouts that would suit the player into a mechanized assault exo-suit are not permitted. - * @param player the player - * @param msg the original packet carrying the request - * @return an actionable message that explains how to process the request - */ - override def Loadout(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { - if(msg.item_page == 4) { //Favorites tab - player.LoadLoadout(msg.unk1) match { - case Some(loadout : InfantryLoadout) => - if(loadout.exosuit != ExoSuitType.MAX) { - val holsters = loadout.visible_slots.map(entry => { InventoryItem(BuildSimplifiedPattern(entry.item), entry.index) }) - val inventory = loadout.inventory.map(entry => { InventoryItem(BuildSimplifiedPattern(entry.item), entry.index) }) - Terminal.InfantryLoadout(loadout.exosuit, loadout.subtype, holsters, inventory) - } - else { - Terminal.NoDeal() - } - case Some(_) | None => - Terminal.NoDeal() - } - } - else { - Terminal.NoDeal() - } - } -} - -object OrderTerminalABDefinition { - /** - * Assemble some logic for a provided object. - * @param obj an `Amenity` object; - * anticipating a `Terminal` object using this same definition - * @param context hook to the local `Actor` system - */ - def Setup(obj : Amenity, context : ActorContext) : Unit = { - import akka.actor.{ActorRef, Props} - if(obj.Actor == ActorRef.noSender) { - obj.Actor = context.actorOf(Props(classOf[TerminalControl], obj), s"${obj.Definition.Name}_${obj.GUID.guid}") - } - } -} diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/OrderTerminalDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/OrderTerminalDefinition.scala index 9182d3b0..a53cb97e 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/OrderTerminalDefinition.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/OrderTerminalDefinition.scala @@ -10,61 +10,39 @@ import net.psforever.objects.inventory.InventoryItem import net.psforever.objects.serverobject.structures.Amenity import net.psforever.packet.game.ItemTransactionMessage import net.psforever.objects.serverobject.terminals.EquipmentTerminalDefinition._ -import net.psforever.types.{CertificationType, ExoSuitType} +import net.psforever.types.{CertificationType, ExoSuitType, TransactionType} import scala.collection.mutable /** - * The definition for any `Terminal` that is of a type "order_terminal". - * This kind of "order_terminal" is applicable to facilities.
+ * The definition for any `Terminal` from which specifications can be altered. + * These specification alternations involve three classifications: + * the exchange of denominations of in-game hardware, i.e., `Equipment`, + * the modification of lists of personal statistics, e.g., `Certifications`, + * and saving and loading of preset configurations, i.e., `Loadouts`. + * This hardware is organized as "stock," occasionally supplemented. + * Terminals have tabs (visually) that are organized by different stock (internally) + * that determines the behavior available from that tab + * and what stock can be drawn or returned.
*
- * `Buy` and `Sell` `Equipment` items and `AmmoBox` items. - * Change `ExoSuitType` and retrieve `Loadout` entries. + * Equipment terminals are the property of bases and vehicles ("amenities"). + * To bases, the `Terminal` object is coupled loosely and may be allowed to diverge. + * To vehicles, the `Terminal` object is coupled directly to the faction affiliation of the vehicle. + * @see `Amenity` + * @see `Terminal` + * @see `Utility` */ -class OrderTerminalDefinition extends EquipmentTerminalDefinition(612) { - Name = "order_terminal" +class OrderTerminalDefinition(objId : Int) extends TerminalDefinition(objId) { + /** An internal object organizing the different specification options found on a terminal's UI. */ + private val tabs : mutable.HashMap[Int, OrderTerminalDefinition.Tab] = + new mutable.HashMap[Int, OrderTerminalDefinition.Tab]() + /** Disconnect the ability to return stock back to the terminal + * from the type of stock available from the terminal in general + * or the type of stock available from its denoted page. + * Will always return a message of type `SellEquipment`.*/ + private var sellEquipmentDefault : Boolean = false - /** - * The `Equipment` available from this `Terminal` on specific pages. - */ - private val buyFunc : (Player, ItemTransactionMessage)=>Terminal.Exchange = EquipmentTerminalDefinition.Buy( - infantryAmmunition ++ infantryWeapons, - supportAmmunition ++ supportWeapons, - suits ++ maxSuits) - - override def Buy(player: Player, msg : ItemTransactionMessage) : Terminal.Exchange = buyFunc(player, msg) - - /** - * Process a `TransactionType.Loadout` action by the user. - * `Loadout` objects are blueprints composed of exo-suit specifications and simplified `Equipment`-to-slot mappings. - * If a valid loadout is found, its data is transformed back into actual `Equipment` for return to the user. - * @param player the player - * @param msg the original packet carrying the request - * @return an actionable message that explains how to process the request - */ - override def Loadout(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { - if(msg.item_page == 4) { //Favorites tab - player.LoadLoadout(msg.unk1) match { - case Some(loadout : InfantryLoadout) => - val holsters = loadout.visible_slots.map(entry => { InventoryItem(BuildSimplifiedPattern(entry.item), entry.index) }) - val inventory = loadout.inventory.map(entry => { InventoryItem(BuildSimplifiedPattern(entry.item), entry.index) }) - Terminal.InfantryLoadout(loadout.exosuit, loadout.subtype, holsters, inventory) - case Some(_) | None => - Terminal.NoDeal() - } - } - else { - Terminal.NoDeal() - } - } -} - -class _OrderTerminalDefinition(objId : Int) extends TerminalDefinition(objId) { - private val pages : mutable.HashMap[Int, _OrderTerminalDefinition.PageDefinition] = - new mutable.HashMap[Int, _OrderTerminalDefinition.PageDefinition]() - private var sellEquipmentDefault : Boolean = true - - def Page : mutable.HashMap[Int, _OrderTerminalDefinition.PageDefinition] = pages + def Tab : mutable.HashMap[Int, OrderTerminalDefinition.Tab] = tabs def SellEquipmentByDefault : Boolean = sellEquipmentDefault @@ -73,8 +51,24 @@ class _OrderTerminalDefinition(objId : Int) extends TerminalDefinition(objId) { SellEquipmentByDefault } - override def Buy(player: Player, msg : ItemTransactionMessage) : Terminal.Exchange = { - pages.get(msg.item_page) match { + def Request(player : Player, msg : Any) : Terminal.Exchange = msg match { + case message : ItemTransactionMessage => + message.transaction_type match { + case TransactionType.Buy | TransactionType.Learn => + Buy(player, message) + case TransactionType.Loadout => + Loadout(player, message) + case TransactionType.Sell => + Sell(player, message) + case _ => + Terminal.NoDeal() + } + case _ => + Terminal.NoDeal() + } + + private def Buy(player: Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + tabs.get(msg.item_page) match { case Some(page) => page.Buy(player, msg) case _ => @@ -82,14 +76,14 @@ class _OrderTerminalDefinition(objId : Int) extends TerminalDefinition(objId) { } } - override def Loadout(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Buy(player, msg) + private def Loadout(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Buy(player, msg) - override def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + private def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { if(sellEquipmentDefault) { Terminal.SellEquipment() } else { - pages.get(msg.item_page) match { + tabs.get(msg.item_page) match { case Some(page) => page.Sell(player, msg) case _ => @@ -99,14 +93,24 @@ class _OrderTerminalDefinition(objId : Int) extends TerminalDefinition(objId) { } } -object _OrderTerminalDefinition { - abstract class PageDefinition(stock : Map[String, Any]) { - def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange - def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange +object OrderTerminalDefinition { + /** + * A basic tab outlining the specific type of stock available from this part of the terminal's interface. + * @see `ItemTransactionMessage` + */ + sealed trait Tab { + def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal() + def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal() } - final case class ArmorPage(stock : Map[String, (ExoSuitType.Value, Int)]) extends PageDefinition(stock) { - def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + /** + * The tab used to select an exo-suit to be worn by the player. + * @see `ExoSuitType` + * @param stock the key is always a `String` value as defined from `ItemTransationMessage` data; + * the value is a tuple composed of an `ExoSuitType` value and a subtype value + */ + final case class ArmorPage(stock : Map[String, (ExoSuitType.Value, Int)]) extends Tab { + override def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { stock.get(msg.item_name) match { case Some((suit : ExoSuitType.Value, subtype : Int)) => Terminal.BuyExosuit(suit, subtype) @@ -114,12 +118,42 @@ object _OrderTerminalDefinition { Terminal.NoDeal() } } - - def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal() } - final case class CertificationPage(stock : Map[String, CertificationType.Value]) extends PageDefinition(stock) { - def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + /** + * An expanded form of the tab used to select an exo-suit to be worn by the player that also provides some equipment. + * @see `ExoSuitType` + * @see `Equipment` + * @param stock the key is always a `String` value as defined from `ItemTransationMessage` data; + * the value is a tuple composed of an `ExoSuitType` value and a subtype value + * @param items the key is always a `String` value as defined from `ItemTransationMessage` data; + * the value is a curried function that produces an `Equipment` object + */ + final case class ArmorWithAmmoPage(stock : Map[String, (ExoSuitType.Value, Int)], items : Map[String, ()=>Equipment]) extends Tab { + override def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + stock.get(msg.item_name) match { + case Some((suit : ExoSuitType.Value, subtype : Int)) => + Terminal.BuyExosuit(suit, subtype) + case _ => + items.get(msg.item_name) match { + case Some(item : (()=>Equipment)) => + Terminal.BuyEquipment(item()) + case _ => + Terminal.NoDeal() + } + } + } + } + + /** + * The tab used to select a certification to be utilized by the player. + * Only certifications may be returned to the interface defined by this page. + * @see `CertificationType` + * @param stock the key is always a `String` value as defined from `ItemTransationMessage` data; + * the value is a `CertificationType` value + */ + final case class CertificationPage(stock : Map[String, CertificationType.Value]) extends Tab { + override def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { stock.get(msg.item_name) match { case Some(cert : CertificationType.Value) => Terminal.LearnCertification(cert) @@ -128,7 +162,7 @@ object _OrderTerminalDefinition { } } - def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + override def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { stock.get(msg.item_name) match { case Some(cert : CertificationType.Value) => Terminal.SellCertification(cert) @@ -138,8 +172,13 @@ object _OrderTerminalDefinition { } } - final case class EquipmentPage(stock : Map[String, ()=>Equipment]) extends PageDefinition(stock) { - def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + /** + * The tab used to produce an `Equipment` object to be used by the player. + * @param stock the key is always a `String` value as defined from `ItemTransationMessage` data; + * the value is a curried function that produces an `Equipment` object + */ + final case class EquipmentPage(stock : Map[String, ()=>Equipment]) extends Tab { + override def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { stock.get(msg.item_name) match { case Some(item : (()=>Equipment)) => Terminal.BuyEquipment(item()) @@ -147,12 +186,18 @@ object _OrderTerminalDefinition { Terminal.NoDeal() } } - - def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.SellEquipment() } - final case class ImplantPage(stock : Map[String, ImplantDefinition]) extends PageDefinition(stock) { - def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + /** + * The tab used to select an implant to be utilized by the player. + * A maximum of three implants can be obtained by any player at a time depending on the player's battle rank. + * Only implants may be returned to the interface defined by this page. + * @see `ImplantDefinition` + * @param stock the key is always a `String` value as defined from `ItemTransationMessage` data; + * the value is a `CertificationType` value + */ + final case class ImplantPage(stock : Map[String, ImplantDefinition]) extends Tab { + override def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { stock.get(msg.item_name) match { case Some(implant : ImplantDefinition) => Terminal.LearnImplant(implant) @@ -161,7 +206,7 @@ object _OrderTerminalDefinition { } } - def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + override def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { stock.get(msg.item_name) match { case Some(implant : ImplantDefinition) => Terminal.SellImplant(implant) @@ -171,8 +216,19 @@ object _OrderTerminalDefinition { } } - final case class InfantryLoadoutPage() extends PageDefinition(Map.empty) { - def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + /** + * The tab used to select which custom loadout the player is using. + * Player loadouts are defined by an exo-suit to be worn by the player + * and equipment in the holsters and the inventory. + * In this case, the reference to the player that is a parameter of the functions maintains information about the loadouts; + * no extra information specific to this page is necessary. + * @see `ExoSuitType` + * @see `Equipment` + * @see `InfantryLoadout` + * @see `Loadout` + */ + final case class InfantryLoadoutPage() extends Tab { + override def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { player.LoadLoadout(msg.unk1) match { case Some(loadout : InfantryLoadout) => val holsters = loadout.visible_slots.map(entry => { InventoryItem(BuildSimplifiedPattern(entry.item), entry.index) }) @@ -182,12 +238,20 @@ object _OrderTerminalDefinition { Terminal.NoDeal() } } - - def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal() } - final case class VehicleLoadoutPage() extends PageDefinition(Map.empty) { - def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + /** + * The tab used to select which custom loadout the player's vehicle is using. + * Vehicle loadouts are defined by a (superfluous) redefinition of the vehicle's mounted weapons + * and equipment in the trunk. + * In this case, the reference to the player that is a parameter of the functions maintains information about the loadouts; + * no extra information specific to this page is necessary. + * @see `Equipment` + * @see `Loadout` + * @see `VehicleLoadout` + */ + final case class VehicleLoadoutPage() extends Tab { + override def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { player.LoadLoadout(msg.unk1 + 10) match { case Some(loadout : VehicleLoadout) => val weapons = loadout.visible_slots.map(entry => { InventoryItem(BuildSimplifiedPattern(entry.item), entry.index) }) @@ -197,13 +261,21 @@ object _OrderTerminalDefinition { Terminal.NoDeal() } } - - def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal() } + /** + * The tab used to select a vehicle to be spawned for the player. + * Vehicle loadouts are defined by a superfluous redefinition of the vehicle's mounted weapons + * and equipment in the trunk + * for the purpose of establishing default contents. + * @see `Equipment` + * @see `Loadout` + * @see `Vehicle` + * @see `VehicleLoadout` + */ import net.psforever.objects.loadouts.{Loadout => Contents} //distinguish from Terminal.Loadout message - final case class VehiclePage(stock : Map[String, ()=>Vehicle], trunk : Map[String, Contents]) extends PageDefinition(stock) { - def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + final case class VehiclePage(stock : Map[String, ()=>Vehicle], trunk : Map[String, Contents]) extends Tab { + override def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { stock.get(msg.item_name) match { case Some(vehicle) => val (weapons, inventory) = trunk.get(msg.item_name) match { @@ -220,8 +292,6 @@ object _OrderTerminalDefinition { Terminal.NoDeal() } } - - def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal() } /** diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityDefinition.scala index 5aa814d3..575d6e55 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityDefinition.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityDefinition.scala @@ -1,20 +1,23 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.serverobject.terminals -import net.psforever.objects.{PlanetSideGameObject, Player} -import net.psforever.packet.game.ItemTransactionMessage +import net.psforever.objects.PlanetSideGameObject +import net.psforever.objects.definition.ObjectDefinition import scala.collection.mutable /** - * The definition for any `Terminal` that possesses a proximity-based effect. + * The definition mix-in for any game object that possesses a proximity-based effect. * This includes the limited proximity-based functionality of the formal medical terminals * and the actual proximity-based functionality of the cavern crystals. - * Objects created by this definition being linked by their use of `ProximityTerminalUseMessage`. + * Objects created by this definition being linked by their communication + * between the server and client using `ProximityTerminalUseMessage` game packets. */ trait ProximityDefinition { + this : ObjectDefinition => + private var useRadius : Float = 0f //TODO belongs on a wider range of object definitions - private val targetValidation : mutable.HashMap[ProximityTarget.Value, (PlanetSideGameObject)=>Boolean] = new mutable.HashMap[ProximityTarget.Value, (PlanetSideGameObject)=>Boolean]() + private val targetValidation : mutable.HashMap[ProximityTarget.Value, PlanetSideGameObject=>Boolean] = new mutable.HashMap[ProximityTarget.Value, PlanetSideGameObject=>Boolean]() def UseRadius : Float = useRadius @@ -23,9 +26,9 @@ trait ProximityDefinition { UseRadius } - def TargetValidation : mutable.HashMap[ProximityTarget.Value, (PlanetSideGameObject)=>Boolean] = targetValidation + def TargetValidation : mutable.HashMap[ProximityTarget.Value, PlanetSideGameObject=>Boolean] = targetValidation - def Validations : Seq[(PlanetSideGameObject)=>Boolean] = { + def Validations : Seq[PlanetSideGameObject=>Boolean] = { targetValidation.headOption match { case Some(_) => targetValidation.values.toSeq @@ -33,10 +36,8 @@ trait ProximityDefinition { Seq(ProximityDefinition.Invalid) } } - - def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal() } object ProximityDefinition { - protected val Invalid : (PlanetSideGameObject=>Boolean) = (_ : PlanetSideGameObject) => false + protected val Invalid : PlanetSideGameObject=>Boolean = (_ : PlanetSideGameObject) => false } diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminal.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminal.scala index c34cbc11..0114c329 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminal.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminal.scala @@ -1,6 +1,8 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.serverobject.terminals +import net.psforever.objects.Player +import net.psforever.objects.serverobject.CommonMessages import net.psforever.objects.serverobject.structures.Amenity import net.psforever.types.Vector3 import services.Service @@ -13,14 +15,23 @@ import services.Service * For example, the cavern crystals are considered owner-neutral elements that are not attached to a `Building` object. * @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields */ -class ProximityTerminal(tdef : TerminalDefinition with ProximityDefinition) extends Terminal(tdef) with ProximityUnit +class ProximityTerminal(tdef : ProximityTerminalDefinition) extends Terminal(tdef) with ProximityUnit { + override def Request(player : Player, msg : Any) : Terminal.Exchange = { + msg match { + case message : CommonMessages.Use => + Actor ! message + case _ => + } + Terminal.NoDeal() + } +} object ProximityTerminal { /** * Overloaded constructor. * @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields */ - def apply(tdef : TerminalDefinition with ProximityDefinition) : ProximityTerminal = { + def apply(tdef : ProximityTerminalDefinition) : ProximityTerminal = { new ProximityTerminal(tdef) } @@ -33,7 +44,7 @@ object ProximityTerminal { * @param context a context to allow the object to properly set up `ActorSystem` functionality * @return the `Terminal` object */ - def Constructor(tdef : TerminalDefinition with ProximityDefinition)(id : Int, context : ActorContext) : Terminal = { + def Constructor(tdef : ProximityTerminalDefinition)(id : Int, context : ActorContext) : Terminal = { import akka.actor.Props val obj = ProximityTerminal(tdef) obj.Actor = context.actorOf(Props(classOf[ProximityTerminalControl], obj), s"${tdef.Name}_$id") @@ -42,12 +53,13 @@ object ProximityTerminal { /** * Instantiate an configure a `Terminal` object, with position coordinates. - * @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields - * @param id the unique id that will be assigned to this entity + * @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields + * @param pos the location of the object + * @param id the unique id that will be assigned to this entity * @param context a context to allow the object to properly set up `ActorSystem` functionality * @return the `Terminal` object */ - def Constructor(tdef : TerminalDefinition with ProximityDefinition, pos : Vector3)(id : Int, context : ActorContext) : Terminal = { + def Constructor(tdef : ProximityTerminalDefinition, pos : Vector3)(id : Int, context : ActorContext) : Terminal = { import akka.actor.Props val obj = ProximityTerminal(tdef) obj.Position = pos diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalDefinition.scala new file mode 100644 index 00000000..ce0c5a15 --- /dev/null +++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalDefinition.scala @@ -0,0 +1,13 @@ +// Copyright (c) 2019 PSForever +package net.psforever.objects.serverobject.terminals + +import net.psforever.objects.Player + +/** + *The definition for any `Terminal` that can be accessed for amenities and services, + * triggered when a certain distance from the unit itself (proximity-based). + * @param objectId the object's identifier number + */ +class ProximityTerminalDefinition(objectId : Int) extends TerminalDefinition(objectId) with ProximityDefinition { + def Request(player : Player, msg : Any) : Terminal.Exchange = Terminal.NoDeal() +} diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/TeleportPadTerminalDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/TeleportPadTerminalDefinition.scala deleted file mode 100644 index 4dd9872e..00000000 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/TeleportPadTerminalDefinition.scala +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.objects.serverobject.terminals - -import akka.actor.ActorContext -import net.psforever.objects.Player -import net.psforever.objects.serverobject.structures.Amenity -import net.psforever.packet.game.ItemTransactionMessage - -class TeleportPadTerminalDefinition extends EquipmentTerminalDefinition(853) { - Name = "teleport_pad_terminal" - - def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { - Terminal.BuyEquipment(EquipmentTerminalDefinition.routerTerminal("router_telepad")()) - } -} - -object TeleportPadTerminalDefinition { - /** - * Assemble some logic for a provided object. - * @param obj an `Amenity` object; - * anticipating a `Terminal` object using this same definition - * @param context hook to the local `Actor` system - */ - def Setup(obj : Amenity, context : ActorContext) : Unit = { - import akka.actor.{ActorRef, Props} - if(obj.Actor == ActorRef.noSender) { - obj.Actor = context.actorOf(Props(classOf[TerminalControl], obj), s"${obj.Definition.Name}_${obj.GUID.guid}") - } - } -} diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/Terminal.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/Terminal.scala index 387660a0..a75df70d 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/Terminal.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/Terminal.scala @@ -6,10 +6,14 @@ import net.psforever.objects.definition.VehicleDefinition import net.psforever.objects.serverobject.hackable.Hackable import net.psforever.objects.serverobject.structures.Amenity import net.psforever.packet.game.{ItemTransactionMessage, TriggeredSound} -import net.psforever.types.TransactionType /** - * A structure-owned server object that is a "terminal" that can be accessed for amenities and services. + * A server object that can be accessed for services and other amenities. + * Terminals are owned by both `Structure` objects and by `Vehicle` objects + * and generally conform to the faction affiliation of the owner. + * Some `Structure`-owned terminals may be compromised + * to extend functionality to other's not of faction affiliation for a short time + * while `Vehicle`-owned terminals may not. * @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields */ class Terminal(tdef : TerminalDefinition) extends Amenity with Hackable { @@ -31,44 +35,23 @@ class Terminal(tdef : TerminalDefinition) extends Amenity with Hackable { } /** - * Process some `TransactionType` action requested by the user. + * Process a message (a "request") dispatched by the user. + * To be accessible, the terminal must be owned by the same faction by the user or must be compromised. + * @see `FactionAffinity` + * @see `PlanetSideEmpire` * @param player the player * @param msg the original packet carrying the request * @return an actionable message that explains what resulted from interacting with this `Terminal` */ - def Request(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + def Request(player : Player, msg : Any) : Terminal.Exchange = { if(Faction == player.Faction || HackedBy.isDefined) { - msg.transaction_type match { - case TransactionType.Buy | TransactionType.Learn => - Buy(player, msg) - - case TransactionType.Sell => - Sell(player, msg) - - case TransactionType.Loadout => - Loadout(player, msg) - - case _ => - Terminal.NoDeal() - } + tdef.Request(player, msg) } else { Terminal.NoDeal() } } - def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { - tdef.Buy(player, msg) - } - - def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { - tdef.Sell(player, msg) - } - - def Loadout(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { - tdef.Loadout(player, msg) - } - def Definition : TerminalDefinition = tdef } diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/TerminalDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/TerminalDefinition.scala index 562c6c91..5659e367 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/TerminalDefinition.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/TerminalDefinition.scala @@ -3,10 +3,9 @@ package net.psforever.objects.serverobject.terminals import net.psforever.objects.Player import net.psforever.objects.definition.converter.TerminalConverter -import net.psforever.packet.game.ItemTransactionMessage /** - * The basic definition for any `Terminal`. + * The basic definition for any `Terminal` object. * @param objectId the object's identifier number */ abstract class TerminalDefinition(objectId : Int) extends net.psforever.objects.definition.ObjectDefinition(objectId) { @@ -14,17 +13,12 @@ abstract class TerminalDefinition(objectId : Int) extends net.psforever.objects. Packet = new TerminalConverter /** - * The unimplemented functionality for this `Terminal`'s `TransactionType.Buy` and `TransactionType.Learn` activity. + * The unimplemented functionality for the entry function of form of activity + * processed by this terminal and codified by the input message (a "request"). + * @see `Terminal.Exchange` + * @param player the player who made the request + * @param msg the request message + * @return a message that resolves the transaction */ - def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange - - /** - * The unimplemented functionality for this `Terminal`'s `TransactionType.Sell` activity. - */ - def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal() - - /** - * The unimplemented functionality for this `Terminal`'s `TransactionType.Loadout` activity. - */ - def Loadout(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal() + def Request(player : Player, msg : Any) : Terminal.Exchange } diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/VehicleTerminalCombinedDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/VehicleTerminalCombinedDefinition.scala deleted file mode 100644 index bcbc35b3..00000000 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/VehicleTerminalCombinedDefinition.scala +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.objects.serverobject.terminals - -class VehicleTerminalCombinedDefinition extends VehicleTerminalDefinition(952) { - vehicles = groundVehicles ++ flight1Vehicles - Name = "vehicle_terminal_combined" -} diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/VehicleTerminalDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/VehicleTerminalDefinition.scala index 553d5cc1..1684f665 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/VehicleTerminalDefinition.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/VehicleTerminalDefinition.scala @@ -2,23 +2,17 @@ package net.psforever.objects.serverobject.terminals import net.psforever.objects.definition.VehicleDefinition -import net.psforever.objects.{Player, Vehicle} +import net.psforever.objects.Vehicle import net.psforever.objects.loadouts.VehicleLoadout -import net.psforever.objects.inventory.InventoryItem -import net.psforever.packet.game.ItemTransactionMessage - -abstract class VehicleTerminalDefinition(objId : Int) extends TerminalDefinition(objId) { - protected var vehicles : Map[String, ()=>Vehicle] = Map() - Name = "vehicle_terminal" +object VehicleTerminalDefinition { import net.psforever.objects.GlobalDefinitions._ - import VehicleTerminalDefinition.MakeVehicle /** * A `Map` of operations for producing a ground-based `Vehicle`. * key - an identification string sent by the client * value - a curried function that builds the object */ - protected val groundVehicles : Map[String, () => Vehicle] = Map( + val groundVehicles : Map[String, () => Vehicle] = Map( "quadassault" -> MakeVehicle(quadassault), "fury" -> MakeVehicle(fury), "quadstealth" -> MakeVehicle(quadstealth), @@ -50,7 +44,7 @@ abstract class VehicleTerminalDefinition(objId : Int) extends TerminalDefinition * key - an identification string sent by the client * value - a curried function that builds the object */ - protected val flight1Vehicles : Map[String, ()=>Vehicle] = Map( + val flight1Vehicles : Map[String, ()=>Vehicle] = Map( "mosquito" -> MakeVehicle(mosquito), "lightgunship" -> MakeVehicle(lightgunship), "wasp" -> MakeVehicle(wasp), @@ -64,7 +58,7 @@ abstract class VehicleTerminalDefinition(objId : Int) extends TerminalDefinition * key - an identification string sent by the client * value - a curried function that builds the object */ - protected val flight2Vehicles : Map[String, ()=>Vehicle] = Map( + val flight2Vehicles : Map[String, ()=>Vehicle] = Map( "dropship" -> MakeVehicle(dropship), "galaxy_gunship" -> MakeVehicle(galaxy_gunship), "lodestar" -> MakeVehicle(lodestar) @@ -75,7 +69,7 @@ abstract class VehicleTerminalDefinition(objId : Int) extends TerminalDefinition * key - an identification string sent by the client * value - a curried function that builds the object */ - protected val bfrVehicles : Map[String, ()=>Vehicle] = Map( + val bfrVehicles : Map[String, ()=>Vehicle] = Map( // "colossus_gunner" -> (()=>Unit), // "colossus_flight" -> (()=>Unit), // "peregrine_gunner" -> (()=>Unit), @@ -91,7 +85,7 @@ abstract class VehicleTerminalDefinition(objId : Int) extends TerminalDefinition * key - an identification string sent by the client (for the vehicle) * value - a curried function that builds the object */ - protected val trunk : Map[String, _Loadout] = { + val trunk : Map[String, _Loadout] = { val ammo_12mm = ShorthandAmmoBox(bullet_12mm, bullet_12mm.Capacity) val ammo_15mm = ShorthandAmmoBox(bullet_15mm, bullet_15mm.Capacity) val ammo_25mm = ShorthandAmmoBox(bullet_25mm, bullet_25mm.Capacity) @@ -483,26 +477,6 @@ abstract class VehicleTerminalDefinition(objId : Int) extends TerminalDefinition ) } - def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { - vehicles.get(msg.item_name) match { - case Some(vehicle) => - val (weapons, inventory) = trunk.get(msg.item_name) match { - case Some(loadout : VehicleLoadout) => - ( - loadout.visible_slots.map(entry => { InventoryItem(EquipmentTerminalDefinition.BuildSimplifiedPattern(entry.item), entry.index) }), - loadout.inventory.map(entry => { InventoryItem(EquipmentTerminalDefinition.BuildSimplifiedPattern(entry.item), entry.index) }) - ) - case _ => - (List.empty, List.empty) - } - Terminal.BuyVehicle(vehicle(), weapons, inventory) - case None => - Terminal.NoDeal() - } - } -} - -object VehicleTerminalDefinition { /** * Create a new `Vehicle` from provided `VehicleDefinition` objects. * @param vdef the `VehicleDefinition` object diff --git a/common/src/main/scala/net/psforever/objects/serverobject/turret/WeaponTurret.scala b/common/src/main/scala/net/psforever/objects/serverobject/turret/WeaponTurret.scala index bdf777cb..18edfdd1 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/turret/WeaponTurret.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/turret/WeaponTurret.scala @@ -3,7 +3,7 @@ package net.psforever.objects.serverobject.turret import net.psforever.objects.definition.{AmmoBoxDefinition, SeatDefinition, ToolDefinition} import net.psforever.objects._ -import net.psforever.objects.equipment.Equipment +import net.psforever.objects.equipment.{Equipment, EquipmentSlot} import net.psforever.objects.inventory.{Container, GridInventory} import net.psforever.objects.serverobject.affinity.FactionAffinity import net.psforever.objects.serverobject.mount.Mountable diff --git a/common/src/main/scala/net/psforever/objects/vehicles/MountedWeapons.scala b/common/src/main/scala/net/psforever/objects/vehicles/MountedWeapons.scala index 3320496c..0d91e502 100644 --- a/common/src/main/scala/net/psforever/objects/vehicles/MountedWeapons.scala +++ b/common/src/main/scala/net/psforever/objects/vehicles/MountedWeapons.scala @@ -1,8 +1,8 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.vehicles -import net.psforever.objects.{EquipmentSlot, PlanetSideGameObject} -import net.psforever.objects.equipment.Equipment +import net.psforever.objects.PlanetSideGameObject +import net.psforever.objects.equipment.{Equipment, EquipmentSlot} import net.psforever.objects.inventory.Container import net.psforever.objects.serverobject.mount.Mountable import net.psforever.objects.vehicles.{Seat => Chair} diff --git a/common/src/main/scala/net/psforever/objects/vehicles/Utility.scala b/common/src/main/scala/net/psforever/objects/vehicles/Utility.scala index 9b769c6b..97a8e745 100644 --- a/common/src/main/scala/net/psforever/objects/vehicles/Utility.scala +++ b/common/src/main/scala/net/psforever/objects/vehicles/Utility.scala @@ -45,11 +45,11 @@ object UtilityType extends Enumeration { * Ostensibly, the purpose of the additional logic, when it is called, * is to initialize a control `Actor` for the contained object. * This `Actor` is expected by other logic. + * @see `Amenity.Owner` * @see `Vehicle.LoadDefinition` * @see `VehicleDefinition.Utilities` * @param util the type of the `Amenity` object to be created * @param vehicle the owner of this object - * @see `Amenity.Owner` */ class Utility(util : UtilityType.Value, vehicle : Vehicle) { private val obj : Amenity = Utility.BuildUtilityFunc(util) @@ -154,9 +154,8 @@ object Utility { * The `Terminal` `Utility` produced has proximity effects. * @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields */ - class ProximityTerminalUtility(tdef : TerminalDefinition) extends Terminal(tdef) + class ProximityTerminalUtility(tdef : ProximityTerminalDefinition) extends ProximityTerminal(tdef) with UtilityWorldEntity - with ProximityUnit /** * Override for a `Terminal` object so that it inherits the spatial characteristics of its `Owner`. @@ -166,19 +165,26 @@ object Utility { */ class TeleportPadTerminalUtility(tdef : TerminalDefinition) extends TerminalUtility(tdef) { /** - * na - * @param player na - * @param msg na - * @return na + * This kind of `Terminal` object only produces one object of importance - a Router's telepad unit. + * When this `Telepad` object is produced, it shlould be associated with the Router, + * that is, with the owner of the `Terminal` object. + * @param player the player who made the request + * @param msg the request message + * @return a message that resolves the transaction */ - override def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { - val reply = super.Buy(player, msg) - reply match { - case Terminal.BuyEquipment(obj : Telepad) => - obj.Router = Owner.GUID - case _ => ; + override def Request(player : Player, msg : Any) : Terminal.Exchange = { + msg match { + case message : ItemTransactionMessage => + val reply = super.Request(player, message) + reply match { + case Terminal.BuyEquipment(obj : Telepad) => + obj.Router = Owner.GUID + case _ => ; + } + reply + case _ => + Terminal.NoDeal() } - reply } } @@ -218,22 +224,20 @@ object Utility { case UtilityType.ams_respawn_tube => SpawnTubeDefinition.Setup case UtilityType.bfr_rearm_terminal => - _OrderTerminalDefinition.Setup + OrderTerminalDefinition.Setup case UtilityType.lodestar_repair_terminal => ProximityTerminal.Setup case UtilityType.matrix_terminalc => MatrixTerminalDefinition.Setup case UtilityType.multivehicle_rearm_terminal => - _OrderTerminalDefinition.Setup + OrderTerminalDefinition.Setup case UtilityType.order_terminala => - OrderTerminalABDefinition.Setup + OrderTerminalDefinition.Setup case UtilityType.order_terminalb => - OrderTerminalABDefinition.Setup + OrderTerminalDefinition.Setup case UtilityType.teleportpad_terminal => - TeleportPadTerminalDefinition.Setup + OrderTerminalDefinition.Setup case UtilityType.internal_router_telepad_deployable => TelepadLike.Setup } - - //private def defaultSetup(o1 : Amenity, o2 : ActorContext) : Unit = { } } diff --git a/common/src/main/scala/net/psforever/objects/vital/resistance/ResistanceCalculations.scala b/common/src/main/scala/net/psforever/objects/vital/resistance/ResistanceCalculations.scala index 82b08dee..911d8f68 100644 --- a/common/src/main/scala/net/psforever/objects/vital/resistance/ResistanceCalculations.scala +++ b/common/src/main/scala/net/psforever/objects/vital/resistance/ResistanceCalculations.scala @@ -1,8 +1,9 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.vital.resistance -import net.psforever.objects.{ExoSuitDefinition, GlobalDefinitions} +import net.psforever.objects.GlobalDefinitions import net.psforever.objects.ballistics._ +import net.psforever.objects.definition.ExoSuitDefinition import net.psforever.objects.vital.projectile.ProjectileCalculations import net.psforever.types.ExoSuitType diff --git a/common/src/main/scala/net/psforever/packet/PSPacket.scala b/common/src/main/scala/net/psforever/packet/PSPacket.scala index bb516208..2ef4cbfd 100644 --- a/common/src/main/scala/net/psforever/packet/PSPacket.scala +++ b/common/src/main/scala/net/psforever/packet/PSPacket.scala @@ -236,10 +236,10 @@ object PacketHelpers { * A `peek` that decodes like the normal but encodes nothing. * Decoding `Codec[A]` from the input vector emits a value but reverts to the prior read position. * Encoding `Codec[A]` to the input vector appends no new data to the input vector. - * In effect, `peek` is a harmless meta-`Codec` that introduces no changes to the input vector. + * In effect, `peek` is a harmless meta-`Codec` that processes a value and introduces no changes to the input/output vector. * @see `scodec.codecs.peek` or `codecs/package.scala:peek` * @param target codec that decodes the value - * @return codec that behaves the same as `target` but resets remainder to the input vector + * @return `Codec` that behaves the same as `target` but resets the contents of the vector as if `Codec` were never applied */ def peek[A](target: Codec[A]): Codec[A] = new Codec[A] { def sizeBound = target.sizeBound diff --git a/common/src/main/scala/net/psforever/packet/game/DeployRequestMessage.scala b/common/src/main/scala/net/psforever/packet/game/DeployRequestMessage.scala index 0a38816a..7f40b7eb 100644 --- a/common/src/main/scala/net/psforever/packet/game/DeployRequestMessage.scala +++ b/common/src/main/scala/net/psforever/packet/game/DeployRequestMessage.scala @@ -41,10 +41,22 @@ final case class DeployRequestMessage(player_guid : PlanetSideGUID, } object DeployRequestMessage extends Marshallable[DeployRequestMessage] { + private val driveState3u = uint(3).xmap[DriveState.Value] ( + n => DriveState(n), + n => { + if(n.id > 7) { + 0 + } + else { + n.id + } + } + ) + implicit val codec : Codec[DeployRequestMessage] = ( ("player_guid" | PlanetSideGUID.codec) :: ("vehicle_guid" | PlanetSideGUID.codec) :: - ("deploy_state" | DriveState.codec) :: + ("deploy_state" | driveState3u) :: ("unk2" | uint(5)) :: ("unk3" | bool) :: ("pos" | Vector3.codec_pos) diff --git a/common/src/main/scala/net/psforever/packet/game/ObjectCreateDetailedMessage.scala b/common/src/main/scala/net/psforever/packet/game/ObjectCreateDetailedMessage.scala index 7bbd21e8..0c2d9363 100644 --- a/common/src/main/scala/net/psforever/packet/game/ObjectCreateDetailedMessage.scala +++ b/common/src/main/scala/net/psforever/packet/game/ObjectCreateDetailedMessage.scala @@ -39,7 +39,7 @@ final case class ObjectCreateDetailedMessage(streamLength : Long, objectClass : Int, guid : PlanetSideGUID, parentInfo : Option[ObjectCreateMessageParent], - data : Option[ConstructorData]) + data : ConstructorData) extends PlanetSideGamePacket { type Packet = ObjectCreateDetailedMessage def opcode = GamePacketOpcode.ObjectCreateMessage @@ -57,7 +57,7 @@ object ObjectCreateDetailedMessage extends Marshallable[ObjectCreateDetailedMess */ def apply(objectClass : Int, guid : PlanetSideGUID, parentInfo : ObjectCreateMessageParent, data : ConstructorData) : ObjectCreateDetailedMessage = { val parentInfoOpt : Option[ObjectCreateMessageParent] = Some(parentInfo) - ObjectCreateDetailedMessage(ObjectCreateBase.streamLen(parentInfoOpt, data), objectClass, guid, parentInfoOpt, Some(data)) + ObjectCreateDetailedMessage(ObjectCreateBase.streamLen(parentInfoOpt, data), objectClass, guid, parentInfoOpt, data) } /** @@ -68,7 +68,7 @@ object ObjectCreateDetailedMessage extends Marshallable[ObjectCreateDetailedMess * @return an ObjectCreateMessage */ def apply(objectClass : Int, guid : PlanetSideGUID, data : ConstructorData) : ObjectCreateDetailedMessage = { - ObjectCreateDetailedMessage(ObjectCreateBase.streamLen(None, data), objectClass, guid, None, Some(data)) + ObjectCreateDetailedMessage(ObjectCreateBase.streamLen(None, data), objectClass, guid, None, data) } implicit val codec : Codec[ObjectCreateDetailedMessage] = ObjectCreateBase.baseCodec.exmap[ObjectCreateDetailedMessage] ( @@ -77,31 +77,36 @@ object ObjectCreateDetailedMessage extends Marshallable[ObjectCreateDetailedMess Attempt.failure(Err("no data to decode")) case len :: cls :: guid :: par :: data :: HNil => - val obj = ObjectCreateBase.decodeData(cls, data, + ObjectCreateBase.decodeData(cls, data, if(par.isDefined) { ObjectClass.selectDataDetailedCodec } else { ObjectClass.selectDataDroppedDetailedCodec } - ) - Attempt.successful(ObjectCreateDetailedMessage(len, cls, guid, par, obj)) + ) match { + case Attempt.Successful(obj) => + Attempt.successful(ObjectCreateDetailedMessage(len, cls, guid, par, obj)) + case Attempt.Failure(err) => + Attempt.failure(err) + } }, { - case ObjectCreateDetailedMessage(_ , _ , _, _, None) => - Attempt.failure(Err("no object to encode")) - - case ObjectCreateDetailedMessage(_, cls, guid, par, Some(obj)) => + case ObjectCreateDetailedMessage(_, cls, guid, par, obj) => val len = ObjectCreateBase.streamLen(par, obj) //even if a stream length has been assigned, it can not be trusted during encoding - val bitvec = ObjectCreateBase.encodeData(cls, obj, + ObjectCreateBase.encodeData(cls, obj, if(par.isDefined) { ObjectClass.selectDataDetailedCodec } else { ObjectClass.selectDataDroppedDetailedCodec } - ) - Attempt.successful(len :: cls :: guid :: par :: bitvec :: HNil) + ) match { + case Attempt.Successful(bvec) => + Attempt.successful(len :: cls :: guid :: par :: bvec :: HNil) + case Attempt.Failure(err) => + Attempt.failure(err) + } } ) } diff --git a/common/src/main/scala/net/psforever/packet/game/ObjectCreateMessage.scala b/common/src/main/scala/net/psforever/packet/game/ObjectCreateMessage.scala index bbe9108f..7fc98a58 100644 --- a/common/src/main/scala/net/psforever/packet/game/ObjectCreateMessage.scala +++ b/common/src/main/scala/net/psforever/packet/game/ObjectCreateMessage.scala @@ -2,7 +2,7 @@ package net.psforever.packet.game import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket} -import net.psforever.packet.game.objectcreate._ +import net.psforever.packet.game.objectcreate.{ObjectCreateBase, _} import scodec.{Attempt, Codec, Err} import scodec.bits.BitVector import shapeless.{::, HNil} @@ -50,7 +50,7 @@ final case class ObjectCreateMessage(streamLength : Long, objectClass : Int, guid : PlanetSideGUID, parentInfo : Option[ObjectCreateMessageParent], - data : Option[ConstructorData]) + data : ConstructorData) extends PlanetSideGamePacket { type Packet = ObjectCreateMessage def opcode = GamePacketOpcode.ObjectCreateMessage_Duplicate @@ -68,7 +68,7 @@ object ObjectCreateMessage extends Marshallable[ObjectCreateMessage] { */ def apply(objectClass : Int, guid : PlanetSideGUID, parentInfo : ObjectCreateMessageParent, data : ConstructorData) : ObjectCreateMessage = { val parentInfoOpt : Option[ObjectCreateMessageParent] = Some(parentInfo) - ObjectCreateMessage(ObjectCreateBase.streamLen(parentInfoOpt, data), objectClass, guid, parentInfoOpt, Some(data)) + ObjectCreateMessage(ObjectCreateBase.streamLen(parentInfoOpt, data), objectClass, guid, parentInfoOpt, data) } /** @@ -79,7 +79,7 @@ object ObjectCreateMessage extends Marshallable[ObjectCreateMessage] { * @return an `ObjectCreateMessage` */ def apply(objectClass : Int, guid : PlanetSideGUID, data : ConstructorData) : ObjectCreateMessage = { - ObjectCreateMessage(ObjectCreateBase.streamLen(None, data), objectClass, guid, None, Some(data)) + ObjectCreateMessage(ObjectCreateBase.streamLen(None, data), objectClass, guid, None, data) } implicit val codec : Codec[ObjectCreateMessage] = ObjectCreateBase.baseCodec.exmap[ObjectCreateMessage] ( @@ -88,31 +88,35 @@ object ObjectCreateMessage extends Marshallable[ObjectCreateMessage] { Attempt.failure(Err("no data to decode")) case len :: cls :: guid :: par :: data :: HNil => - val obj = ObjectCreateBase.decodeData(cls, data, - if(par.isDefined) { - ObjectClass.selectDataCodec + ObjectCreateBase.decodeData(cls, data, if(par.isDefined) { + ObjectClass.selectDataCodec } else { ObjectClass.selectDataDroppedCodec } - ) - Attempt.successful(ObjectCreateMessage(len, cls, guid, par, obj)) + ) match { + case Attempt.Successful(obj) => + Attempt.successful(ObjectCreateMessage(len, cls, guid, par, obj)) + case Attempt.Failure(err) => + Attempt.failure(err) + } }, { - case ObjectCreateMessage(_ , _ , _, _, None) => - Attempt.failure(Err("no object to encode")) - - case ObjectCreateMessage(_, cls, guid, par, Some(obj)) => + case ObjectCreateMessage(_, cls, guid, par, obj) => val len = ObjectCreateBase.streamLen(par, obj) //even if a stream length has been assigned, it can not be trusted during encoding - val bitvec = ObjectCreateBase.encodeData(cls, obj, + ObjectCreateBase.encodeData(cls, obj, if(par.isDefined) { ObjectClass.selectDataCodec } else { ObjectClass.selectDataDroppedCodec } - ) - Attempt.successful(len :: cls :: guid :: par :: bitvec :: HNil) + ) match { + case Attempt.Successful(bvec) => + Attempt.successful(len :: cls :: guid :: par :: bvec :: HNil) + case Attempt.Failure(err) => + Attempt.failure(err) + } } ) } diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/ACEData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/ACEData.scala deleted file mode 100644 index ef6324e2..00000000 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/ACEData.scala +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.packet.game.objectcreate - -import net.psforever.packet.Marshallable -import scodec.{Attempt, Codec, Err} -import scodec.codecs._ -import shapeless.{::, HNil} - -/** - * A representation of an adaptive construction engine (ACE). - * This one-time-use item deploys a variety of utilities into the game environment. - * Has an advanced version internally called an `advanced_ace` and commonly called a Field Deployment Unit (FDU). - * @param unk1 na - * @param unk2 na - * @param unk3 na - */ -final case class ACEData(unk1 : Int, - unk2 : Int, - unk3 : Int = 0 - ) extends ConstructorData { - override def bitsize : Long = 34L -} - -object ACEData extends Marshallable[ACEData] { - implicit val codec : Codec[ACEData] = ( - ("unk1" | uint4L) :: - ("unk2" | uint4L) :: - uint(20) :: - ("unk3" | uint4L) :: - uint2L - ).exmap[ACEData] ( - { - case unk1 :: unk2 :: 0 :: unk3 :: 0 :: HNil => - Attempt.successful(ACEData(unk1, unk2, unk3)) - case _ :: _ :: _ :: _ :: _ :: HNil => - Attempt.failure(Err("invalid ace data format")) - }, - { - case ACEData(unk1, unk2, unk3) => - Attempt.successful(unk1 :: unk2 :: 0 :: unk3 :: 0 :: HNil) - } - ) -} diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/AegisShieldGeneratorData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/AegisShieldGeneratorData.scala index 271d7ca7..b33becc5 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/AegisShieldGeneratorData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/AegisShieldGeneratorData.scala @@ -11,7 +11,7 @@ import shapeless.{::, HNil} * @param deploy data common to objects spawned by the (advanced) adaptive construction engine * @param health the amount of health the object has, as a percentage of a filled bar */ -final case class AegisShieldGeneratorData(deploy : CommonFieldData, +final case class AegisShieldGeneratorData(deploy : CommonFieldDataWithPlacement, health : Int ) extends ConstructorData { override def bitsize : Long = { @@ -21,15 +21,16 @@ final case class AegisShieldGeneratorData(deploy : CommonFieldData, object AegisShieldGeneratorData extends Marshallable[AegisShieldGeneratorData] { implicit val codec : Codec[AegisShieldGeneratorData] = ( - ("deploy" | CommonFieldData.codec) :: + ("deploy" | CommonFieldDataWithPlacement.codec) :: ("health" | uint8L) :: uint32 :: uint32 :: uint32 :: uint4L //100 bits ).exmap[AegisShieldGeneratorData] ( { case deploy :: health :: 0 :: 0 :: 0 :: 0 :: HNil => Attempt.successful(AegisShieldGeneratorData(deploy, health)) - case _ => - Attempt.failure(Err("invalid aegis data format")) + + case data => + Attempt.failure(Err(s"invalid aegis data format - $data")) }, { case AegisShieldGeneratorData(deploy, health) => diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/AmmoBoxData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/AmmoBoxData.scala index 90f1c281..df3c7dc4 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/AmmoBoxData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/AmmoBoxData.scala @@ -1,53 +1,26 @@ // Copyright (c) 2017 PSForever package net.psforever.packet.game.objectcreate -import net.psforever.packet.Marshallable import net.psforever.packet.game.PlanetSideGUID -import scodec.{Attempt, Codec, Err} -import scodec.codecs._ -import shapeless.{::, HNil} /** * A representation of ammunition that can be created using `ObjectCreateMessage` packet data. * This data will help construct a "box" of that type of ammunition when standalone. * It can also be constructed directly inside a weapon as its magazine.
*
- * This ammunition object ompletely ignores thr capacity field, normal to detailed ammunition objects. - * Creating an object of this type directly and picking it up or observing it (in a weapon) reveals a single round. - * @param unk na; - * defaults to 0 + * This ammunition object ompletely ignores the capacity field, normal to detailed ammunition objects. + * Creating an object of this type directly and picking it up or observing it (in a weapon) will reveals single round. * @see `DetailedAmmoBoxData` */ -final case class AmmoBoxData(unk : Int = 0) extends ConstructorData { - override def bitsize : Long = 24L -} - -object AmmoBoxData extends Marshallable[AmmoBoxData] { +object AmmoBoxData { /** * An abbreviated constructor for creating `AmmoBoxData` while masking use of `InternalSlot`. * @param cls the code for the type of object being constructed * @param guid the GUID this object will be assigned * @param parentSlot a parent-defined slot identifier that explains where the child is to be attached to the parent * @param ammo the ammunition object - * @return an `InternalSlot` object that encapsulates `AmmoBoxData` + * @return an `InternalSlot` object that encapsulates `CommonFieldData` */ - def apply(cls : Int, guid : PlanetSideGUID, parentSlot : Int, ammo : AmmoBoxData) : InternalSlot = + def apply(cls : Int, guid : PlanetSideGUID, parentSlot : Int, ammo : CommonFieldData) : InternalSlot = new InternalSlot(cls, guid, parentSlot, ammo) - - implicit val codec : Codec[AmmoBoxData] = ( - uint4L :: - ("unk" | uint4L) :: // 8 - common - 4 - safe, 2 - stream misalignment, 1 - safe, 0 - common - uint(16) - ).exmap[AmmoBoxData] ( - { - case 0xC :: unk :: 0 :: HNil => - Attempt.successful(AmmoBoxData(unk)) - case _ :: _ :: _ :: HNil => - Attempt.failure(Err("invalid ammunition data format")) - }, - { - case AmmoBoxData(unk) => - Attempt.successful(0xC :: unk :: 0 :: HNil) - } - ) } diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/BoomerTriggerData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/BoomerTriggerData.scala deleted file mode 100644 index f5e704b7..00000000 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/BoomerTriggerData.scala +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.packet.game.objectcreate - -import net.psforever.packet.Marshallable -import scodec.{Attempt, Codec, Err} -import scodec.codecs._ -import shapeless.{::, HNil} - -/** - * A representation of the detonator utility that is created when putting down a Boomer with an ACE. - * @param unk na - */ -final case class BoomerTriggerData(unk : Int = 0x8) extends ConstructorData { - override def bitsize : Long = 34L -} - -object BoomerTriggerData extends Marshallable[BoomerTriggerData] { - implicit val codec : Codec[BoomerTriggerData] = ( - uint4L :: - uint4L :: - uint(26) - ).exmap[BoomerTriggerData] ( - { - case 0xC :: unk :: 0 :: HNil => - Attempt.successful(BoomerTriggerData(unk)) - case _ => - Attempt.failure(Err("invalid command detonater format")) - }, - { - case BoomerTriggerData(unk) => - Attempt.successful(0xC :: unk :: 0 :: HNil) - } - ) -} diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/CaptureFlagData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/CaptureFlagData.scala index 44b32560..56e402d0 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/CaptureFlagData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/CaptureFlagData.scala @@ -50,8 +50,9 @@ object CaptureFlagData extends Marshallable[CaptureFlagData] { { case pos :: fac :: false :: 4 :: 0 :: unk1 :: 0 :: unk2 :: 0 :: unk3 :: unk4 :: 0 :: HNil => Attempt.Successful(CaptureFlagData(pos, fac, unk1, unk2, unk3, unk4)) - case _ => - Attempt.failure(Err("invalid capture flag data")) + + case data => + Attempt.failure(Err(s"invalid capture flag data format - $data")) }, { case CaptureFlagData(pos, fac, unk1, unk2, unk3, unk4) => diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/CharacterAppearanceData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/CharacterAppearanceData.scala index 2bc98a36..c2b064d3 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/CharacterAppearanceData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/CharacterAppearanceData.scala @@ -1,6 +1,7 @@ // Copyright (c) 2017 PSForever package net.psforever.packet.game.objectcreate +import net.psforever.packet.game.PlanetSideGUID import net.psforever.packet.{Marshallable, PacketHelpers} import net.psforever.types._ import scodec.{Attempt, Codec, Err} @@ -12,22 +13,20 @@ import shapeless.{::, HNil} * @see `CharacterData` * @see `DetailedCharacterData` * @see `ExoSuitType` - * @param app the player's cardinal appearance settings - * @param black_ops whether or not this avatar is enrolled in Black OPs - * @param jammered the player has been caught in an EMP blast recently; - * creates a jammered sound effect that follows the player around and can be heard by others - * @param exosuit the type of exo-suit the avatar will be depicted in; - * for Black OPs, the agile exo-suit and the reinforced exo-suit are replaced with the Black OPs exo-suits + * @param app the player's cardinal appearance settings + * @param data common field data
+ * -bops - this vehicle belongs to the Black Ops, regardless of the faction field; + * activates the green camo and adjusts permissions
+ * -destroyed - flagged when using a model that is not the standard player in some stance
+ * -jammered - the player has been caught in an EMP blast recently; + * creates a jammered sound effect that follows the player around and can be heard by others
+ * -player_guid - does nothing? + * @param exosuit the type of exo-suit the avatar will be depicted in; + * for Black OPs, the agile exo-suit and the reinforced exo-suit are replaced with the Black OPs exo-suits */ final case class CharacterAppearanceA(app : BasicCharacterData, - black_ops : Boolean, - altModel : Boolean, - unk1 : Boolean, - unk2 : Option[CharacterAppearanceData.ExtraData], - jammered : Boolean, + data : CommonFieldData, exosuit : ExoSuitType.Value, - unk3 : Option[Int], - unk4 : Int, unk5 : Int, unk6 : Long, unk7 : Int, @@ -36,11 +35,9 @@ final case class CharacterAppearanceA(app : BasicCharacterData, unkA : Int) (name_padding : Int) extends StreamBitSize { override def bitsize : Long = { - //factor guard bool values into the base size, not its corresponding optional field - val unk2Size : Long = unk2 match { case Some(n) => n.bitsize ; case None => 0L } + val dataSize : Long = data.bitsize val nameStringSize : Long = StreamBitSize.stringBitSize(app.name, 16) + name_padding - val unk3Size : Long = unk3 match { case Some(_) => 32L ; case None => 0L } - 137L + unk2Size + nameStringSize + unk3Size + 114L + dataSize + nameStringSize } } @@ -162,14 +159,23 @@ object CharacterAppearanceData extends Marshallable[CharacterAppearanceData] { val altModel : Boolean = backpack || on_zipline.isDefined val a = CharacterAppearanceA( app, - black_ops, - altModel, - false, - None, - jammered, + CommonFieldData( + app.faction, + black_ops, + altModel, + false, + None, + false, + None, + if(jammered) { + Some(0) + } + else { + None + }, + PlanetSideGUID(0) + ), exosuit, - None, - 0, 0, 0, 0, @@ -206,7 +212,7 @@ object CharacterAppearanceData extends Marshallable[CharacterAppearanceData] { def apply(a : Int=>CharacterAppearanceA, b : (Boolean,Int)=>CharacterAppearanceB, ribbons : RibbonBars)(name_padding : Int) : CharacterAppearanceData = { val first = a(name_padding) - CharacterAppearanceData(a(name_padding), b(first.altModel, name_padding), ribbons)(name_padding) + CharacterAppearanceData(a(name_padding), b(first.data.alternate, name_padding), ribbons)(name_padding) } /** @@ -238,13 +244,18 @@ object CharacterAppearanceData extends Marshallable[CharacterAppearanceData] { * @return the length of the variable field that exists when using alternate models */ def altModelBit(app : CharacterAppearanceData) : Option[Int] = if(app.b.backpack || app.b.on_zipline.isDefined) { - Some(1) + if(!app.a.data.alternate) { + throw new IllegalArgumentException("missing alternate model flag when should be set") + } + else { + Some(1) + } } else { None } - def namePadding(inheritPad : Int, pad : Option[ExtraData]) : Int = { + def namePadding(inheritPad : Int, pad : Option[CommonFieldDataExtra]) : Int = { pad match { case Some(n) => val bitsize = n.bitsize.toInt % 8 @@ -282,45 +293,48 @@ object CharacterAppearanceData extends Marshallable[CharacterAppearanceData] { * @return na */ def a_codec(name_padding : Int) : Codec[CharacterAppearanceA] = ( - ("faction" | PlanetSideEmpire.codec) :: - ("black_ops" | bool) :: - (("alt_model" | bool) >>:~ { alt_model => //modifies stream format (to display alternate player models) - ("unk1" | bool) :: //serves a different internal purpose depending on the state of alt_model - (conditional(false, "unk2" | extra_codec) >>:~ { extra => //TODO not sure what causes this branch - ("jammered" | bool) :: - optional(bool, "unk3" | uint16L) :: - ("unk4" | uint16L) :: - ("name" | PacketHelpers.encodedWideStringAligned(namePadding(name_padding, extra))) :: - ("exosuit" | ExoSuitType.codec) :: - ("unk5" | uint2) :: //unknown - ("sex" | CharacterGender.codec) :: - ("head" | uint8L) :: - ("voice" | CharacterVoice.codec) :: - ("unk6" | uint32L) :: - ("unk7" | uint16L) :: - ("unk8" | uint16L) :: - ("unk9" | uint16L) :: - ("unkA" | uint16L) //usually either 0 or 65535 - }) - }) + ("data" | CommonFieldData.codec) >>:~ { data => + ("name" | PacketHelpers.encodedWideStringAligned(namePadding(name_padding, data.v2))) :: + ("exosuit" | ExoSuitType.codec) :: + ("unk5" | uint2) :: //unknown + ("sex" | CharacterGender.codec) :: + ("head" | uint8L) :: + ("voice" | CharacterVoice.codec) :: + ("unk6" | uint32L) :: + ("unk7" | uint16L) :: + ("unk8" | uint16L) :: + ("unk9" | uint16L) :: + ("unkA" | uint16L) //usually either 0 or 65535 + } ).exmap[CharacterAppearanceA] ( { - case faction :: bops :: alt :: u1 :: u2 :: jamd :: u3 :: u4 :: name :: suit :: u5 :: sex :: head :: v1 :: u6 :: u7 :: u8 :: u9 :: uA :: HNil => + case data :: name :: suit :: u5 :: sex :: head :: v1 :: u6 :: u7 :: u8 :: u9 :: uA :: HNil => Attempt.successful( - CharacterAppearanceA(BasicCharacterData(name, faction, sex, head, v1), bops, alt, u1, u2, jamd, suit, u3, u4, u5, u6, u7, u8, u9, uA)(name_padding) + CharacterAppearanceA(BasicCharacterData(name, data.faction, sex, head, v1), data, suit, u5, u6, u7, u8, u9, uA)(name_padding) ) case _ => Attempt.Failure(Err("invalid character appearance data; can not encode")) }, { - case CharacterAppearanceA(BasicCharacterData(name, PlanetSideEmpire.NEUTRAL, _, _, _), _, _, _, _, _, _, _, _, _, _, _, _, _, _) => + case CharacterAppearanceA(BasicCharacterData(name, PlanetSideEmpire.NEUTRAL, _, _, _), _, _, _, _, _, _, _, _) => Attempt.failure(Err(s"character $name's faction can not declare as neutral")) - case CharacterAppearanceA(BasicCharacterData(name, faction, sex, head, v1), bops, alt, u1, u2, jamd, suit, u3, u4, u5, u6, u7, u8, u9, uA) => - Attempt.successful( - faction :: bops :: alt :: u1 :: u2 :: jamd :: u3 :: u4 :: name :: suit :: u5 :: sex :: head :: v1 :: u6 :: u7 :: u8 :: u9 :: uA :: HNil - ) + case CharacterAppearanceA(BasicCharacterData(name, faction, sex, head, v1), data, suit, u5, u6, u7, u8, u9, uA) => + if(faction != data.faction) { + Attempt.failure(Err(s"character $name's faction fields are mismatched, $faction != ${data.faction}")) + } + else if(data.faction == PlanetSideEmpire.NEUTRAL) { + Attempt.successful( + CommonFieldData(faction, data.bops, data.alternate, data.v1, data.v2, data.v3, None, data.v5, PlanetSideGUID(0)) :: + name :: suit :: u5 :: sex :: head :: v1 :: u6 :: u7 :: u8 :: u9 :: uA :: HNil + ) + } + else { + Attempt.successful( + data :: name :: suit :: u5 :: sex :: head :: v1 :: u6 :: u7 :: u8 :: u9 :: uA :: HNil + ) + } case _ => Attempt.Failure(Err("invalid character appearance data; can not decode")) @@ -385,7 +399,7 @@ object CharacterAppearanceData extends Marshallable[CharacterAppearanceData] { def codec(name_padding : Int) : Codec[CharacterAppearanceData] = ( ("a" | a_codec(name_padding)) >>:~ { a => - ("b" | b_codec(a.altModel, name_padding)) :: + ("b" | b_codec(a.data.alternate, name_padding)) :: ("ribbons" | RibbonBars.codec) } ).xmap[CharacterAppearanceData] ( diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/CharacterData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/CharacterData.scala index a913b901..3a3fadb7 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/CharacterData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/CharacterData.scala @@ -27,7 +27,8 @@ object ImplantEffects extends Enumeration { /** * Values for the four different color designs that impact a player's uniform. - * Exo-suits get minor graphical updates at the following battle rank levels: seven, fourteen, and twenty-five. + * Exo-suits get minor graphical updates at the following battle rank levels: seven (1), fourteen (2), and twenty-five (4). + * The values 3 and 5 also exist and are visually descriptive to the third upgrade. */ object UniformStyle extends Enumeration { type Type = Value @@ -35,9 +36,11 @@ object UniformStyle extends Enumeration { val Normal = Value(0) val FirstUpgrade = Value(1) val SecondUpgrade = Value(2) + val SecondUpgradeEx = Value(3) val ThirdUpgrade = Value(4) + val ThirdUpgradeEx = Value(5) - implicit val codec = PacketHelpers.createEnumerationCodec(this, uintL(3)) + implicit val codec = PacketHelpers.createEnumerationCodec(this, uint(3)) } /** @@ -115,7 +118,7 @@ object CharacterData extends Marshallable[CharacterData] { uint(3) :: //uniform_upgrade is actually interpreted as a 6u field, but the lower 3u seems to be discarded ("command_rank" | uintL(3)) :: listOfN(uint2, "implant_effects" | ImplantEffects.codec) :: - conditional(style == UniformStyle.ThirdUpgrade, "cosmetics" | Cosmetics.codec) + conditional(style.id > UniformStyle.SecondUpgrade.id,"cosmetics" | Cosmetics.codec) }) ).exmap[CharacterData] ( { @@ -141,7 +144,7 @@ object CharacterData extends Marshallable[CharacterData] { uint(3) :: //uniform_upgrade is actually interpreted as a 6u field, but the lower 3u seems to be discarded ("command_rank" | uintL(3)) :: listOfN(uint2, "implant_effects" | ImplantEffects.codec) :: - conditional(style == UniformStyle.ThirdUpgrade, "cosmetics" | Cosmetics.codec) + conditional(style.id > UniformStyle.SecondUpgrade.id, "cosmetics" | Cosmetics.codec) } ).exmap[CharacterData] ( { diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/CommandDetonaterData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/CommandDetonaterData.scala deleted file mode 100644 index 0d5d46a2..00000000 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/CommandDetonaterData.scala +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.packet.game.objectcreate - -import net.psforever.packet.Marshallable -import scodec.{Attempt, Codec, Err} -import scodec.codecs._ -import shapeless.{::, HNil} - -/** - * A representation of the command uplink device.
- * I don't know much about the command uplink device so someone else has to provide this commentary. - */ -final case class CommandDetonaterData(unk1 : Int = 0, - unk2 : Int = 0) extends ConstructorData { - override def bitsize : Long = 34L -} - -object CommandDetonaterData extends Marshallable[CommandDetonaterData] { - implicit val codec : Codec[CommandDetonaterData] = ( - ("unk1" | uint4L) :: - ("unk2" | uint4L) :: - uint(26) - ).exmap[CommandDetonaterData] ( - { - case unk1 :: unk2 :: 0 :: HNil => - Attempt.successful(CommandDetonaterData(unk1, unk2)) - case _ :: _ :: _ :: HNil => - Attempt.failure(Err("invalid command detonator data format")) - }, - { - case CommandDetonaterData(unk1, unk2) => - Attempt.successful(unk1 :: unk2 :: 0 :: HNil) - } - ) -} diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/CommonFieldData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/CommonFieldData.scala index 37ec4167..6c9ef68c 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/CommonFieldData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/CommonFieldData.scala @@ -8,96 +8,138 @@ import scodec.{Attempt, Codec, Err} import scodec.codecs._ import shapeless.{::, HNil} +final case class CommonFieldDataExtra(unk1 : Int, unk2 : Boolean) extends StreamBitSize { + override def bitsize : Long = 17L +} + +object CommonFieldDataExtra { + implicit val codec : Codec[CommonFieldDataExtra] = ( + ("unk1" | uint16L) :: + ("unk2" | bool) + ).as[CommonFieldDataExtra] +} + /** * Data that is common to a number of game object serializations. - * @param pos where and how the object is oriented - * @param faction association of the object with - * @param unk na - * @param player_guid the player who placed/leverages/[action]s this object + * @param faction faction affinity + * `NEUTRAL` when not required to be any specific value + * @param bops usually indicates black ops affiliation + * @param alternate usually indicates variance in model from default (e.g., vehicle is destroyed, player has released, etc.); + * when set on a tool, that tool will be rendered nonfunctional instead (though it can still be equipped) + * @param v1 na + * @param v2 na; + * optional data whose reading is triggered in unknown conditions; + * flag a weapon as "jammered" + * @param v3 na; + * for weapons, works like `alternate` + * @param v4 na; + * a field used by a second encoding format for this data + * @param v5 na; + * previously considered to flag as "jammered" + * @param guid usually indicates another active game object that placed/leverages/[action]s this object */ -final case class CommonFieldData(pos : PlacementData, - faction : PlanetSideEmpire.Value, +final case class CommonFieldData(faction : PlanetSideEmpire.Value, bops : Boolean, - destroyed : Boolean, - unk : Int, - jammered : Boolean, - player_guid : PlanetSideGUID - ) extends StreamBitSize { - override def bitsize : Long = 23L + pos.bitsize + alternate : Boolean, + v1 : Boolean, + v2 : Option[CommonFieldDataExtra], + v3 : Boolean, + v4 : Option[Boolean], + v5 : Option[Int], + guid : PlanetSideGUID + ) extends ConstructorData { + override def bitsize : Long = { + val extraSize : Long = v2 match { + case Some(v) => v.bitsize + case None => 0L + } + val v4Size = v4 match { + case Some(_) => 1L + case None => 0L + } + val v5Size = v5 match { + case Some(_) => 16L + case None => 0L + } + 23L + extraSize + v4Size + v5Size + } + + def apply(flag : Boolean) : CommonFieldData = CommonFieldData(faction, bops, alternate, v1, v2, v3, Some(flag), v5, guid) } object CommonFieldData extends Marshallable[CommonFieldData] { - final val internalWeapon_bitsize : Long = 10 - /** - * Overloaded constructor that eliminates the need to list the fourth, optional, GUID field. - * @param pos where and how the object is oriented - * @param faction association of the object with - * @param unk na + * Overloaded constructors. * @return a `CommonFieldData` object */ - def apply(pos : PlacementData, faction : PlanetSideEmpire.Value, unk : Int) : CommonFieldData = - CommonFieldData(pos, faction, false, false, unk, false, PlanetSideGUID(0)) + def apply() : CommonFieldData = + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)) - def apply(pos : PlacementData, faction : PlanetSideEmpire.Value, unk : Int, player_guid : PlanetSideGUID) : CommonFieldData = - CommonFieldData(pos, faction, false, false, unk, false, player_guid) + def apply(faction : PlanetSideEmpire.Value) : CommonFieldData = + CommonFieldData(faction, false, false, false, None, false, None, None, PlanetSideGUID(0)) - def apply(pos : PlacementData, faction : PlanetSideEmpire.Value, destroyed : Boolean, unk : Int) : CommonFieldData = - CommonFieldData(pos, faction, false, destroyed, unk, false, PlanetSideGUID(0)) + def apply(faction : PlanetSideEmpire.Value, unk : Int) : CommonFieldData = + CommonFieldData(faction, false, false, unk>1, None, unk%1==1, None, None, PlanetSideGUID(0)) - def apply(pos : PlacementData, faction : PlanetSideEmpire.Value, destroyed : Boolean, unk : Int, player_guid : PlanetSideGUID) : CommonFieldData = - CommonFieldData(pos, faction, false, destroyed, unk, false, player_guid) + def apply(faction : PlanetSideEmpire.Value, unk : Int, player_guid : PlanetSideGUID) : CommonFieldData = + CommonFieldData(faction, false, false, unk>1, None, unk%1==1, None, None, player_guid) - /** - * `Codec` for transforming reliable `WeaponData` from the internal structure of the turret when it is defined. - * Works for both `SmallTurretData` and `OneMannedFieldTurretData`. - */ - val internalWeaponCodec : Codec[InternalSlot] = ( - uint8L :: //number of internal weapons (should be 1)? - uint2L :: - InternalSlot.codec - ).exmap[InternalSlot] ( + def apply(faction : PlanetSideEmpire.Value, destroyed : Boolean, unk : Int) : CommonFieldData = + CommonFieldData(faction, false, destroyed, unk>1, None, unk%1==1, None, None, PlanetSideGUID(0)) + + def apply(faction : PlanetSideEmpire.Value, destroyed : Boolean, unk : Int, player_guid : PlanetSideGUID) : CommonFieldData = + CommonFieldData(faction, false, destroyed, unk>1, None, unk%1==1, None, None, player_guid) + + def apply(faction : PlanetSideEmpire.Value, bops : Boolean, destroyed : Boolean, unk : Int, jammered : Boolean, player_guid : PlanetSideGUID) : CommonFieldData = { + val jammeredField = if(jammered) { Some(0) } else { None } + CommonFieldData(faction, bops, destroyed, unk>1, None, unk%1==1, None, jammeredField, player_guid) + } + + def codec(extra : Boolean) : Codec[CommonFieldData] = ( + ("faction" | PlanetSideEmpire.codec) :: + ("bops" | bool) :: + ("alternate" | bool) :: + ("v1" | bool) :: //the purpose of this bit changes depending on the previous bit + conditional(extra, "v2" | CommonFieldDataExtra.codec) :: + ("v3" | bool) :: + optional(bool, "v5" | uint16L) :: + ("guid" | PlanetSideGUID.codec) + ).xmap[CommonFieldData] ( { - case 1 :: 0 :: InternalSlot(a1, b1, c1, WeaponData(a2, b2, c2, d)) :: HNil => - Attempt.successful(InternalSlot(a1, b1, c1, WeaponData(a2, b2, c2, d))) - - case 1 :: 0 :: InternalSlot(_, _, _, _) :: HNil => - Attempt.failure(Err(s"turret internals must contain weapon data")) - - case n :: 0 :: _ :: HNil => - Attempt.failure(Err(s"turret internals can not have $n weapons")) - - case _ => - Attempt.failure(Err("invalid turret internals data format")) + case faction :: bops :: alternate :: v1 :: v2 :: v3 :: v5 :: player_guid :: HNil => + CommonFieldData(faction, bops, alternate, v1, v2, v3, None, v5, player_guid) }, { - case InternalSlot(a1, b1, c1, WeaponData(a2, b2, c2, d)) => - Attempt.successful(1 :: 0 :: InternalSlot(a1, b1, c1, WeaponData(a2, b2, c2, d)) :: HNil) - - case InternalSlot(_, _, _, _) => - Attempt.failure(Err(s"turret internals must contain weapon data")) - - case _ => - Attempt.failure(Err("invalid turret internals data format")) + case CommonFieldData(faction, bops, alternate, v1, v2, v3, _, v5, guid) => + faction :: bops :: alternate :: v1 :: v2 :: v3 :: v5 :: guid :: HNil } ) - implicit val codec : Codec[CommonFieldData] = ( - ("pos" | PlacementData.codec) :: - ("faction" | PlanetSideEmpire.codec) :: + implicit val codec : Codec[CommonFieldData] = codec(false) + + def codec2(extra : Boolean) : Codec[CommonFieldData] = ( + ("faction" | PlanetSideEmpire.codec) :: ("bops" | bool) :: - ("destroyed" | bool) :: - ("unk" | uint2L) :: //3 - na, 2 - common, 1 - na, 0 - common? - ("jammered" | bool) :: - ("player_guid" | PlanetSideGUID.codec) + ("alternate" | bool) :: + ("v1" | bool) :: //though the code path differs depending on the previous bit, this one gets read one way or another + conditional(extra, "v2" | CommonFieldDataExtra.codec) :: + ("v3" | bool) :: + optional(bool, "v5" | uint16L) :: + ("v4" | bool) :: + ("guid" | PlanetSideGUID.codec) ).exmap[CommonFieldData] ( { - case pos :: fac :: bops :: wrecked :: unk :: jammered :: player :: HNil => - Attempt.successful(CommonFieldData(pos, fac, bops, wrecked, unk,jammered, player)) + case faction :: bops :: alternate :: v1 :: v2 :: v3 :: v5 :: v4 :: guid :: HNil => + Attempt.successful(CommonFieldData(faction, bops, alternate, v1, v2, v3, Some(v4), v5, guid)) }, { - case CommonFieldData(pos, fac, bops, wrecked, unk, jammered, player) => - Attempt.successful(pos :: fac :: bops :: wrecked :: unk :: jammered :: player :: HNil) + case CommonFieldData(_, _, _, _, _, _, None, _, _) => + Attempt.Failure(Err("invalid CommonFieldData - expected a field to be defined, but it was 'None'")) + + case CommonFieldData(faction, bops, alternate, v1, v2, v3, Some(v4), v5, player_guid) => + Attempt.successful(faction :: bops :: alternate :: v1 :: v2 :: v3 :: v5 :: v4 :: player_guid :: HNil) } ) + + val codec2 : Codec[CommonFieldData] = codec2(false) } diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/CommonFieldDataWithPlacement.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/CommonFieldDataWithPlacement.scala new file mode 100644 index 00000000..790f7433 --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/CommonFieldDataWithPlacement.scala @@ -0,0 +1,55 @@ +// Copyright (c) 2017 PSForever +package net.psforever.packet.game.objectcreate + +import net.psforever.packet.Marshallable +import net.psforever.packet.game.PlanetSideGUID +import net.psforever.types.PlanetSideEmpire +import scodec.Codec +import scodec.codecs._ + +/** + * Data that is common to a number of game object serializations, plus position information + * @see `DroppedItemData` + * @param pos the location, orientation, and potential velocity of the object + * @param data the common fields + */ +final case class CommonFieldDataWithPlacement(pos : PlacementData, + data : CommonFieldData + ) extends ConstructorData { + override def bitsize : Long = pos.bitsize + data.bitsize +} + +object CommonFieldDataWithPlacement extends Marshallable[CommonFieldDataWithPlacement] { + /** + * Overloaded constructors. + * @return a `CommonFieldDataWithPlacement` object + */ + def apply(pos : PlacementData, faction : PlanetSideEmpire.Value) : CommonFieldDataWithPlacement = + CommonFieldDataWithPlacement(pos, CommonFieldData(faction)) + + def apply(pos : PlacementData, faction : PlanetSideEmpire.Value, unk : Int) : CommonFieldDataWithPlacement = + CommonFieldDataWithPlacement(pos, CommonFieldData(faction, unk)) + + def apply(pos : PlacementData, faction : PlanetSideEmpire.Value, unk : Int, player_guid : PlanetSideGUID) : CommonFieldDataWithPlacement = + CommonFieldDataWithPlacement(pos, CommonFieldData(faction, unk, player_guid)) + + def apply(pos : PlacementData, faction : PlanetSideEmpire.Value, destroyed : Boolean, unk : Int) : CommonFieldDataWithPlacement = + CommonFieldDataWithPlacement(pos, CommonFieldData(faction, destroyed, unk)) + + def apply(pos : PlacementData, faction : PlanetSideEmpire.Value, destroyed : Boolean, unk : Int, player_guid : PlanetSideGUID) : CommonFieldDataWithPlacement = + CommonFieldDataWithPlacement(pos, CommonFieldData(faction, destroyed, unk, player_guid)) + + def codec(extra : Boolean) : Codec[CommonFieldDataWithPlacement] = ( + ("pos" | PlacementData.codec) :: + CommonFieldData.codec(extra) + ).as[CommonFieldDataWithPlacement] + + implicit val codec : Codec[CommonFieldDataWithPlacement] = codec(false) + + def codec2(extra : Boolean) : Codec[CommonFieldDataWithPlacement] = ( + ("pos" | PlacementData.codec) :: + CommonFieldData.codec2(extra) + ).as[CommonFieldDataWithPlacement] + + implicit val codec2 : Codec[CommonFieldDataWithPlacement] = codec2(false) +} diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/CommonTerminalData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/CommonTerminalData.scala deleted file mode 100644 index 39dc42a1..00000000 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/CommonTerminalData.scala +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.packet.game.objectcreate - -import net.psforever.packet.Marshallable -import net.psforever.packet.game.PlanetSideGUID -import net.psforever.types.PlanetSideEmpire -import scodec.{Attempt, Codec, Err} -import scodec.codecs._ -import shapeless.{::, HNil} - -/** - * A representation of an object that can be interacted with when using a variety of terminals. - * This object is generally invisible. - * @param faction the faction that can access the terminal - * @param unk na - */ -final case class CommonTerminalData(faction : PlanetSideEmpire.Value, - unk : Int = 0 - ) extends ConstructorData { - override def bitsize : Long = 24L -} - -object CommonTerminalData extends Marshallable[CommonTerminalData] { - /** - * Overloaded constructor for a type of common terminal. - * @param cls the code for the type of object being constructed - * @param guid the GUID this object will be assigned - * @param parentSlot a parent-defined slot identifier that explains where the child is to be attached to the parent - * @param terminal the `CommonTerminalData` - * @return an `InternalSlot` object - */ - def apply(cls : Int, guid : PlanetSideGUID, parentSlot : Int, terminal : CommonTerminalData) : InternalSlot = - InternalSlot(cls, guid, parentSlot, terminal) - - implicit val codec : Codec[CommonTerminalData] = ( - ("faction" | PlanetSideEmpire.codec) :: - uint2L :: - ("unk" | uint2L) :: - uint(18) - ).exmap[CommonTerminalData] ( - { - case fac :: 0 :: unk :: 0 :: HNil => - Attempt.successful(CommonTerminalData(fac, unk)) - case _ => - Attempt.failure(Err("invalid terminal data format")) - }, - { - case CommonTerminalData(fac, unk) => - Attempt.successful(fac :: 0 :: unk :: 0 :: HNil) - } - ) -} diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/ConstructorData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/ConstructorData.scala index 6b91eb74..108d68d4 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/ConstructorData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/ConstructorData.scala @@ -16,30 +16,32 @@ abstract class ConstructorData extends StreamBitSize object ConstructorData { /** - * This pattern is intended to provide common conversion between all of the `Codec`s of the children of this class. - * The casting will be performed through use of `exmap` in the child class. - */ - type genericPattern = Option[ConstructorData] - - /** - * Transform a `Codec[T]` for object type `T` into `ConstructorData.genericPattern`. + * Transform a `Codec[T]` for object type `T` into `ConstructorData`. * @param objCodec a `Codec` that satisfies the transformation `Codec[T] -> T` * @param objType a `String` that explains what the object should be identified as in the `Err` message; * defaults to "object" * @tparam T a subclass of `ConstructorData` that indicates what type the object is - * @return `ConstructorData.genericPattern` + * @return `Codec[ConstructorData]` */ - def genericCodec[T <: ConstructorData](objCodec : Codec[T], objType : String = "object") : Codec[ConstructorData.genericPattern] = - objCodec.exmap[ConstructorData.genericPattern] ( - { - case x => - Attempt.successful(Some(x.asInstanceOf[ConstructorData])) - }, - { - case Some(x) => - Attempt.successful(x.asInstanceOf[T]) //why does this work? shouldn't type erasure be a problem? - case _ => - Attempt.failure(Err(s"can not encode as $objType data")) - } - ) + def apply[T <: ConstructorData](objCodec : Codec[T], objType : String = "object") : Codec[ConstructorData] = + objCodec.exmap[ConstructorData] ( + x => { + try { + Attempt.successful(x.asInstanceOf[ConstructorData]) + } + catch { + case ex : Exception => + Attempt.failure(Err(s"can not cast decode of $x to $objType - $ex")) + } + }, + x => { + try { + Attempt.successful(x.asInstanceOf[T]) //why does this work? shouldn't type erasure be a problem? + } + catch { + case ex : Exception => + Attempt.failure(Err(s"can not cast encode $x to $objType - $ex")) + } + } + ) } diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/ContainedTelepadDeployableData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/ContainedTelepadDeployableData.scala deleted file mode 100644 index 2d7ff06e..00000000 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/ContainedTelepadDeployableData.scala +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.packet.game.objectcreate - -import net.psforever.packet.Marshallable -import net.psforever.packet.game.PlanetSideGUID -import scodec.{Attempt, Codec, Err} -import scodec.codecs._ -import shapeless.{::, HNil} - -/** - * na - */ -final case class ContainedTelepadDeployableData(unk : Int, - router_guid : PlanetSideGUID) extends ConstructorData { - override def bitsize : Long = 59L -} - -object ContainedTelepadDeployableData extends Marshallable[ContainedTelepadDeployableData] { - implicit val codec : Codec[ContainedTelepadDeployableData] = ( - ("unk" | uint(7)) :: - ("router_guid" | PlanetSideGUID.codec) :: - uint16 :: - uint4 :: - uint16 - ).exmap[ContainedTelepadDeployableData] ( - { - case unk :: rguid :: 0 :: 8 :: 0 :: HNil => - Attempt.successful(ContainedTelepadDeployableData(unk, rguid)) - case _ :: _ :: _ :: _ :: _ :: HNil => - Attempt.failure(Err("invalid rek data format")) - }, - { - case ContainedTelepadDeployableData(unk, rguid) => - Attempt.successful(unk :: rguid :: 0 :: 8 :: 0 :: HNil) - } - ) -} diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/Cosmetics.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/Cosmetics.scala index da3f85b2..cd0ece4a 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/Cosmetics.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/Cosmetics.scala @@ -4,6 +4,25 @@ package net.psforever.packet.game.objectcreate import scodec.codecs._ import scodec.Codec +/** + * Values for the different specific customizations available as cosmetics.
+ * `NoHelmet` removes the current helmet on the reinforced exo-suit and the agile exo-suit; + * other cosmetics require `no_helmet` to be `true` before they can be seen; + * `NoHelmet` does not override `Beret` or `BrimmedCap`
+ * `Beret` player dons a beret
+ * `Sunglasses` player dons sunglasses
+ * `Earpiece` player dons an earpiece on the left
+ * `BrimmedCap` player dons a cap; + * the cap overrides the beret, if both are selected + */ +object PersonalStyle extends Enumeration { + val BrimmedCap = Value(1) + val Earpiece = Value(2) + val Sunglasses = Value(4) + val Beret = Value(8) + val NoHelmet = Value(16) +} + /** * The different cosmetics that a player can apply to their character model's head.
*
@@ -11,31 +30,99 @@ import scodec.Codec * These flags are only valid if the player has: * for `DetailedCharacterData`, achieved at least battle rank twenty-four (battle experience points greater than 2286230), * or, for `CharacterData`, achieved at least battle rank twenty-five (acquired their third uniform upgrade). - * `CharacterData`, as implied, will not display these options until one battle rank after they would have become available. - * @param no_helmet removes the current helmet on the reinforced exo-suit and the agile exo-suit; - * all other cosmetics require `no_helmet` to be `true` before they can be seen - * @param beret player dons a beret - * @param sunglasses player dons sunglasses - * @param earpiece player dons an earpiece on the left - * @param brimmed_cap player dons a cap; - * the cap overrides the beret, if both are selected - * @see `UniformStyle.ThirdUpgrade` + * `CharacterData`, as suggested, will not display these options until one battle rank after they would have become available. + * @param pstyles a value that indicates certain cosmetic features by bitwise math + * @see `UniformStyle` + * @see `PersonalStyleFeatures` */ -final case class Cosmetics(no_helmet : Boolean, - beret : Boolean, - sunglasses : Boolean, - earpiece : Boolean, - brimmed_cap : Boolean - ) extends StreamBitSize { +final case class Cosmetics(pstyles : Int) extends StreamBitSize { override def bitsize : Long = 5L + + /** + * Transform the accumulated bitwise cosmetic feature integer into a group of all valid cosmetic feature values. + * @return a group of all valid cosmetic feature values + */ + def Styles : Set[PersonalStyle.Value] = { + (for { + style <- PersonalStyle.values.toList + if (pstyles & style.id) == style.id + } yield style) toSet + } + + /** + * Allocate a cosmetic feature to an existing group of cosmetic feature values if that feature is not already a member.
+ * `Cosmetics` is an immutable object so a new object with the additional value must be created. + * @param pstyle the cosmetic feature value + * @return a new `Cosmetics` object, potentially including the new cosmetic feature + */ + def +(pstyle : PersonalStyle.Value) : Cosmetics = { + Cosmetics(pstyles | pstyle.id) + } + + /** + * Revoke a cosmetic feature from an existing group of cosmetic feature values if that feature is a member.
+ * * `Cosmetics` is an immutable object so a new object with the value removed must be created. + * @param pstyle the cosmetic feature value + * @return a new `Cosmetics` object, excluding the new cosmetic feature + */ + def -(pstyle : PersonalStyle.Value) : Cosmetics = { + Cosmetics(pstyles - (pstyles & pstyle.id)) + } + + /** + * Determine if this `Cosmetics` object contain the given cosmetic feature. + * @param pstyle the cosmetic feature value + * @return `true`, if the feature is included; `false`, otherwise + */ + def contains(pstyle : PersonalStyle.Value) : Boolean = (pstyles & pstyle.id) == pstyle.id } object Cosmetics { - implicit val codec : Codec[Cosmetics] = ( - ("no_helmet" | bool) :: - ("beret" | bool) :: - ("sunglasses" | bool) :: - ("earpiece" | bool) :: - ("brimmed_cap" | bool) - ).as[Cosmetics] + /** + * Overloaded constructor for `Cosmetics` that loads no option. + * @return a `Cosmetics` object + */ + def apply() : Cosmetics = Cosmetics(0) + + /** + * Overloaded constructor for `Cosmetics` that loads a single option. + * @param pstyle the cosmetic feature that will be valid + * @return a `Cosmetics` object + */ + def apply(pstyle : PersonalStyle.Value) : Cosmetics = Cosmetics(pstyle.id) + + /** + * Overloaded constructor for `Cosmetics` that loads all options listed. + * @param pstyle all of the cosmetic feature that will be valid + * @return a `Cosmetics` object + */ + def apply(pstyle : Set[PersonalStyle.Value]) : Cosmetics = { + Cosmetics(pstyle.foldLeft(0)(_ + _.id)) + } + + /** + * Overloaded constructor for `Cosmetics` that list all options as boolean values + * @param no_helmet removes the current helmet on the reinforced exo-suit and the agile exo-suit + * @param beret player dons a beret + * @param sunglasses player dons sunglasses + * @param earpiece player dons an earpiece on the left + * @param brimmed_cap player dons a cap + * @return a `Cosmetics` object + */ + def apply(no_helmet : Boolean, + beret : Boolean, + sunglasses : Boolean, + earpiece : Boolean, + brimmed_cap : Boolean) : Cosmetics = { + implicit def bool2int(b : Boolean) : Int = if(b) 1 else 0 + Cosmetics( + (no_helmet * 16) + + (beret * 8) + + (sunglasses * 4) + + (earpiece * 2) + + brimmed_cap + ) + } + + implicit val codec : Codec[Cosmetics] = uint(5).hlist.as[Cosmetics] } diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedACEData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedACEData.scala deleted file mode 100644 index 0c1ad166..00000000 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedACEData.scala +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.packet.game.objectcreate - -import net.psforever.packet.Marshallable -import scodec.{Attempt, Codec, Err} -import scodec.codecs._ -import shapeless.{::, HNil} - -/** - * A representation of an adaptive construction engine (ACE). - * This one-time-use item deploys a variety of utilities into the game environment. - * Has an advanced version internally called an `advanced_ace` and commonly called a Field Deployment Unit (FDU). - * @param unk na - */ -final case class DetailedACEData(unk : Int) extends ConstructorData { - override def bitsize : Long = 51L -} - -object DetailedACEData extends Marshallable[DetailedACEData] { - implicit val codec : Codec[DetailedACEData] = ( - ("unk" | uint4L) :: - uint4L :: - uintL(20) :: - uint4L :: - uint16L :: - uint(3) - ).exmap[DetailedACEData] ( - { - case code :: 8 :: 0 :: 2 :: 0 :: 4 :: HNil => - Attempt.successful(DetailedACEData(code)) - case _ => - Attempt.failure(Err("invalid ace data format")) - }, - { - case DetailedACEData(code) => - Attempt.successful(code :: 8 :: 0 :: 2 :: 0 :: 4 :: HNil) - } - ) -} diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedAmmoBoxData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedAmmoBoxData.scala index 794ccf23..f430de8a 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedAmmoBoxData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedAmmoBoxData.scala @@ -3,6 +3,7 @@ package net.psforever.packet.game.objectcreate import net.psforever.packet.Marshallable import net.psforever.packet.game.PlanetSideGUID +import net.psforever.types.PlanetSideEmpire import scodec.{Attempt, Codec, Err} import scodec.codecs._ import shapeless.{::, HNil} @@ -15,14 +16,17 @@ import shapeless.{::, HNil} * The maximum amount of ammunition that can be stored in a single box is 65535 units. * Regardless of the interface, however, the number will never be fully visible. * Only the first three digits or the first four digits may be represented. - * @param unk na + * @param data na * @param magazine the number of rounds available - * @see DetailedWeaponData + * @see `DetailedWeaponData` */ -final case class DetailedAmmoBoxData(unk : Int, +final case class DetailedAmmoBoxData(data : CommonFieldData, magazine : Int ) extends ConstructorData { - override def bitsize : Long = 40L + override def bitsize : Long = { + val dataSize = data.bitsize + 17L + dataSize + } } object DetailedAmmoBoxData extends Marshallable[DetailedAmmoBoxData] { @@ -37,22 +41,27 @@ object DetailedAmmoBoxData extends Marshallable[DetailedAmmoBoxData] { def apply(cls : Int, guid : PlanetSideGUID, parentSlot : Int, ammo : DetailedAmmoBoxData) : InternalSlot = new InternalSlot(cls, guid, parentSlot, ammo) + def apply(unk : Int, mag : Int) : DetailedAmmoBoxData = { + DetailedAmmoBoxData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, unk > 0, None, false, None, None, PlanetSideGUID(0)), mag + ) + } + implicit val codec : Codec[DetailedAmmoBoxData] = ( - uint4L :: - ("unk" | uint4L) :: // 8 - common - 4 - safe, 2 - stream misalignment, 1 - safe, 0 - common - uint(15) :: + ("data" | CommonFieldData.codec) :: ("magazine" | uint16L) :: bool ).exmap[DetailedAmmoBoxData] ( { - case 0xC :: unk :: 0 :: mag :: false :: HNil => - Attempt.successful(DetailedAmmoBoxData(unk, mag)) - case _ => - Attempt.failure(Err("invalid ammunition data format")) + case data :: mag :: false :: HNil => + Attempt.successful(DetailedAmmoBoxData(data, mag)) + + case data => + Attempt.failure(Err(s"invalid detailed ammunition data format - $data")) }, { - case DetailedAmmoBoxData(unk, mag) => - Attempt.successful(0xC :: unk :: 0 :: mag :: false:: HNil) + case DetailedAmmoBoxData(data, mag) => + Attempt.successful(data :: mag :: false:: HNil) } ) } diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedBoomerTriggerData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedBoomerTriggerData.scala deleted file mode 100644 index 3e4aebf7..00000000 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedBoomerTriggerData.scala +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.packet.game.objectcreate - -import net.psforever.packet.Marshallable -import scodec.{Attempt, Codec, Err} -import scodec.codecs._ -import shapeless.{::, HNil} - -/** - * A representation of the detonater utility that is created when putting down a Boomer with an ACE. - */ -final case class DetailedBoomerTriggerData() extends ConstructorData { - override def bitsize : Long = 51L -} - -object DetailedBoomerTriggerData extends Marshallable[DetailedBoomerTriggerData] { - implicit val codec : Codec[DetailedBoomerTriggerData] = ( - uint8L :: - uint(22) :: - bool :: //true - uint(17) :: - bool :: //true - uint2L - ).exmap[DetailedBoomerTriggerData] ( - { - case 0xC8 :: 0 :: true :: 0 :: true :: 0 :: HNil => - Attempt.successful(DetailedBoomerTriggerData()) - case _ :: _ :: _ :: _ :: _ :: _ :: HNil => - Attempt.failure(Err("invalid command detonater format")) - }, - { - case DetailedBoomerTriggerData() => - Attempt.successful(0xC8 :: 0 :: true :: 0 :: true :: 0 :: HNil) - } - ) -} diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedCommandDetonaterData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedCommandDetonaterData.scala index cd5c684b..7e50e19d 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedCommandDetonaterData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedCommandDetonaterData.scala @@ -7,32 +7,32 @@ import scodec.codecs._ import shapeless.{::, HNil} /** - * A representation of the command uplink device.
- * I don't know much about the command uplink device so someone else has to provide this commentary. + * A representation of the command uplink device. */ -final case class DetailedCommandDetonaterData(unk1 : Int = 8, - unk2 : Int = 0) extends ConstructorData { - override def bitsize : Long = 51L +final case class DetailedCommandDetonaterData(data : CommonFieldData) extends ConstructorData { + override def bitsize : Long = { + val dataSize = data.bitsize + 28L + dataSize + } } object DetailedCommandDetonaterData extends Marshallable[DetailedCommandDetonaterData] { implicit val codec : Codec[DetailedCommandDetonaterData] = ( - ("unk1" | uint4L) :: - ("unk2" | uint4L) :: - uint(20) :: - uint4L :: + ("data" | CommonFieldData.codec) :: + uint8 :: uint16 :: - uint(3) + uint4 ).exmap[DetailedCommandDetonaterData] ( { - case unk1 :: unk2 :: 0 :: 2 :: 0 :: 4 :: HNil => - Attempt.successful(DetailedCommandDetonaterData(unk1, unk2)) - case _ => - Attempt.failure(Err("invalid command detonator data format")) + case data :: 1 :: 0 :: 4 :: HNil => + Attempt.successful(DetailedCommandDetonaterData(data)) + + case data => + Attempt.failure(Err(s"invalid detailed command detonater data format - $data")) }, { - case DetailedCommandDetonaterData(unk1, unk2) => - Attempt.successful(unk1 :: unk2 :: 0 :: 2 :: 0 :: 4 :: HNil) + case DetailedCommandDetonaterData(data) => + Attempt.successful(data :: 1 :: 0 :: 4 :: HNil) } ) } diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedConstructionToolData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedConstructionToolData.scala new file mode 100644 index 00000000..5fc89bc0 --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedConstructionToolData.scala @@ -0,0 +1,37 @@ +// Copyright (c) 2018 PSForever +package net.psforever.packet.game.objectcreate + +import net.psforever.packet.Marshallable +import scodec.codecs._ +import scodec.{Attempt, Codec, Err} +import shapeless.{::, HNil} + +/** + * `DetailedACEData` - `data.faction` is faction affinity, `data.unk1` is `true` + * `DetailedBoomerTriggerData` - `data.faction` can be `NEUTRAL`, `data.unk1` is `true` + * `DetailedTelepadData` - `data.faction` can be `NEUTRAL`, `data.jammered` is the router's GUID + */ +final case class DetailedConstructionToolData(data : CommonFieldData) extends ConstructorData { + override def bitsize : Long = 28L + data.bitsize +} + +object DetailedConstructionToolData extends Marshallable[DetailedConstructionToolData] { + implicit val codec : Codec[DetailedConstructionToolData] = ( + ("data" | CommonFieldData.codec(false)) :: + uint8 :: + uint(18) :: + uint2 + ).exmap[DetailedConstructionToolData] ( + { + case data :: 1 :: 1 :: _ :: HNil => + Attempt.successful(DetailedConstructionToolData(data)) + case data => + Attempt.failure(Err(s"invalid detailed construction tool data format - $data")) + }, + { + case DetailedConstructionToolData(data) => + Attempt.successful(data :: 1 :: 1 :: 0 :: HNil) + } + ) +} + diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedLockerContainerData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedLockerContainerData.scala index cae75cd8..beda8df1 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedLockerContainerData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedLockerContainerData.scala @@ -3,6 +3,7 @@ package net.psforever.packet.game.objectcreate import net.psforever.packet.Marshallable import net.psforever.packet.game.PlanetSideGUID +import net.psforever.types.PlanetSideEmpire import scodec.codecs._ import scodec.{Attempt, Codec, Err} import shapeless.{::, HNil} @@ -14,10 +15,10 @@ import shapeless.{::, HNil} * the actual container for them, in grid format, can only be accessed by interacting with locker objects in the game world. * Items are generally added and removed in the same way as with any other opened inventory. * Unlike other inventories, however, locker space is personal to an avatar and can not be accessed by other players. - * @param unk na + * @param data na * @param inventory the items in this inventory */ -final case class DetailedLockerContainerData(unk : Int, +final case class DetailedLockerContainerData(data : CommonFieldData, inventory : Option[InventoryData] ) extends ConstructorData { override def bitsize : Long = { @@ -34,7 +35,7 @@ object DetailedLockerContainerData extends Marshallable[DetailedLockerContainerD * @return a `DetailedLockerContainerData` object */ def apply(unk : Int) : DetailedLockerContainerData = - new DetailedLockerContainerData(unk, None) + new DetailedLockerContainerData(CommonFieldData(PlanetSideEmpire.NEUTRAL, unk), None) /** * Overloaded constructor for creating `DetailedLockerContainerData` containing known items. @@ -43,7 +44,7 @@ object DetailedLockerContainerData extends Marshallable[DetailedLockerContainerD * @return a `DetailedLockerContainerData` object */ def apply(unk : Int, inventory : List[InternalSlot]) : DetailedLockerContainerData = - new DetailedLockerContainerData(unk, Some(InventoryData(inventory))) + new DetailedLockerContainerData(CommonFieldData(PlanetSideEmpire.NEUTRAL, unk), Some(InventoryData(inventory))) /** * Overloaded constructor for creating `DetailedLockerContainerData` while masking use of `InternalSlot`. @@ -57,27 +58,26 @@ object DetailedLockerContainerData extends Marshallable[DetailedLockerContainerD new InternalSlot(cls, guid, parentSlot, locker) implicit val codec : Codec[DetailedLockerContainerData] = ( - uint4L :: - ("unk" | uint4L) :: // 8 - common - 4 - safe, 2 - stream misalignment, 1 - safe, 0 - common - uint(15) :: + ("data" | CommonFieldData.codec) :: uint16L :: //always 1 optional(bool, InventoryData.codec_detailed) ).exmap[DetailedLockerContainerData] ( { - case 0xC :: unk :: 0 :: 1 :: None :: HNil => - Attempt.successful(DetailedLockerContainerData(unk, None)) + case data :: 1 :: None :: HNil => + Attempt.successful(DetailedLockerContainerData(data, None)) - case 0xC :: unk :: 0 :: 1 :: Some(inv) :: HNil => - Attempt.successful(DetailedLockerContainerData(unk, Some(inv))) - case _ => - Attempt.failure(Err(s"invalid locker container data format")) + case data :: 1 :: Some(inv) :: HNil => + Attempt.successful(DetailedLockerContainerData(data, Some(inv))) + + case data => + Attempt.failure(Err(s"invalid detailed locker container data format - $data")) }, { - case DetailedLockerContainerData(unk, None) => - Attempt.successful(0xC :: unk :: 0 :: 1 :: None :: HNil) + case DetailedLockerContainerData(data, None) => + Attempt.successful(data :: 1 :: None :: HNil) - case DetailedLockerContainerData(unk, Some(inv)) => - Attempt.successful(0xC :: unk :: 0 :: 1 :: Some(inv) :: HNil) + case DetailedLockerContainerData(data, Some(inv)) => + Attempt.successful(data :: 1 :: Some(inv) :: HNil) } ) } diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedPlayerData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedPlayerData.scala index c4778dba..e4788bb5 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedPlayerData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedPlayerData.scala @@ -60,7 +60,7 @@ object DetailedPlayerData extends Marshallable[DetailedPlayerData] { * technically, always `DrawnSlot.None`, but the field is preserved to maintain similarity * @return a `DetailedPlayerData` object */ - def apply(basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Option[Int])=>DetailedCharacterData, inventory : InventoryData, drawn_slot : DrawnSlot.Value) : DetailedPlayerData = { + def apply(basic_appearance : Int=>CharacterAppearanceData, character_data : Option[Int]=>DetailedCharacterData, inventory : InventoryData, drawn_slot : DrawnSlot.Value) : DetailedPlayerData = { val appearance = basic_appearance(5) DetailedPlayerData(None, appearance, character_data(appearance.altModelBit), Some(inventory), drawn_slot)(false) } @@ -75,7 +75,7 @@ object DetailedPlayerData extends Marshallable[DetailedPlayerData] { * technically, always `DrawnSlot.None`, but the field is preserved to maintain similarity * @return a `DetailedPlayerData` object */ - def apply(basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Option[Int])=>DetailedCharacterData, drawn_slot : DrawnSlot.Value) : DetailedPlayerData = { + def apply(basic_appearance : Int=>CharacterAppearanceData, character_data : Option[Int]=>DetailedCharacterData, drawn_slot : DrawnSlot.Value) : DetailedPlayerData = { val appearance = basic_appearance(5) DetailedPlayerData(None, appearance, character_data(appearance.altModelBit), None, drawn_slot)(false) } @@ -91,7 +91,7 @@ object DetailedPlayerData extends Marshallable[DetailedPlayerData] { * @param drawn_slot the holster that is depicted as exposed, or "drawn" * @return a `DetailedPlayerData` object */ - def apply(pos : PlacementData, basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Option[Int])=>DetailedCharacterData, inventory : InventoryData, drawn_slot : DrawnSlot.Value) : DetailedPlayerData = { + def apply(pos : PlacementData, basic_appearance : Int=>CharacterAppearanceData, character_data : Option[Int]=>DetailedCharacterData, inventory : InventoryData, drawn_slot : DrawnSlot.Value) : DetailedPlayerData = { val appearance = basic_appearance(PlayerData.PaddingOffset(Some(pos))) DetailedPlayerData(Some(pos), appearance, character_data(appearance.altModelBit), Some(inventory), drawn_slot)(true) } @@ -106,7 +106,7 @@ object DetailedPlayerData extends Marshallable[DetailedPlayerData] { * @param drawn_slot the holster that is depicted as exposed, or "drawn" * @return a `DetailedPlayerData` object */ - def apply(pos : PlacementData, basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Option[Int])=>DetailedCharacterData, drawn_slot : DrawnSlot.Value) : DetailedPlayerData = { + def apply(pos : PlacementData, basic_appearance : Int=>CharacterAppearanceData, character_data : Option[Int]=>DetailedCharacterData, drawn_slot : DrawnSlot.Value) : DetailedPlayerData = { val appearance = basic_appearance(PlayerData.PaddingOffset(Some(pos))) DetailedPlayerData(Some(pos), appearance, character_data(appearance.altModelBit), None, drawn_slot)(true) } diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedREKData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedREKData.scala index c4c19e62..583e320a 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedREKData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedREKData.scala @@ -11,34 +11,36 @@ import shapeless.{::, HNil} * This data will help construct the "tool" called a Remote Electronics Kit.
*
* Of note is the first portion of the data which resembles the `DetailedWeaponData` format. - * @param unk1 na - * @param unk2 na + * @param data na + * @param unk na */ -final case class DetailedREKData(unk1 : Int, - unk2 : Int = 0 +final case class DetailedREKData(data : CommonFieldData, + unk : Int = 0 ) extends ConstructorData { - override def bitsize : Long = 67L + override def bitsize : Long = { + val dataSize = data.bitsize + 43L + dataSize + } } object DetailedREKData extends Marshallable[DetailedREKData] { implicit val codec : Codec[DetailedREKData] = ( - ("unk" | uint4L) :: - uint4L :: - uintL(20) :: - uint4L :: + ("data" | CommonFieldData.codec2) :: + uint8 :: uint16L :: uint4L :: - ("unk2" | uintL(15)) + ("unk" | uint8) :: + uint(7) ).exmap[DetailedREKData] ( { - case code :: 8 :: 0 :: 2 :: 0 :: 8 :: unk2 :: HNil => - Attempt.successful(DetailedREKData(code, unk2)) - case _ => - Attempt.failure(Err("invalid rek data format")) + case data :: 2 :: 0 :: 8 :: unk :: 0 :: HNil => + Attempt.successful(DetailedREKData(data, unk)) + case data => + Attempt.failure(Err(s"invalid detailed rek data format - $data")) }, { - case DetailedREKData(code, unk2) => - Attempt.successful(code :: 8 :: 0 :: 2 :: 0 :: 8 :: unk2 :: HNil) + case DetailedREKData(data, unk) => + Attempt.successful(data :: 2 :: 0 :: 8 :: unk :: 0 :: HNil) } ) } diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedTelepadData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedTelepadData.scala deleted file mode 100644 index 230fb666..00000000 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedTelepadData.scala +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.packet.game.objectcreate - -import net.psforever.packet.Marshallable -import net.psforever.packet.game.PlanetSideGUID -import scodec.{Attempt, Codec, Err} -import scodec.codecs._ -import shapeless.{::, HNil} - -/** - * A representation of the telepad portion of `ObjectCreateDetailedMessage` packet data. - * This data will help construct the "cosntruction tool" - * that can be obtained from the Router vehicle - the Router telepad. - * It issued to construct a bidirectional teleportation point associated with a Router if that Router is deployed. - * @param unk na - * @param router_guid the Router - */ -final case class DetailedTelepadData(unk : Int, router_guid : Option[PlanetSideGUID]) extends ConstructorData { - override def bitsize : Long = { - val rguidSize = if(router_guid.nonEmpty) 16 else 0 - 51L + rguidSize - } -} - -object DetailedTelepadData extends Marshallable[DetailedTelepadData] { - def apply(unk : Int) : DetailedTelepadData = DetailedTelepadData(unk, None) - - def apply(unk : Int, router_guid : PlanetSideGUID) : DetailedTelepadData = DetailedTelepadData(unk, Some(router_guid)) - - implicit val codec : Codec[DetailedTelepadData] = ( - ("unk" | uint(6)) :: - optional(bool, "router_guid" | PlanetSideGUID.codec) :: - uint(24) :: - uint(18) :: - uint2 - ).exmap[DetailedTelepadData] ( - { - case unk :: rguid :: 1 :: 1 :: 0 :: HNil => - Attempt.successful(DetailedTelepadData(unk, rguid)) - case _ => - Attempt.failure(Err("invalid detailed telepad format")) - }, - { - case DetailedTelepadData(unk, rguid) => - Attempt.successful(unk :: rguid :: 1 :: 1 :: 0 :: HNil) - } - ) -} diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedWeaponData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedWeaponData.scala index ba55ad81..cc9e997c 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedWeaponData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedWeaponData.scala @@ -3,6 +3,7 @@ package net.psforever.packet.game.objectcreate import net.psforever.packet.Marshallable import net.psforever.packet.game.PlanetSideGUID +import net.psforever.types.PlanetSideEmpire import scodec.{Attempt, Codec, Err} import scodec.codecs._ import shapeless.{::, HNil} @@ -14,29 +15,21 @@ import shapeless.{::, HNil} * The data for the weapons nests information for the default (current) type and number of ammunition in its magazine. * This ammunition data essentially is the weapon's magazines as numbered slots. * An "expected" number of ammunition slot data can be passed into the function. - * @param unk1 na - * @param unk2 na + * @param data field common to multiple game objects + * @param fire_mode the current fire mode * @param ammo data regarding the currently loaded ammunition type(s) and quantity(ies) - * @param mag_capacity implicit; - * the total number of concurrently-loaded ammunition types allowed in this weapon; - * concurrent ammunition does not need to be unloaded to be switched; - * defaults to 1; - * 0 is invalid; - * -1 or less ignores the imposed checks * @see `DetailedAmmoBoxData` * @see `WeaponData` */ -final case class DetailedWeaponData(unk1 : Int, - unk2 : Int, +final case class DetailedWeaponData(data : CommonFieldData, fire_mode : Int, - ammo : List[InternalSlot] - )(implicit val mag_capacity : Int = 1) extends ConstructorData { + ammo : List[InternalSlot], + unk : Boolean = false + ) extends ConstructorData { override def bitsize : Long = { - var bitsize : Long = 0L - for(o <- ammo) { - bitsize += o.bitsize - } - 61L + bitsize //51 + 10 (from InventoryData) + ammo + val dataSize = data.bitsize + val ammoSize : Long = ammo.foldLeft(0L)(_ + _.bitsize) + 38L + dataSize + ammoSize //28 + 10 (from InventoryData) + ammo } } @@ -51,8 +44,23 @@ object DetailedWeaponData extends Marshallable[DetailedWeaponData] { * @param ammo the constructor data for the ammunition * @return a `DetailedWeaponData` object */ - def apply(unk1 : Int, unk2 : Int, cls : Int, guid : PlanetSideGUID, parentSlot : Int, ammo : DetailedAmmoBoxData) : DetailedWeaponData = - new DetailedWeaponData(unk1, unk2, 0, InternalSlot(cls, guid, parentSlot, ammo) :: Nil) + def apply(unk1 : Int, unk2 : Int, cls : Int, guid : PlanetSideGUID, parentSlot : Int, ammo : DetailedAmmoBoxData) : DetailedWeaponData = { + DetailedWeaponData( + CommonFieldData( + PlanetSideEmpire(unk1 & 3), + false, + false, + (unk2 & 8) == 8, + None, + (unk2 & 4) == 4, + None, + None, + PlanetSideGUID(0) + ), + 0, + List(InternalSlot(cls, guid, parentSlot, ammo)) + ) + } /** @@ -65,71 +73,58 @@ object DetailedWeaponData extends Marshallable[DetailedWeaponData] { * @param ammo the constructor data for the ammunition * @return a `DetailedWeaponData` object */ - def apply(unk1 : Int, unk2 : Int, fire_mode : Int, cls : Int, guid : PlanetSideGUID, parentSlot : Int, ammo : DetailedAmmoBoxData) : DetailedWeaponData = - new DetailedWeaponData(unk1, unk2, fire_mode, InternalSlot(cls, guid, parentSlot, ammo) :: Nil) + def apply(unk1 : Int, unk2 : Int, fire_mode : Int, cls : Int, guid : PlanetSideGUID, parentSlot : Int, ammo : DetailedAmmoBoxData) : DetailedWeaponData = { + DetailedWeaponData( + CommonFieldData( + PlanetSideEmpire(unk1 & 3), + false, + false, + (unk2 & 8) == 8, + None, + (unk2 & 4) == 4, + None, + None, + PlanetSideGUID(0) + ), + fire_mode, + List(InternalSlot(cls, guid, parentSlot, ammo)) + ) + } - /** - * A `Codec` for `DetailedWeaponData` - * @param mag_capacity the total number of concurrently-loaded ammunition types allowed in this weapon; - * defaults to 1 - * @return a `WeaponData` object or a `BitVector` - */ - def codec(mag_capacity : Int = 1) : Codec[DetailedWeaponData] = ( - ("unk1" | uint(3)) :: - bool :: //weapon refuses to shoot if set (not weapons lock?) - ("unk2" | uint4L) :: //8 - common; 4 - jammers weapons; 2 - weapon breaks; 1, 0 - safe - uint24 :: - uint(12) :: - ("fire_mode" | uint(3)) :: //TODO size? - uint(3) :: - ("ammo" | InventoryData.codec_detailed) :: - bool + implicit val codec : Codec[DetailedWeaponData] = ( + ("data" | CommonFieldData.codec) :: + uint8 :: + uint8 :: + ("fire_mode" | uint8) :: + uint2 :: + optional(bool, "ammo" | InventoryData.codec_detailed) :: + ("unk" | bool) ).exmap[DetailedWeaponData] ( { - case unk1 :: false :: unk2 :: 2 :: 0 :: fmode :: 3 :: InventoryData(ammo) :: false :: HNil => + case data :: 1 :: 0 :: fmode :: 1 :: Some(InventoryData(ammo)) :: unk :: HNil => val magSize = ammo.size - if(mag_capacity == 0 || magSize == 0) { + if(magSize == 0) { Attempt.failure(Err("weapon must decode some ammunition")) } - else if(mag_capacity > 0 && magSize != mag_capacity) { - Attempt.failure(Err(s"weapon decodes too much or too little ammunition - actual $magSize, expected $mag_capacity")) - } else { - Attempt.successful(DetailedWeaponData(unk1, unk2, fmode, ammo)(magSize)) + Attempt.successful(DetailedWeaponData(data, fmode, ammo, unk)) } - case _ => - Attempt.failure(Err("invalid weapon data format")) + case data => + Attempt.failure(Err(s"invalid weapon data format - $data")) }, { - case obj @ DetailedWeaponData(unk1, unk2, fmode, ammo) => + case DetailedWeaponData(data, fmode, ammo, unk) => val magSize = ammo.size - val magCapacity = obj.mag_capacity - if(mag_capacity == 0 || magCapacity == 0 || magSize == 0) { + if(magSize == 0) { Attempt.failure(Err("weapon must encode some ammunition")) } - else if(magCapacity < 0 || mag_capacity < 0) { - Attempt.successful(unk1 :: false :: unk2 :: 2 :: 0 :: fmode :: 3 :: InventoryData(ammo) :: false :: HNil) + else if(magSize >= 255) { + Attempt.failure(Err("weapon encodes too much ammunition (255+ types!)")) } else { - if(magCapacity != mag_capacity) { - Attempt.failure(Err(s"different encoding expectations for amount of ammunition - actual $magCapacity, expected $mag_capacity")) - } - else if(magSize != mag_capacity) { - Attempt.failure(Err(s"weapon encodes wrong amount of ammunition - actual $magSize, expected $mag_capacity")) - } - else if(magSize >= 255) { - Attempt.failure(Err("weapon encodes too much ammunition (255+ types!)")) - } - else { - Attempt.successful(unk1 :: false :: unk2 :: 2 :: 0 :: fmode :: 3 :: InventoryData(ammo) :: false :: HNil) - } + Attempt.successful(data :: 1 :: 0 :: fmode :: 1 :: Some(InventoryData(ammo)) :: unk :: HNil) } - - case _ => - Attempt.failure(Err("invalid weapon data format")) } ) - - implicit val codec : Codec[DetailedWeaponData] = codec() } diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/DroppedItemData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/DroppedItemData.scala index e65cab16..267d926d 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/DroppedItemData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/DroppedItemData.scala @@ -17,7 +17,7 @@ final case class DroppedItemData[T <: ConstructorData](pos : PlacementData, obj object DroppedItemData { /** - * Transform `DroppedItemData[T]` for object type `T` into `ConstructorData.genericPattern`.
+ * Transform `DroppedItemData[T]` for object type `T` into `ConstructorData`.
*
* This function eliminates the need to have a separate "DroppedFooData" class for every object "Foo." * Two functions normally perform this transformation: an `implicit` `codec` used in a `genericCodec`. @@ -32,10 +32,10 @@ object DroppedItemData { * @param objType a `String` that explains what the object should be identified as in the log; * defaults to "object" * @tparam T a subclass of `ConstructorData` that indicates what type the object is - * @return `ConstructorData.genericPattern` - * @see `ConstructorData.genericPattern` (function) + * @return `Codec[ConstructorData]` + * @see `ConstructorData` (function) */ - def genericCodec[T <: ConstructorData](objCodec : Codec[T], objType : String = "object") : Codec[ConstructorData.genericPattern] = ( + def apply[T <: ConstructorData](objCodec : Codec[T], objType : String = "object") : Codec[ConstructorData] = ( ("pos" | PlacementData.codec) :: ("obj" | objCodec) ).xmap[DroppedItemData[T]] ( @@ -47,16 +47,24 @@ object DroppedItemData { case DroppedItemData(pos, obj) => pos :: obj :: HNil } - ).exmap[ConstructorData.genericPattern] ( - { - case x => - Attempt.successful(Some(x.asInstanceOf[ConstructorData])) + ).exmap[ConstructorData] ( + x => { + try { + Attempt.successful(x.asInstanceOf[ConstructorData]) + } + catch { + case ex : Exception => + Attempt.failure(Err(s"can not cast decode of $x to dropped $objType - $ex")) + } }, - { - case Some(x) => - Attempt.successful(x.asInstanceOf[DroppedItemData[T]]) - case _ => - Attempt.failure(Err(s"can not encode dropped $objType data")) + x => { + try { + Attempt.successful(x.asInstanceOf[DroppedItemData[T]]) //why does this work? shouldn't type erasure be a problem? + } + catch { + case ex : Exception => + Attempt.failure(Err(s"can not cast encode $x to dropped $objType - $ex")) + } } ) } diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/DroppodData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/DroppodData.scala index 9ad295b0..6d7006a9 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/DroppodData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/DroppodData.scala @@ -3,7 +3,7 @@ package net.psforever.packet.game.objectcreate import net.psforever.packet.Marshallable import scodec.codecs._ -import scodec.{Attempt, Codec} +import scodec.{Attempt, Codec, Err} import shapeless.{::, HNil} /** @@ -31,7 +31,7 @@ import shapeless.{::, HNil} * @see `DroppodLaunchRequestMessage` * @see `DroppodLaunchResponseMessage` */ -final case class DroppodData(basic : CommonFieldData, +final case class DroppodData(basic : CommonFieldDataWithPlacement, burn : Boolean = false, health : Int = 255 ) extends ConstructorData { @@ -43,7 +43,7 @@ final case class DroppodData(basic : CommonFieldData, object DroppodData extends Marshallable[DroppodData] { implicit val codec : Codec[DroppodData] = ( - ("basic" | CommonFieldData.codec) :: + ("basic" | CommonFieldDataWithPlacement.codec) :: bool :: ("health" | uint8L) :: //health uintL(5) :: //0x0 @@ -56,6 +56,9 @@ object DroppodData extends Marshallable[DroppodData] { case basic :: false :: health :: 0 :: 0xF :: 0 :: boosters :: false :: HNil => val burn : Boolean = boosters == 0 Attempt.successful(DroppodData(basic, burn, health)) + + case data => + Attempt.failure(Err(s"invalid droppod data format - $data")) }, { case DroppodData(basic, burn, health) => diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/HandheldData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/HandheldData.scala new file mode 100644 index 00000000..9cd6e5e0 --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/HandheldData.scala @@ -0,0 +1,46 @@ +// Copyright (c) 2017 PSForever +package net.psforever.packet.game.objectcreate + +import net.psforever.packet.Marshallable +import scodec.{Attempt, Codec, Err} +import scodec.codecs._ +import shapeless.{::, HNil} + +/** + * A representation of a number of simplified objects that the user can hold in their hands, including: + * the advanced construction engine (`ace`), + * the field deployable unit (`advanced_ace`), + * the boomer trigger apparatus, + * the remote telepad (not deployed), + * the flail laser pointer (`flail_targeting_laser`), + * and the command uplink device (`command_detonater`). + * @param data fields that are common to this game object + * - v4 - not used, i.e., the simple format `CommonFieldData` object is employed + * - v5 - for the telepad, this field is expected to be the GUID of the associated Router + */ +final case class HandheldData(data : CommonFieldData) extends ConstructorData { + override def bitsize : Long = { + 11L + data.bitsize + } +} + +object HandheldData extends Marshallable[HandheldData] { + implicit val codec : Codec[HandheldData] = ( + ("data" | CommonFieldData.codec) :: + uint4 :: + uint4 :: + uint(3) + ).exmap[HandheldData] ( + { + case data :: 0 :: 0 :: 0 :: HNil => + Attempt.successful(HandheldData(data)) + + case data => + Attempt.failure(Err(s"invalid handheld tool data format - $data")) + }, + { + case HandheldData(data) => + Attempt.successful(data :: 0 :: 0 :: 0 :: HNil) + } + ) +} diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/InternalSlot.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/InternalSlot.scala index 012dacb7..c338490f 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/InternalSlot.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/InternalSlot.scala @@ -45,12 +45,12 @@ object InternalSlot { } ).xmap[InternalSlot] ( { - case cls :: guid :: slot :: Some(obj) :: HNil => + case cls :: guid :: slot :: obj :: HNil => InternalSlot(cls, guid, slot, obj) }, { case InternalSlot(cls, guid, slot, obj) => - cls :: guid :: slot :: Some(obj) :: HNil + cls :: guid :: slot :: obj :: HNil } ) @@ -65,12 +65,12 @@ object InternalSlot { } ).xmap[InternalSlot] ( { - case cls :: guid :: slot :: Some(obj) :: HNil => + case cls :: guid :: slot :: obj :: HNil => InternalSlot(cls, guid, slot, obj) }, { case InternalSlot(cls, guid, slot, obj) => - cls :: guid :: slot :: Some(obj) :: HNil + cls :: guid :: slot :: obj :: HNil } ) } diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/LargeDeployableData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/LargeDeployableData.scala index e2a63545..d332f428 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/LargeDeployableData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/LargeDeployableData.scala @@ -7,19 +7,9 @@ import scodec.{Attempt, Codec, Err} import shapeless.{::, HNil} /** - * A representation of the Spitfire-based small turrets deployed using an adaptive construction engine.
- *
- * The turret may contain substructure defining a weapon is a turret weapon contained within the turret itself. - * Furthermore, that turret-like weapon is loaded with turret-like ammunition. - * In other words, this outer turret can be considered a weapons platform for the inner turret weapon.
- *
- * If the turret has no `health`, it is rendered as destroyed. - * If the turret has no internal weapon, it is safest rendered as destroyed. - * @param deploy data common to objects spawned by the (advanced) adaptive construction engine - * @param health the amount of health the object has, as a percentage of a filled bar - * @param internals data regarding the mounted weapon + * This class currently is unused but is based on the `SmallTurretData` `Codec` class. */ -final case class LargeDeployableData(deploy : SmallDeployableData, +final case class LargeDeployableData(deploy : CommonFieldDataWithPlacement, health : Int, internals : Option[InventoryData] = None ) extends ConstructorData { @@ -37,7 +27,7 @@ final case class LargeDeployableData(deploy : SmallDeployableData, object LargeDeployableData extends Marshallable[LargeDeployableData] { implicit val codec : Codec[LargeDeployableData] = ( - ("deploy" | SmallDeployableData.codec) :: + ("deploy" | CommonFieldDataWithPlacement.codec2) :: ("health" | uint8L) :: uintL(7) :: uint4L :: @@ -54,8 +44,9 @@ object LargeDeployableData extends Marshallable[LargeDeployableData] { } Attempt.successful(LargeDeployableData(deploy, newHealth, newInternals)) - case _ => - Attempt.failure(Err("invalid large deployable data format")) + + case data => + Attempt.failure(Err(s"invalid large deployable data format - $data")) }, { case LargeDeployableData(deploy, health, internals) => diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/LockerContainerData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/LockerContainerData.scala index 3cba5574..6bae06b1 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/LockerContainerData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/LockerContainerData.scala @@ -12,27 +12,39 @@ import shapeless.{::, HNil} * For whatever reason, these "lockers" are typically placed at the origin coordinates. * @param inventory the items inside this locker */ -final case class LockerContainerData(inventory : InventoryData) extends ConstructorData { - override def bitsize : Long = 105L + inventory.bitsize //81u + 2u + 21u + 1u +final case class LockerContainerData(inventory : Option[InventoryData]) extends ConstructorData { + override def bitsize : Long = { + val base : Long = 105L + (inventory match { + case Some(inv) => inv.bitsize + case None => 0L + }) + base //81u + 2u + 21u + 1u + } } object LockerContainerData extends Marshallable[LockerContainerData] { + def apply() : LockerContainerData = new LockerContainerData(None) + + def apply(inventory : InventoryData) : LockerContainerData = new LockerContainerData(Some(inventory)) + + def apply(inventory : List[InternalSlot]) : LockerContainerData = new LockerContainerData(Some(InventoryData(inventory))) + implicit val codec : Codec[LockerContainerData] = ( - uint32 :: uint32 :: uint(17) :: //can substitute with PlacementData, if ever necessary + uint32 :: uint32 :: uint(17) :: uint2L :: uint(21) :: - bool :: - InventoryData.codec + ("inventory" | optional(bool, InventoryData.codec)) ).exmap[LockerContainerData] ( { - case 0 :: 0 :: 0 :: 3 :: 0 :: true :: inv :: HNil => - Attempt.successful(LockerContainerData(inv)) - case _ => - Attempt.failure(Err("invalid locker container format")) + case 0 :: 0 :: 0 :: 3 :: 0 :: inventory :: HNil => + Attempt.successful(LockerContainerData(inventory)) + + case data => + Attempt.failure(Err(s"invalid locker container data format - $data")) }, { - case LockerContainerData(inv) => - Attempt.successful(0L :: 0L :: 0 :: 3 :: 0 :: true :: inv :: HNil) + case LockerContainerData(inventory) => + Attempt.successful(0L :: 0L :: 0 :: 3 :: 0 :: inventory :: HNil) } ) } diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/ObjectClass.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/ObjectClass.scala index c4766570..776d367c 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/ObjectClass.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/ObjectClass.scala @@ -296,9 +296,20 @@ object ObjectClass { final val portable_manned_turret_vs = 688 //projectiles final val hunter_seeker_missile_projectile = 405 + final val meteor_common = 543 + final val meteor_projectile_b_large = 544 + final val meteor_projectile_b_medium = 545 + final val meteor_projectile_b_small = 546 + final val meteor_projectile_large = 547 + final val meteor_projectile_medium = 548 + final val meteor_projectile_small = 549 + final val oicw_little_buddy = 601 final val oicw_projectile = 602 + final val radiator_cload = 717 + final val sparrow_projectile = 792 final val starfire_projectile = 831 final val striker_missile_targeting_projectile = 841 + final val wasp_rocket_projectile = 1001 //vehicles final val apc_destroyed = 65 final val apc_tr = 67 //juggernaut @@ -394,289 +405,289 @@ object ObjectClass { * @return the `Codec` that handles the format of data for that particular item class, or a failing `Codec` * @see `ConstructorData` */ - def selectDataDetailedCodec(objClass : Int) : Codec[ConstructorData.genericPattern] = + def selectDataDetailedCodec(objClass : Int) : Codec[ConstructorData] = (objClass : @switch) match { //ammunition - case ObjectClass.bullet_105mm => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_12mm => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_150mm => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_15mm => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_20mm => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_25mm => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_35mm => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_75mm => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_9mm => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_9mm_AP => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.ancient_ammo_combo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.ancient_ammo_vehicle => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.anniversary_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.aphelion_immolation_cannon_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.aphelion_laser_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.aphelion_plasma_rocket_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.aphelion_ppa_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.aphelion_starfire_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.armor_canister => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.armor_siphon_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.bolt => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.burster_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.colossus_100mm_cannon_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.colossus_burster_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.colossus_chaingun_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.colossus_cluster_bomb_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.colossus_tank_cannon_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.comet_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.dualcycler_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.energy_cell => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.energy_gun_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.falcon_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.firebird_missile => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.flamethrower_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.flux_cannon_thresher_battery => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.fluxpod_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.frag_cartridge => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.frag_grenade_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.gauss_cannon_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.grenade => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.health_canister => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.heavy_grenade_mortar => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.heavy_rail_beam_battery => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.hellfire_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.hunter_seeker_missile => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.jammer_cartridge => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.jammer_grenade_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.lancer_cartridge => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.liberator_bomb => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.maelstrom_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.melee_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.mine => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.mine_sweeper_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.ntu_siphon_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.oicw_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.pellet_gun_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.peregrine_dual_machine_gun_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.peregrine_mechhammer_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.peregrine_particle_cannon_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.peregrine_rocket_pod_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.peregrine_sparrow_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.phalanx_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.phoenix_missile => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.plasma_cartridge => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.plasma_grenade_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.pounder_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.pulse_battery => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.quasar_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.reaver_rocket => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.rocket => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.scattercannon_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.shotgun_shell => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.shotgun_shell_AP => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.six_shooter_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.skyguard_flak_cannon_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.sparrow_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.spitfire_aa_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.spitfire_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.starfire_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.striker_missile_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.trek_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.upgrade_canister => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.wasp_gun_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.wasp_rocket_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.winchester_ammo => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.bullet_105mm => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.bullet_12mm => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.bullet_150mm => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.bullet_15mm => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.bullet_20mm => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.bullet_25mm => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.bullet_35mm => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.bullet_75mm => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.bullet_9mm => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.bullet_9mm_AP => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.ancient_ammo_combo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.ancient_ammo_vehicle => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.anniversary_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.aphelion_immolation_cannon_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.aphelion_laser_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.aphelion_plasma_rocket_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.aphelion_ppa_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.aphelion_starfire_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.armor_canister => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.armor_siphon_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.bolt => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.burster_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.colossus_100mm_cannon_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.colossus_burster_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.colossus_chaingun_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.colossus_cluster_bomb_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.colossus_tank_cannon_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.comet_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.dualcycler_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.energy_cell => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.energy_gun_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.falcon_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.firebird_missile => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.flamethrower_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.flux_cannon_thresher_battery => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.fluxpod_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.frag_cartridge => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.frag_grenade_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.gauss_cannon_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.grenade => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.health_canister => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.heavy_grenade_mortar => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.heavy_rail_beam_battery => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.hellfire_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.hunter_seeker_missile => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.jammer_cartridge => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.jammer_grenade_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.lancer_cartridge => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.liberator_bomb => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.maelstrom_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.melee_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.mine => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.mine_sweeper_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.ntu_siphon_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.oicw_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.pellet_gun_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.peregrine_dual_machine_gun_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.peregrine_mechhammer_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.peregrine_particle_cannon_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.peregrine_rocket_pod_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.peregrine_sparrow_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.phalanx_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.phoenix_missile => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.plasma_cartridge => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.plasma_grenade_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.pounder_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.pulse_battery => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.quasar_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.reaver_rocket => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.rocket => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.scattercannon_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.shotgun_shell => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.shotgun_shell_AP => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.six_shooter_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.skyguard_flak_cannon_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.sparrow_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.spitfire_aa_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.spitfire_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.starfire_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.striker_missile_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.trek_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.upgrade_canister => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.wasp_gun_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.wasp_rocket_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.winchester_ammo => ConstructorData(DetailedAmmoBoxData.codec, "ammo box") //weapons - case ObjectClass.beamer => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.cannon_dropship_20mm => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.anniversary_gun => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.anniversary_guna => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.anniversary_gunb => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.apc_ballgun_l => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.apc_ballgun_r => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.apc_weapon_systema => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.apc_weapon_systemb => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.apc_weapon_systemc => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.apc_weapon_systemc_nc => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.apc_weapon_systemc_tr => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.apc_weapon_systemc_vs => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.apc_weapon_systemd => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.apc_weapon_systemd_nc => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.apc_weapon_systemd_tr => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.apc_weapon_systemd_vs => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.aphelion_immolation_cannon => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.aphelion_laser => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.aphelion_laser_left => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.aphelion_laser_right => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.aphelion_plasma_rocket_pod => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.aphelion_ppa => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.aphelion_ppa_left => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.aphelion_ppa_right => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.aphelion_starfire => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.aphelion_starfire_left => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.aphelion_starfire_right => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.aurora_weapon_systema => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.aurora_weapon_systemb => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.battlewagon_weapon_systema => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.battlewagon_weapon_systemb => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.battlewagon_weapon_systemc => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.battlewagon_weapon_systemd => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.bolt_driver => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.chainblade => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.colossus_burster => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.colossus_burster_left => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.colossus_burster_right => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.colossus_chaingun => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.colossus_chaingun_left => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.colossus_chaingun_right => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.colossus_cluster_bomb_pod => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.colossus_dual_100mm_cannons => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.colossus_tank_cannon => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.colossus_tank_cannon_left => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.colossus_tank_cannon_right => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.cycler => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.dropship_rear_turret => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.energy_gun => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.energy_gun_nc => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.energy_gun_tr => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.energy_gun_vs => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.flail_weapon => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.flamethrower => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.flechette => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.flux_cannon_thresher => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.fluxpod => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.forceblade => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.fragmentation_grenade => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.fury_weapon_systema => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.galaxy_gunship_cannon => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.galaxy_gunship_gun => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.galaxy_gunship_tailgun => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.gauss => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.gauss_cannon => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.grenade_launcher_marauder => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.heavy_rail_beam_magrider => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.heavy_sniper => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.hellfire => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.hunterseeker => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.ilc9 => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.isp => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.jammer_grenade => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.katana => ConstructorData.genericCodec(DetailedWeaponData.codec(2), "weapon") - case ObjectClass.lancer => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.lasher => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.liberator_25mm_cannon => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.liberator_bomb_bay => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.liberator_weapon_system => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.lightgunship_weapon_system => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.lightning_weapon_system => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.maelstrom => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.magcutter => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.mediumtransport_weapon_systemA => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.mediumtransport_weapon_systemB => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.mini_chaingun => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.oicw => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.nchev_falcon => ConstructorData.genericCodec(DetailedWeaponData.codec(-1), "weapon") - case ObjectClass.nchev_scattercannon => ConstructorData.genericCodec(DetailedWeaponData.codec(-1), "weapon") - case ObjectClass.nchev_sparrow => ConstructorData.genericCodec(DetailedWeaponData.codec(-1), "weapon") -// case ObjectClass.particle_beam_magrider => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.peregrine_dual_machine_gun => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.peregrine_dual_machine_gun_left => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.peregrine_dual_machine_gun_right => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.peregrine_dual_rocket_pods => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.peregrine_mechhammer => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.peregrine_mechhammer_left => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.peregrine_mechhammer_right => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.peregrine_particle_cannon => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.peregrine_sparrow => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.peregrine_sparrow_left => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.peregrine_sparrow_right => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.phalanx_avcombo => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.phalanx_flakcombo => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.phalanx_sgl_hevgatcan => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.phoenix => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.prowler_weapon_systemA => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.prowler_weapon_systemB => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.plasma_grenade => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.pulsar => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.pulsed_particle_accelerator => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.punisher => ConstructorData.genericCodec(DetailedWeaponData.codec(2), "weapon") -// case ObjectClass.quadassault_weapon_system => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.r_shotgun => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.radiator => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.repeater => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.rocklet => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.rotarychaingun_mosquito => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.scythe => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.skyguard_weapon_system => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.spiker => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.spitfire_aa_weapon => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.spitfire_weapon => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.striker => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.suppressor => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.thumper => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.thunderer_weapon_systema => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.thunderer_weapon_systemb => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.trhev_burster => ConstructorData.genericCodec(DetailedWeaponData.codec(-1), "weapon") - case ObjectClass.trhev_dualcycler => ConstructorData.genericCodec(DetailedWeaponData.codec(-1), "weapon") - case ObjectClass.trhev_pounder => ConstructorData.genericCodec(DetailedWeaponData.codec(-1), "weapon") -// case ObjectClass.vanguard_weapon_system => ConstructorData.genericCodec(DetailedWeaponData.codec(2), "weapon") -// case ObjectClass.vanu_sentry_turret_weapon => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.vshev_comet => ConstructorData.genericCodec(DetailedWeaponData.codec(-1), "weapon") - case ObjectClass.vshev_starfire => ConstructorData.genericCodec(DetailedWeaponData.codec(-1), "weapon") - case ObjectClass.vshev_quasar => ConstructorData.genericCodec(DetailedWeaponData.codec(-1), "weapon") -// case ObjectClass.vulture_bomb_bay => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.vulture_nose_weapon_system => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.vulture_tail_cannon => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.wasp_weapon_system => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") + case ObjectClass.beamer => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.cannon_dropship_20mm => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.anniversary_gun => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.anniversary_guna => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.anniversary_gunb => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.apc_ballgun_l => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.apc_ballgun_r => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.apc_weapon_systema => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.apc_weapon_systemb => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.apc_weapon_systemc => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.apc_weapon_systemc_nc => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.apc_weapon_systemc_tr => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.apc_weapon_systemc_vs => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.apc_weapon_systemd => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.apc_weapon_systemd_nc => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.apc_weapon_systemd_tr => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.apc_weapon_systemd_vs => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.aphelion_immolation_cannon => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.aphelion_laser => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.aphelion_laser_left => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.aphelion_laser_right => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.aphelion_plasma_rocket_pod => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.aphelion_ppa => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.aphelion_ppa_left => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.aphelion_ppa_right => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.aphelion_starfire => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.aphelion_starfire_left => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.aphelion_starfire_right => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.aurora_weapon_systema => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.aurora_weapon_systemb => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.battlewagon_weapon_systema => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.battlewagon_weapon_systemb => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.battlewagon_weapon_systemc => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.battlewagon_weapon_systemd => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.bolt_driver => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.chainblade => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.colossus_burster => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.colossus_burster_left => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.colossus_burster_right => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.colossus_chaingun => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.colossus_chaingun_left => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.colossus_chaingun_right => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.colossus_cluster_bomb_pod => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.colossus_dual_100mm_cannons => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.colossus_tank_cannon => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.colossus_tank_cannon_left => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.colossus_tank_cannon_right => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.cycler => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.dropship_rear_turret => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.energy_gun => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.energy_gun_nc => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.energy_gun_tr => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.energy_gun_vs => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.flail_weapon => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.flamethrower => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.flechette => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.flux_cannon_thresher => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.fluxpod => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.forceblade => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.fragmentation_grenade => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.fury_weapon_systema => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.galaxy_gunship_cannon => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.galaxy_gunship_gun => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.galaxy_gunship_tailgun => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.gauss => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.gauss_cannon => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.grenade_launcher_marauder => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.heavy_rail_beam_magrider => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.heavy_sniper => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.hellfire => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.hunterseeker => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.ilc9 => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.isp => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.jammer_grenade => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.katana => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.lancer => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.lasher => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.liberator_25mm_cannon => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.liberator_bomb_bay => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.liberator_weapon_system => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.lightgunship_weapon_system => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.lightning_weapon_system => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.maelstrom => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.magcutter => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.mediumtransport_weapon_systemA => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.mediumtransport_weapon_systemB => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.mini_chaingun => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.oicw => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.nchev_falcon => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.nchev_scattercannon => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.nchev_sparrow => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.particle_beam_magrider => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.peregrine_dual_machine_gun => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.peregrine_dual_machine_gun_left => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.peregrine_dual_machine_gun_right => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.peregrine_dual_rocket_pods => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.peregrine_mechhammer => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.peregrine_mechhammer_left => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.peregrine_mechhammer_right => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.peregrine_particle_cannon => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.peregrine_sparrow => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.peregrine_sparrow_left => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.peregrine_sparrow_right => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.phalanx_avcombo => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.phalanx_flakcombo => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.phalanx_sgl_hevgatcan => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.phoenix => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.prowler_weapon_systemA => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.prowler_weapon_systemB => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.plasma_grenade => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.pulsar => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.pulsed_particle_accelerator => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.punisher => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.quadassault_weapon_system => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.r_shotgun => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.radiator => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.repeater => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.rocklet => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.rotarychaingun_mosquito => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.scythe => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.skyguard_weapon_system => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.spiker => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.spitfire_aa_weapon => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.spitfire_weapon => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.striker => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.suppressor => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.thumper => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.thunderer_weapon_systema => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.thunderer_weapon_systemb => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.trhev_burster => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.trhev_dualcycler => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.trhev_pounder => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.vanguard_weapon_system => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.vanu_sentry_turret_weapon => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.vshev_comet => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.vshev_starfire => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.vshev_quasar => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.vulture_bomb_bay => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.vulture_nose_weapon_system => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.vulture_tail_cannon => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.wasp_weapon_system => ConstructorData(DetailedWeaponData.codec, "weapon") //other weapons - case ObjectClass.ace_deployable => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.advanced_missile_launcher_t => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.cannon_20mm => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.cannon_75mm => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.cannon_deliverer_20mm => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.cannon_dropship_l_20mm => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.chaingun_12mm => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.chaingun_15mm => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.chaingun_p => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.cycler_v2 => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.cycler_v3 => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.cycler_v4 => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.dynomite => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.frag_grenade => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.generic_grenade => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.lightning_75mm => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.mine_sweeper => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.pellet_gun => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") -// case ObjectClass.phantasm_12mm_machinegun => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.six_shooter => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") - case ObjectClass.winchester => ConstructorData.genericCodec(DetailedWeaponData.codec, "weapon") + case ObjectClass.ace_deployable => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.advanced_missile_launcher_t => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.cannon_20mm => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.cannon_75mm => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.cannon_deliverer_20mm => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.cannon_dropship_l_20mm => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.chaingun_12mm => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.chaingun_15mm => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.chaingun_p => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.cycler_v2 => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.cycler_v3 => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.cycler_v4 => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.dynomite => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.frag_grenade => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.generic_grenade => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.lightning_75mm => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.mine_sweeper => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.pellet_gun => ConstructorData(DetailedWeaponData.codec, "weapon") +// case ObjectClass.phantasm_12mm_machinegun => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.six_shooter => ConstructorData(DetailedWeaponData.codec, "weapon") + case ObjectClass.winchester => ConstructorData(DetailedWeaponData.codec, "weapon") //medkits - case ObjectClass.medkit => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.super_armorkit => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.super_medkit => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") - case ObjectClass.super_staminakit => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "ammo box") + case ObjectClass.medkit => ConstructorData(DetailedAmmoBoxData.codec, "medkit") + case ObjectClass.super_armorkit => ConstructorData(DetailedAmmoBoxData.codec, "repair kit") + case ObjectClass.super_medkit => ConstructorData(DetailedAmmoBoxData.codec, "super medkit") + case ObjectClass.super_staminakit => ConstructorData(DetailedAmmoBoxData.codec, "stamina kit") //tools - case ObjectClass.applicator => ConstructorData.genericCodec(DetailedWeaponData.codec, "tool") - case ObjectClass.bank => ConstructorData.genericCodec(DetailedWeaponData.codec, "tool") - case ObjectClass.command_detonater => ConstructorData.genericCodec(DetailedCommandDetonaterData.codec, "tool") - case ObjectClass.flail_targeting_laser => ConstructorData.genericCodec(DetailedCommandDetonaterData.codec, "tool") - case ObjectClass.medicalapplicator => ConstructorData.genericCodec(DetailedWeaponData.codec, "tool") - case ObjectClass.nano_dispenser => ConstructorData.genericCodec(DetailedWeaponData.codec, "tool") - case ObjectClass.remote_electronics_kit => ConstructorData.genericCodec(DetailedREKData.codec, "tool") - case ObjectClass.trek => ConstructorData.genericCodec(DetailedWeaponData.codec, "tool") + case ObjectClass.applicator => ConstructorData(DetailedWeaponData.codec, "tool") + case ObjectClass.bank => ConstructorData(DetailedWeaponData.codec, "tool") + case ObjectClass.command_detonater => ConstructorData(DetailedCommandDetonaterData.codec, "tool") + case ObjectClass.flail_targeting_laser => ConstructorData(DetailedCommandDetonaterData.codec, "tool") + case ObjectClass.medicalapplicator => ConstructorData(DetailedWeaponData.codec, "tool") + case ObjectClass.nano_dispenser => ConstructorData(DetailedWeaponData.codec, "tool") + case ObjectClass.remote_electronics_kit => ConstructorData(DetailedREKData.codec, "tool") + case ObjectClass.trek => ConstructorData(DetailedWeaponData.codec, "tool") //ace deployable - case ObjectClass.ace => ConstructorData.genericCodec(DetailedACEData.codec, "ace") - case ObjectClass.advanced_ace => ConstructorData.genericCodec(DetailedACEData.codec, "advanced ace") - case ObjectClass.router_telepad => ConstructorData.genericCodec(DetailedTelepadData.codec, "router telepad") - case ObjectClass.boomer_trigger => ConstructorData.genericCodec(DetailedBoomerTriggerData.codec, "boomer trigger") + case ObjectClass.ace => ConstructorData(DetailedConstructionToolData.codec, "ace") + case ObjectClass.advanced_ace => ConstructorData(DetailedConstructionToolData.codec, "advanced ace") + case ObjectClass.router_telepad => ConstructorData(DetailedConstructionToolData.codec, "router telepad") + case ObjectClass.boomer_trigger => ConstructorData(DetailedConstructionToolData.codec, "boomer trigger") //other - case ObjectClass.avatar => ConstructorData.genericCodec(DetailedPlayerData.codec(false), "avatar") - case ObjectClass.locker_container => ConstructorData.genericCodec(DetailedLockerContainerData.codec, "locker container") + case ObjectClass.avatar => ConstructorData(DetailedPlayerData.codec(false), "avatar") + case ObjectClass.locker_container => ConstructorData(DetailedLockerContainerData.codec, "locker container") //failure case case _ => defaultFailureCodec(objClass) } - def selectDataDroppedDetailedCodec(objClass : Int) : Codec[ConstructorData.genericPattern] = + def selectDataDroppedDetailedCodec(objClass : Int) : Codec[ConstructorData] = (objClass : @switch) match { //special cases - case ObjectClass.avatar => ConstructorData.genericCodec(DetailedPlayerData.codec(true), "avatar") + case ObjectClass.avatar => ConstructorData(DetailedPlayerData.codec(true), "avatar") //defer to other codec selection case _ => selectDataDetailedCodec(objClass) } @@ -690,291 +701,296 @@ object ObjectClass { * @return the `Codec` that handles the format of data for that particular item class, or a failing `Codec` * @see `ConstructorData` */ - def selectDataCodec(objClass : Int) : Codec[ConstructorData.genericPattern] = + def selectDataCodec(objClass : Int) : Codec[ConstructorData] = (objClass : @switch) match { //ammunition - case ObjectClass.bullet_105mm => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_12mm => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_150mm => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_15mm => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_20mm => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_25mm => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_35mm => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_75mm => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_9mm => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_9mm_AP => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.ancient_ammo_combo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.ancient_ammo_vehicle => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.anniversary_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.aphelion_immolation_cannon_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.aphelion_laser_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.aphelion_plasma_rocket_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.aphelion_ppa_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.aphelion_starfire_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.armor_canister => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.armor_siphon_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.bolt => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.burster_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.colossus_100mm_cannon_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.colossus_burster_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.colossus_chaingun_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.colossus_cluster_bomb_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.colossus_tank_cannon_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.comet_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.dualcycler_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.energy_cell => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.energy_gun_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.falcon_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.firebird_missile => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.flamethrower_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.flux_cannon_thresher_battery => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.fluxpod_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.frag_cartridge => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.frag_grenade_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.gauss_cannon_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.grenade => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.health_canister => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.heavy_grenade_mortar => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.heavy_rail_beam_battery => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.hellfire_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.hunter_seeker_missile => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.jammer_cartridge => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.jammer_grenade_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.lancer_cartridge => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.liberator_bomb => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.maelstrom_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.melee_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.mine => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.mine_sweeper_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.ntu_siphon_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.oicw_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.pellet_gun_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.peregrine_dual_machine_gun_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.peregrine_mechhammer_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.peregrine_particle_cannon_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.peregrine_rocket_pod_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.peregrine_sparrow_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.phalanx_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.phoenix_missile => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.plasma_cartridge => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.plasma_grenade_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.pounder_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.pulse_battery => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.quasar_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.reaver_rocket => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.rocket => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.scattercannon_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.shotgun_shell => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.shotgun_shell_AP => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.six_shooter_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.skyguard_flak_cannon_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.sparrow_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.spitfire_aa_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.spitfire_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.starfire_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.striker_missile_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.trek_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.upgrade_canister => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.wasp_gun_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.wasp_rocket_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.winchester_ammo => ConstructorData.genericCodec(AmmoBoxData.codec, "ammo box") + case ObjectClass.bullet_105mm => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.bullet_12mm => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.bullet_150mm => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.bullet_15mm => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.bullet_20mm => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.bullet_25mm => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.bullet_35mm => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.bullet_75mm => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.bullet_9mm => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.bullet_9mm_AP => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.ancient_ammo_combo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.ancient_ammo_vehicle => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.anniversary_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.aphelion_immolation_cannon_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.aphelion_laser_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.aphelion_plasma_rocket_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.aphelion_ppa_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.aphelion_starfire_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.armor_canister => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.armor_siphon_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.bolt => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.burster_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.colossus_100mm_cannon_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.colossus_burster_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.colossus_chaingun_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.colossus_cluster_bomb_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.colossus_tank_cannon_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.comet_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.dualcycler_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.energy_cell => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.energy_gun_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.falcon_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.firebird_missile => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.flamethrower_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.flux_cannon_thresher_battery => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.fluxpod_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.frag_cartridge => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.frag_grenade_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.gauss_cannon_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.grenade => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.health_canister => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.heavy_grenade_mortar => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.heavy_rail_beam_battery => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.hellfire_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.hunter_seeker_missile => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.jammer_cartridge => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.jammer_grenade_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.lancer_cartridge => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.liberator_bomb => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.maelstrom_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.melee_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.mine => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.mine_sweeper_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.ntu_siphon_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.oicw_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.pellet_gun_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.peregrine_dual_machine_gun_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.peregrine_mechhammer_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.peregrine_particle_cannon_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.peregrine_rocket_pod_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.peregrine_sparrow_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.phalanx_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.phoenix_missile => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.plasma_cartridge => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.plasma_grenade_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.pounder_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.pulse_battery => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.quasar_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.reaver_rocket => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.rocket => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.scattercannon_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.shotgun_shell => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.shotgun_shell_AP => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.six_shooter_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.skyguard_flak_cannon_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.sparrow_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.spitfire_aa_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.spitfire_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.starfire_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.striker_missile_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.trek_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.upgrade_canister => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.wasp_gun_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.wasp_rocket_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") + case ObjectClass.winchester_ammo => ConstructorData(CommonFieldData.codec2, "ammo box") //weapons - case ObjectClass.beamer => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.anniversary_gun => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.anniversary_guna => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.anniversary_gunb => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.apc_ballgun_l => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.apc_ballgun_r => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.apc_weapon_systema => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.apc_weapon_systemb => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.apc_weapon_systemc => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.apc_weapon_systemc_nc => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.apc_weapon_systemc_tr => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.apc_weapon_systemc_vs => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.apc_weapon_systemd => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.apc_weapon_systemd_nc => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.apc_weapon_systemd_tr => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.apc_weapon_systemd_vs => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.aphelion_immolation_cannon => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.aphelion_laser => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.aphelion_laser_left => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.aphelion_laser_right => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.aphelion_plasma_rocket_pod => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.aphelion_ppa => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.aphelion_ppa_left => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.aphelion_ppa_right => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.aphelion_starfire => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.aphelion_starfire_left => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.aphelion_starfire_right => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.aurora_weapon_systema => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.aurora_weapon_systemb => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.battlewagon_weapon_systema => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.battlewagon_weapon_systemb => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.battlewagon_weapon_systemc => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.battlewagon_weapon_systemd => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.bolt_driver => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.chainblade => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.chaingun_p => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.colossus_burster => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.colossus_burster_left => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.colossus_burster_right => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.colossus_chaingun => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.colossus_chaingun_left => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.colossus_chaingun_right => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.colossus_cluster_bomb_pod => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.colossus_dual_100mm_cannons => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.colossus_tank_cannon => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.colossus_tank_cannon_left => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.colossus_tank_cannon_right => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.cycler => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.dropship_rear_turret => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.energy_gun_nc => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.energy_gun_tr => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.energy_gun_vs => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.flail_weapon => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.flamethrower => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.flechette => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.flux_cannon_thresher => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.fluxpod => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.forceblade => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.fragmentation_grenade => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.fury_weapon_systema => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.galaxy_gunship_cannon => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.galaxy_gunship_gun => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.galaxy_gunship_tailgun => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.gauss => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.gauss_cannon => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.grenade_launcher_marauder => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.heavy_rail_beam_magrider => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.heavy_sniper => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.hellfire => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.hunterseeker => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.ilc9 => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.isp => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.jammer_grenade => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.katana => ConstructorData.genericCodec(WeaponData.codec(2), "weapon") - case ObjectClass.lancer => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.lasher => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.liberator_25mm_cannon => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.liberator_bomb_bay => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.liberator_weapon_system => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.lightgunship_weapon_system => ConstructorData.genericCodec(WeaponData.codec(2), "weapon") - case ObjectClass.lightning_weapon_system => ConstructorData.genericCodec(WeaponData.codec(2), "weapon") - case ObjectClass.maelstrom => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.magcutter => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.mediumtransport_weapon_systemA => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.mediumtransport_weapon_systemB => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.mini_chaingun => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.nchev_falcon => ConstructorData.genericCodec(WeaponData.codec(-1), "weapon") - case ObjectClass.nchev_scattercannon => ConstructorData.genericCodec(WeaponData.codec(-1), "weapon") - case ObjectClass.nchev_sparrow => ConstructorData.genericCodec(WeaponData.codec(-1), "weapon") - case ObjectClass.oicw => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.particle_beam_magrider => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.pellet_gun => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.peregrine_dual_machine_gun => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.peregrine_dual_machine_gun_left => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.peregrine_dual_machine_gun_right => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.peregrine_dual_rocket_pods => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.peregrine_mechhammer => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.peregrine_mechhammer_left => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.peregrine_mechhammer_right => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.peregrine_particle_cannon => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.peregrine_sparrow => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.peregrine_sparrow_left => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.peregrine_sparrow_right => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.phalanx_avcombo => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.phalanx_flakcombo => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.phalanx_sgl_hevgatcan => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.phoenix => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.plasma_grenade => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.prowler_weapon_systemA => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.prowler_weapon_systemB => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.pulsar => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.pulsed_particle_accelerator => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.punisher => ConstructorData.genericCodec(WeaponData.codec(2), "weapon") - case ObjectClass.quadassault_weapon_system => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.r_shotgun => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.radiator => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.repeater => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.rocklet => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.rotarychaingun_mosquito => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.scythe => ConstructorData.genericCodec(WeaponData.codec(2), "weapon") - case ObjectClass.skyguard_weapon_system => ConstructorData.genericCodec(WeaponData.codec(2), "weapon") - case ObjectClass.spiker => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.spitfire_aa_weapon => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.spitfire_weapon => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.striker => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.suppressor => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.thumper => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.thunderer_weapon_systema => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.thunderer_weapon_systemb => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.trhev_burster => ConstructorData.genericCodec(WeaponData.codec(-1), "weapon") - case ObjectClass.trhev_dualcycler => ConstructorData.genericCodec(WeaponData.codec(-1), "weapon") - case ObjectClass.trhev_pounder => ConstructorData.genericCodec(WeaponData.codec(-1), "weapon") - case ObjectClass.vanguard_weapon_system => ConstructorData.genericCodec(WeaponData.codec(2), "weapon") - case ObjectClass.vanu_sentry_turret_weapon => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.vshev_comet => ConstructorData.genericCodec(WeaponData.codec(-1), "weapon") - case ObjectClass.vshev_quasar => ConstructorData.genericCodec(WeaponData.codec(-1), "weapon") - case ObjectClass.vshev_starfire => ConstructorData.genericCodec(WeaponData.codec(-1), "weapon") - case ObjectClass.vulture_bomb_bay => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.vulture_nose_weapon_system => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.vulture_tail_cannon => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.wasp_weapon_system => ConstructorData.genericCodec(WeaponData.codec(2), "weapon") + case ObjectClass.beamer => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.anniversary_gun => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.anniversary_guna => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.anniversary_gunb => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.apc_ballgun_l => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.apc_ballgun_r => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.apc_weapon_systema => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.apc_weapon_systemb => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.apc_weapon_systemc => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.apc_weapon_systemc_nc => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.apc_weapon_systemc_tr => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.apc_weapon_systemc_vs => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.apc_weapon_systemd => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.apc_weapon_systemd_nc => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.apc_weapon_systemd_tr => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.apc_weapon_systemd_vs => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.aphelion_immolation_cannon => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.aphelion_laser => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.aphelion_laser_left => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.aphelion_laser_right => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.aphelion_plasma_rocket_pod => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.aphelion_ppa => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.aphelion_ppa_left => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.aphelion_ppa_right => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.aphelion_starfire => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.aphelion_starfire_left => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.aphelion_starfire_right => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.aurora_weapon_systema => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.aurora_weapon_systemb => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.battlewagon_weapon_systema => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.battlewagon_weapon_systemb => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.battlewagon_weapon_systemc => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.battlewagon_weapon_systemd => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.bolt_driver => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.chainblade => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.chaingun_p => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.colossus_burster => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.colossus_burster_left => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.colossus_burster_right => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.colossus_chaingun => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.colossus_chaingun_left => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.colossus_chaingun_right => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.colossus_cluster_bomb_pod => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.colossus_dual_100mm_cannons => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.colossus_tank_cannon => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.colossus_tank_cannon_left => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.colossus_tank_cannon_right => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.cycler => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.dropship_rear_turret => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.energy_gun_nc => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.energy_gun_tr => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.energy_gun_vs => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.flail_weapon => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.flamethrower => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.flechette => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.flux_cannon_thresher => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.fluxpod => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.forceblade => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.fragmentation_grenade => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.fury_weapon_systema => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.galaxy_gunship_cannon => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.galaxy_gunship_gun => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.galaxy_gunship_tailgun => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.gauss => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.gauss_cannon => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.grenade_launcher_marauder => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.heavy_rail_beam_magrider => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.heavy_sniper => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.hellfire => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.hunterseeker => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.ilc9 => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.isp => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.jammer_grenade => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.katana => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.lancer => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.lasher => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.liberator_25mm_cannon => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.liberator_bomb_bay => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.liberator_weapon_system => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.lightgunship_weapon_system => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.lightning_weapon_system => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.maelstrom => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.magcutter => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.mediumtransport_weapon_systemA => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.mediumtransport_weapon_systemB => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.mini_chaingun => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.nchev_falcon => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.nchev_scattercannon => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.nchev_sparrow => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.oicw => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.particle_beam_magrider => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.pellet_gun => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.peregrine_dual_machine_gun => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.peregrine_dual_machine_gun_left => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.peregrine_dual_machine_gun_right => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.peregrine_dual_rocket_pods => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.peregrine_mechhammer => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.peregrine_mechhammer_left => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.peregrine_mechhammer_right => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.peregrine_particle_cannon => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.peregrine_sparrow => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.peregrine_sparrow_left => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.peregrine_sparrow_right => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.phalanx_avcombo => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.phalanx_flakcombo => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.phalanx_sgl_hevgatcan => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.phoenix => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.plasma_grenade => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.prowler_weapon_systemA => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.prowler_weapon_systemB => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.pulsar => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.pulsed_particle_accelerator => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.punisher => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.quadassault_weapon_system => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.r_shotgun => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.radiator => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.repeater => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.rocklet => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.rotarychaingun_mosquito => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.scythe => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.skyguard_weapon_system => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.spiker => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.spitfire_aa_weapon => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.spitfire_weapon => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.striker => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.suppressor => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.thumper => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.thunderer_weapon_systema => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.thunderer_weapon_systemb => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.trhev_burster => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.trhev_dualcycler => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.trhev_pounder => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.vanguard_weapon_system => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.vanu_sentry_turret_weapon => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.vshev_comet => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.vshev_quasar => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.vshev_starfire => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.vulture_bomb_bay => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.vulture_nose_weapon_system => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.vulture_tail_cannon => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.wasp_weapon_system => ConstructorData(WeaponData.codec, "weapon") //other weapons - case ObjectClass.ace_deployable => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.advanced_missile_launcher_t => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.cannon_20mm => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.cannon_75mm => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.cannon_deliverer_20mm => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.cannon_dropship_l_20mm => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.cannon_dropship_20mm => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.chaingun_12mm => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.chaingun_15mm => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.cycler_v2 => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.cycler_v3 => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.cycler_v4 => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.dynomite => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.energy_gun => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.frag_grenade => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.generic_grenade => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.lightning_75mm => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.mine_sweeper => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.phantasm_12mm_machinegun => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.six_shooter => ConstructorData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.winchester => ConstructorData.genericCodec(WeaponData.codec, "weapon") + case ObjectClass.ace_deployable => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.advanced_missile_launcher_t => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.cannon_20mm => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.cannon_75mm => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.cannon_deliverer_20mm => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.cannon_dropship_l_20mm => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.cannon_dropship_20mm => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.chaingun_12mm => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.chaingun_15mm => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.cycler_v2 => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.cycler_v3 => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.cycler_v4 => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.dynomite => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.energy_gun => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.frag_grenade => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.generic_grenade => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.lightning_75mm => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.mine_sweeper => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.phantasm_12mm_machinegun => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.six_shooter => ConstructorData(WeaponData.codec, "weapon") + case ObjectClass.winchester => ConstructorData(WeaponData.codec, "weapon") + //medkits + case ObjectClass.medkit => ConstructorData(CommonFieldData.codec2, "medkit") + case ObjectClass.super_armorkit => ConstructorData(CommonFieldData.codec2, "repair kit") + case ObjectClass.super_medkit => ConstructorData(CommonFieldData.codec2, "super medkit") + case ObjectClass.super_staminakit => ConstructorData(CommonFieldData.codec2, "stamina kit") //tools - case ObjectClass.applicator => ConstructorData.genericCodec(WeaponData.codec, "tool") - case ObjectClass.bank => ConstructorData.genericCodec(WeaponData.codec, "tool") - case ObjectClass.command_detonater => ConstructorData.genericCodec(CommandDetonaterData.codec, "tool") - case ObjectClass.flail_targeting_laser => ConstructorData.genericCodec(CommandDetonaterData.codec, "tool") - case ObjectClass.medicalapplicator => ConstructorData.genericCodec(WeaponData.codec, "tool") - case ObjectClass.nano_dispenser => ConstructorData.genericCodec(WeaponData.codec, "tool") - case ObjectClass.remote_electronics_kit => ConstructorData.genericCodec(REKData.codec, "tool") - case ObjectClass.trek => ConstructorData.genericCodec(WeaponData.codec, "tool") + case ObjectClass.applicator => ConstructorData(WeaponData.codec, "tool") + case ObjectClass.bank => ConstructorData(WeaponData.codec, "tool") + case ObjectClass.command_detonater => ConstructorData(HandheldData.codec, "tool") + case ObjectClass.flail_targeting_laser => ConstructorData(HandheldData.codec, "tool") + case ObjectClass.medicalapplicator => ConstructorData(WeaponData.codec, "tool") + case ObjectClass.nano_dispenser => ConstructorData(WeaponData.codec, "tool") + case ObjectClass.remote_electronics_kit => ConstructorData(REKData.codec, "tool") + case ObjectClass.trek => ConstructorData(WeaponData.codec, "tool") //deployables - case ObjectClass.ace => ConstructorData.genericCodec(ACEData.codec, "ace") - case ObjectClass.advanced_ace => ConstructorData.genericCodec(ACEData.codec, "advanced ace") - case ObjectClass.router_telepad => ConstructorData.genericCodec(TelepadData.codec, "router telepad") - case ObjectClass.router_telepad_deployable => ConstructorData.genericCodec(ContainedTelepadDeployableData.codec, "router telepad") - case ObjectClass.boomer_trigger => ConstructorData.genericCodec(BoomerTriggerData.codec, "boomer trigger") + case ObjectClass.ace => ConstructorData(HandheldData.codec, "ace") + case ObjectClass.advanced_ace => ConstructorData(HandheldData.codec, "advanced ace") + case ObjectClass.router_telepad => ConstructorData(HandheldData.codec, "router telepad") + case ObjectClass.router_telepad_deployable => ConstructorData(TelepadDeployableData.codec, "router telepad") + case ObjectClass.boomer_trigger => ConstructorData(HandheldData.codec, "boomer trigger") //vehicles? - case ObjectClass.orbital_shuttle => ConstructorData.genericCodec(OrbitalShuttleData.codec, "HART") + case ObjectClass.orbital_shuttle => ConstructorData(OrbitalShuttleData.codec, "HART") //other - case ObjectClass.ams_order_terminal => ConstructorData.genericCodec(CommonTerminalData.codec, "terminal") - case ObjectClass.ams_respawn_tube => ConstructorData.genericCodec(CommonTerminalData.codec, "terminal") - case ObjectClass.avatar => ConstructorData.genericCodec(PlayerData.codec(false), "avatar") - case ObjectClass.bfr_rearm_terminal => ConstructorData.genericCodec(CommonTerminalData.codec, "terminal") - case ObjectClass.implant_terminal_interface => ConstructorData.genericCodec(CommonTerminalData.codec, "implant terminal") - case ObjectClass.lodestar_repair_terminal => ConstructorData.genericCodec(CommonTerminalData.codec, "terminal") - case ObjectClass.matrix_terminala => ConstructorData.genericCodec(CommonTerminalData.codec, "terminal") - case ObjectClass.matrix_terminalb => ConstructorData.genericCodec(CommonTerminalData.codec, "terminal") - case ObjectClass.matrix_terminalc => ConstructorData.genericCodec(CommonTerminalData.codec, "terminal") - case ObjectClass.multivehicle_rearm_terminal => ConstructorData.genericCodec(CommonTerminalData.codec, "terminal") - case ObjectClass.order_terminal => ConstructorData.genericCodec(CommonTerminalData.codec, "terminal") - case ObjectClass.order_terminala => ConstructorData.genericCodec(CommonTerminalData.codec, "terminal") - case ObjectClass.order_terminalb => ConstructorData.genericCodec(CommonTerminalData.codec, "terminal") - case ObjectClass.targeting_laser_dispenser => ConstructorData.genericCodec(CommonTerminalData.codec, "terminal") - case ObjectClass.teleportpad_terminal => ConstructorData.genericCodec(CommonTerminalData.codec, "terminal") + case ObjectClass.ams_order_terminal => ConstructorData(CommonFieldData.codec2, "terminal") + case ObjectClass.ams_respawn_tube => ConstructorData(CommonFieldData.codec2, "terminal") + case ObjectClass.avatar => ConstructorData(PlayerData.codec(false), "avatar") + case ObjectClass.bfr_rearm_terminal => ConstructorData(CommonFieldData.codec2, "terminal") + case ObjectClass.implant_terminal_interface => ConstructorData(CommonFieldData.codec2, "implant terminal") + case ObjectClass.lodestar_repair_terminal => ConstructorData(CommonFieldData.codec2, "terminal") + case ObjectClass.matrix_terminala => ConstructorData(CommonFieldData.codec2, "terminal") + case ObjectClass.matrix_terminalb => ConstructorData(CommonFieldData.codec2, "terminal") + case ObjectClass.matrix_terminalc => ConstructorData(CommonFieldData.codec2, "terminal") + case ObjectClass.multivehicle_rearm_terminal => ConstructorData(CommonFieldData.codec2, "terminal") + case ObjectClass.order_terminal => ConstructorData(CommonFieldData.codec2, "terminal") + case ObjectClass.order_terminala => ConstructorData(CommonFieldData.codec2, "terminal") + case ObjectClass.order_terminalb => ConstructorData(CommonFieldData.codec2, "terminal") + case ObjectClass.targeting_laser_dispenser => ConstructorData(CommonFieldData.codec2, "terminal") + case ObjectClass.teleportpad_terminal => ConstructorData(CommonFieldData.codec2, "terminal") //failure case case _ => defaultFailureCodec(objClass) } @@ -988,307 +1004,316 @@ object ObjectClass { * @return the `Codec` that handles the format of data for that particular item class, or a failing `Codec` * @see `ConstructorData` */ - def selectDataDroppedCodec(objClass : Int) : Codec[ConstructorData.genericPattern] = + def selectDataDroppedCodec(objClass : Int) : Codec[ConstructorData] = (objClass : @switch) match { //ammunition - case ObjectClass.bullet_105mm => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_12mm => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_150mm => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_15mm => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_20mm => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_25mm => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_35mm => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_75mm => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_9mm => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.bullet_9mm_AP => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.ancient_ammo_combo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.ancient_ammo_vehicle => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.anniversary_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.aphelion_immolation_cannon_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.aphelion_laser_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.aphelion_plasma_rocket_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.aphelion_ppa_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.aphelion_starfire_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.armor_canister => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.armor_siphon_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.bolt => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.burster_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.colossus_100mm_cannon_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.colossus_burster_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.colossus_chaingun_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.colossus_cluster_bomb_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.colossus_tank_cannon_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.comet_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.dualcycler_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.energy_cell => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.energy_gun_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.falcon_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.firebird_missile => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.flamethrower_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.flux_cannon_thresher_battery => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.fluxpod_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.frag_cartridge => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") -// case ObjectClass.frag_grenade_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.gauss_cannon_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.grenade => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.health_canister => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.heavy_grenade_mortar => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.heavy_rail_beam_battery => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.hellfire_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.hunter_seeker_missile => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.jammer_cartridge => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") -// case ObjectClass.jammer_grenade_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.lancer_cartridge => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.liberator_bomb => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.maelstrom_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.melee_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.mine => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.mine_sweeper_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.ntu_siphon_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.oicw_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.pellet_gun_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.peregrine_dual_machine_gun_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.peregrine_mechhammer_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.peregrine_particle_cannon_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.peregrine_rocket_pod_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.peregrine_sparrow_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.phalanx_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.phoenix_missile => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.plasma_cartridge => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") -// case ObjectClass.plasma_grenade_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.pounder_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.pulse_battery => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.quasar_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.reaver_rocket => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.rocket => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.scattercannon_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.shotgun_shell => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.shotgun_shell_AP => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.six_shooter_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.skyguard_flak_cannon_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.sparrow_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.spitfire_aa_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.spitfire_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.starfire_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.striker_missile_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") -// case ObjectClass.trek_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.upgrade_canister => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.wasp_gun_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.wasp_rocket_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") - case ObjectClass.winchester_ammo => DroppedItemData.genericCodec(AmmoBoxData.codec, "ammo box") + case ObjectClass.bullet_105mm => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.bullet_12mm => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.bullet_150mm => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.bullet_15mm => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.bullet_20mm => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.bullet_25mm => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.bullet_35mm => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.bullet_75mm => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.bullet_9mm => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.bullet_9mm_AP => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.ancient_ammo_combo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.ancient_ammo_vehicle => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.anniversary_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.aphelion_immolation_cannon_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.aphelion_laser_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.aphelion_plasma_rocket_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.aphelion_ppa_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.aphelion_starfire_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.armor_canister => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.armor_siphon_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.bolt => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.burster_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.colossus_100mm_cannon_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.colossus_burster_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.colossus_chaingun_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.colossus_cluster_bomb_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.colossus_tank_cannon_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.comet_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.dualcycler_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.energy_cell => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.energy_gun_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.falcon_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.firebird_missile => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.flamethrower_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.flux_cannon_thresher_battery => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.fluxpod_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.frag_cartridge => DroppedItemData(CommonFieldData.codec2, "ammo box") +// case ObjectClass.frag_grenade_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.gauss_cannon_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.grenade => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.health_canister => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.heavy_grenade_mortar => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.heavy_rail_beam_battery => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.hellfire_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.hunter_seeker_missile => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.jammer_cartridge => DroppedItemData(CommonFieldData.codec2, "ammo box") +// case ObjectClass.jammer_grenade_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.lancer_cartridge => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.liberator_bomb => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.maelstrom_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.melee_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.mine => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.mine_sweeper_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.ntu_siphon_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.oicw_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.pellet_gun_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.peregrine_dual_machine_gun_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.peregrine_mechhammer_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.peregrine_particle_cannon_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.peregrine_rocket_pod_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.peregrine_sparrow_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.phalanx_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.phoenix_missile => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.plasma_cartridge => DroppedItemData(CommonFieldData.codec2, "ammo box") +// case ObjectClass.plasma_grenade_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.pounder_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.pulse_battery => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.quasar_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.reaver_rocket => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.rocket => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.scattercannon_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.shotgun_shell => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.shotgun_shell_AP => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.six_shooter_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.skyguard_flak_cannon_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.sparrow_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.spitfire_aa_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.spitfire_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.starfire_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.striker_missile_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") +// case ObjectClass.trek_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.upgrade_canister => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.wasp_gun_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.wasp_rocket_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") + case ObjectClass.winchester_ammo => DroppedItemData(CommonFieldData.codec2, "ammo box") //weapons - case ObjectClass.beamer => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.anniversary_gun => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.anniversary_guna => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.anniversary_gunb => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.aphelion_immolation_cannon => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.aphelion_laser => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.aphelion_laser_left => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.aphelion_laser_right => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.aphelion_plasma_rocket_pod => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.aphelion_ppa => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.aphelion_ppa_left => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.aphelion_ppa_right => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.aphelion_starfire => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.aphelion_starfire_left => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.aphelion_starfire_right => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.bolt_driver => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.chainblade => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.chaingun_p => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.colossus_burster => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.colossus_burster_left => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.colossus_burster_right => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.colossus_chaingun => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.colossus_chaingun_left => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.colossus_chaingun_right => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.colossus_cluster_bomb_pod => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.colossus_dual_100mm_cannons => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.colossus_tank_cannon => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.colossus_tank_cannon_left => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.colossus_tank_cannon_right => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.cycler => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.energy_gun => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.energy_gun_nc => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.energy_gun_tr => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.energy_gun_vs => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.flamethrower => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.flechette => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.forceblade => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.fragmentation_grenade => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.gauss => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.heavy_sniper => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.hellfire => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.hunterseeker => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.ilc9 => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.isp => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.jammer_grenade => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.katana => DroppedItemData.genericCodec(WeaponData.codec(2), "weapon") - case ObjectClass.lancer => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.lasher => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.maelstrom => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.magcutter => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.mini_chaingun => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.oicw => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.peregrine_dual_machine_gun => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.peregrine_dual_machine_gun_left => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.peregrine_dual_machine_gun_right => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.peregrine_dual_rocket_pods => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.peregrine_mechhammer => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.peregrine_mechhammer_left => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.peregrine_mechhammer_right => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.peregrine_particle_cannon => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.peregrine_sparrow => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.peregrine_sparrow_left => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.peregrine_sparrow_right => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.phoenix => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.pulsar => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.plasma_grenade => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.punisher => DroppedItemData.genericCodec(WeaponData.codec(2), "weapon") - case ObjectClass.r_shotgun => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.radiator => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.repeater => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.rocklet => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.spiker => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.spitfire_aa_weapon => DroppedItemData.genericCodec(WeaponData.codec, "weapon") -// case ObjectClass.spitfire_weapon => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.striker => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.suppressor => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.thumper => DroppedItemData.genericCodec(WeaponData.codec, "weapon") + case ObjectClass.beamer => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.anniversary_gun => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.anniversary_guna => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.anniversary_gunb => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.aphelion_immolation_cannon => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.aphelion_laser => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.aphelion_laser_left => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.aphelion_laser_right => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.aphelion_plasma_rocket_pod => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.aphelion_ppa => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.aphelion_ppa_left => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.aphelion_ppa_right => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.aphelion_starfire => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.aphelion_starfire_left => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.aphelion_starfire_right => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.bolt_driver => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.chainblade => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.chaingun_p => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.colossus_burster => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.colossus_burster_left => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.colossus_burster_right => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.colossus_chaingun => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.colossus_chaingun_left => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.colossus_chaingun_right => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.colossus_cluster_bomb_pod => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.colossus_dual_100mm_cannons => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.colossus_tank_cannon => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.colossus_tank_cannon_left => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.colossus_tank_cannon_right => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.cycler => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.energy_gun => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.energy_gun_nc => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.energy_gun_tr => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.energy_gun_vs => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.flamethrower => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.flechette => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.forceblade => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.fragmentation_grenade => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.gauss => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.heavy_sniper => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.hellfire => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.hunterseeker => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.ilc9 => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.isp => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.jammer_grenade => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.katana => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.lancer => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.lasher => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.maelstrom => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.magcutter => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.mini_chaingun => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.oicw => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.peregrine_dual_machine_gun => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.peregrine_dual_machine_gun_left => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.peregrine_dual_machine_gun_right => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.peregrine_dual_rocket_pods => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.peregrine_mechhammer => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.peregrine_mechhammer_left => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.peregrine_mechhammer_right => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.peregrine_particle_cannon => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.peregrine_sparrow => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.peregrine_sparrow_left => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.peregrine_sparrow_right => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.phoenix => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.pulsar => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.plasma_grenade => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.punisher => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.r_shotgun => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.radiator => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.repeater => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.rocklet => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.spiker => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.spitfire_aa_weapon => DroppedItemData(WeaponData.codec, "weapon") +// case ObjectClass.spitfire_weapon => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.striker => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.suppressor => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.thumper => DroppedItemData(WeaponData.codec, "weapon") //other weapons - case ObjectClass.ace_deployable => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.advanced_missile_launcher_t => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.chaingun_12mm => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.chaingun_15mm => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.cycler_v2 => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.cycler_v3 => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.cycler_v4 => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.dynomite => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.frag_grenade => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.generic_grenade => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.mine_sweeper => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.pellet_gun => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.six_shooter => DroppedItemData.genericCodec(WeaponData.codec, "weapon") - case ObjectClass.winchester => DroppedItemData.genericCodec(WeaponData.codec, "weapon") + case ObjectClass.ace_deployable => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.advanced_missile_launcher_t => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.chaingun_12mm => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.chaingun_15mm => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.cycler_v2 => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.cycler_v3 => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.cycler_v4 => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.dynomite => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.frag_grenade => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.generic_grenade => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.mine_sweeper => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.pellet_gun => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.six_shooter => DroppedItemData(WeaponData.codec, "weapon") + case ObjectClass.winchester => DroppedItemData(WeaponData.codec, "weapon") //medkits - case ObjectClass.medkit => DroppedItemData.genericCodec(AmmoBoxData.codec, "medkit") - case ObjectClass.super_armorkit => DroppedItemData.genericCodec(AmmoBoxData.codec, "repair kit") - case ObjectClass.super_medkit => DroppedItemData.genericCodec(AmmoBoxData.codec, "medkit") - case ObjectClass.super_staminakit => DroppedItemData.genericCodec(AmmoBoxData.codec, "stamina kit") + case ObjectClass.medkit => DroppedItemData(CommonFieldData.codec2, "medkit") + case ObjectClass.super_armorkit => DroppedItemData(CommonFieldData.codec2, "repair kit") + case ObjectClass.super_medkit => DroppedItemData(CommonFieldData.codec2, "super medkit") + case ObjectClass.super_staminakit => DroppedItemData(CommonFieldData.codec2, "stamina kit") //tools - case ObjectClass.applicator => DroppedItemData.genericCodec(WeaponData.codec, "tool") - case ObjectClass.bank => DroppedItemData.genericCodec(WeaponData.codec, "tool") - case ObjectClass.command_detonater => DroppedItemData.genericCodec(CommandDetonaterData.codec, "tool") - case ObjectClass.flail_targeting_laser => DroppedItemData.genericCodec(CommandDetonaterData.codec, "tool") - case ObjectClass.medicalapplicator => DroppedItemData.genericCodec(WeaponData.codec, "tool") - case ObjectClass.nano_dispenser => DroppedItemData.genericCodec(WeaponData.codec, "tool") - case ObjectClass.remote_electronics_kit => DroppedItemData.genericCodec(REKData.codec, " tool") - case ObjectClass.trek => DroppedItemData.genericCodec(WeaponData.codec, "tool") + case ObjectClass.applicator => DroppedItemData(WeaponData.codec, "tool") + case ObjectClass.bank => DroppedItemData(WeaponData.codec, "tool") + case ObjectClass.command_detonater => DroppedItemData(HandheldData.codec, "tool") + case ObjectClass.flail_targeting_laser => DroppedItemData(HandheldData.codec, "tool") + case ObjectClass.medicalapplicator => DroppedItemData(WeaponData.codec, "tool") + case ObjectClass.nano_dispenser => DroppedItemData(WeaponData.codec, "tool") + case ObjectClass.remote_electronics_kit => DroppedItemData(REKData.codec, " tool") + case ObjectClass.trek => DroppedItemData(WeaponData.codec, "tool") //deployables - case ObjectClass.ace => DroppedItemData.genericCodec(ACEData.codec, "ace") - case ObjectClass.advanced_ace => DroppedItemData.genericCodec(ACEData.codec, "advanced ace") - case ObjectClass.router_telepad => DroppedItemData.genericCodec(TelepadData.codec, "router telepad") //TODO not correct - case ObjectClass.boomer_trigger => DroppedItemData.genericCodec(BoomerTriggerData.codec, "boomer trigger") - case ObjectClass.boomer => ConstructorData.genericCodec(SmallDeployableData.codec, "ace deployable") - case ObjectClass.he_mine => ConstructorData.genericCodec(SmallDeployableData.codec, "ace deployable") - case ObjectClass.jammer_mine => ConstructorData.genericCodec(SmallDeployableData.codec, "ace deployable") - case ObjectClass.motionalarmsensor => ConstructorData.genericCodec(SmallDeployableData.codec, "ace deployable") - case ObjectClass.sensor_shield => ConstructorData.genericCodec(SmallDeployableData.codec, "ace deployable") - case ObjectClass.spitfire_aa => ConstructorData.genericCodec(SmallTurretData.codec, "small turret") - case ObjectClass.spitfire_cloaked => ConstructorData.genericCodec(SmallTurretData.codec, "small turret") - case ObjectClass.spitfire_turret => ConstructorData.genericCodec(SmallTurretData.codec, "small turret") - case ObjectClass.tank_traps => ConstructorData.genericCodec(TRAPData.codec, "trap") - case ObjectClass.deployable_shield_generator => ConstructorData.genericCodec(AegisShieldGeneratorData.codec, "shield generator") - case ObjectClass.portable_manned_turret => ConstructorData.genericCodec(OneMannedFieldTurretData.codec, "field turret") - case ObjectClass.portable_manned_turret_nc => ConstructorData.genericCodec(OneMannedFieldTurretData.codec, "field turret") - case ObjectClass.portable_manned_turret_tr => ConstructorData.genericCodec(OneMannedFieldTurretData.codec, "field turret") - case ObjectClass.portable_manned_turret_vs => ConstructorData.genericCodec(OneMannedFieldTurretData.codec, "field turret") - case ObjectClass.router_telepad_deployable => ConstructorData.genericCodec(TelepadDeployableData.codec, "telepad deployable") + case ObjectClass.ace => DroppedItemData(HandheldData.codec, "ace") + case ObjectClass.advanced_ace => DroppedItemData(HandheldData.codec, "advanced ace") + case ObjectClass.router_telepad => DroppedItemData(HandheldData.codec, "router telepad") + case ObjectClass.boomer_trigger => DroppedItemData(HandheldData.codec, "boomer trigger") + case ObjectClass.boomer => ConstructorData(CommonFieldDataWithPlacement.codec2, "ace deployable") + case ObjectClass.he_mine => ConstructorData(CommonFieldDataWithPlacement.codec2, "ace deployable") + case ObjectClass.jammer_mine => ConstructorData(CommonFieldDataWithPlacement.codec2, "ace deployable") + case ObjectClass.motionalarmsensor => ConstructorData(CommonFieldDataWithPlacement.codec2, "ace deployable") + case ObjectClass.sensor_shield => ConstructorData(CommonFieldDataWithPlacement.codec2, "ace deployable") + case ObjectClass.spitfire_aa => ConstructorData(SmallTurretData.codec, "small turret") + case ObjectClass.spitfire_cloaked => ConstructorData(SmallTurretData.codec, "small turret") + case ObjectClass.spitfire_turret => ConstructorData(SmallTurretData.codec, "small turret") + case ObjectClass.tank_traps => ConstructorData(TRAPData.codec, "trap") + case ObjectClass.deployable_shield_generator => ConstructorData(AegisShieldGeneratorData.codec, "shield generator") + case ObjectClass.portable_manned_turret => ConstructorData(OneMannedFieldTurretData.codec, "field turret") + case ObjectClass.portable_manned_turret_nc => ConstructorData(OneMannedFieldTurretData.codec, "field turret") + case ObjectClass.portable_manned_turret_tr => ConstructorData(OneMannedFieldTurretData.codec, "field turret") + case ObjectClass.portable_manned_turret_vs => ConstructorData(OneMannedFieldTurretData.codec, "field turret") + case ObjectClass.router_telepad_deployable => DroppedItemData(TelepadDeployableData.codec, "telepad deployable") //projectiles - case ObjectClass.hunter_seeker_missile_projectile => ConstructorData.genericCodec(TrackedProjectileData.codec, "projectile") - case ObjectClass.oicw_projectile => ConstructorData.genericCodec(TrackedProjectileData.codec, "projectile") - case ObjectClass.starfire_projectile => ConstructorData.genericCodec(TrackedProjectileData.codec, "projectile") - case ObjectClass.striker_missile_targeting_projectile => ConstructorData.genericCodec(TrackedProjectileData.codec, "projectile") + case ObjectClass.hunter_seeker_missile_projectile => ConstructorData(TrackedProjectileData.codec, "projectile") + case ObjectClass.meteor_common => ConstructorData(TrackedProjectileData.codec, "meteor") + case ObjectClass.meteor_projectile_b_large => ConstructorData(TrackedProjectileData.codec, "meteor") + case ObjectClass.meteor_projectile_b_medium => ConstructorData(TrackedProjectileData.codec, "meteor") + case ObjectClass.meteor_projectile_b_small => ConstructorData(TrackedProjectileData.codec, "meteor") + case ObjectClass.meteor_projectile_large => ConstructorData(TrackedProjectileData.codec, "meteor") + case ObjectClass.meteor_projectile_medium => ConstructorData(TrackedProjectileData.codec, "meteor") + case ObjectClass.meteor_projectile_small => ConstructorData(TrackedProjectileData.codec, "meteor") + case ObjectClass.oicw_projectile => ConstructorData(TrackedProjectileData.codec, "projectile") + case ObjectClass.sparrow_projectile => ConstructorData(TrackedProjectileData.codec, "projectile") + case ObjectClass.starfire_projectile => ConstructorData(TrackedProjectileData.codec, "projectile") + case ObjectClass.striker_missile_targeting_projectile => ConstructorData(TrackedProjectileData.codec, "projectile") + case ObjectClass.wasp_rocket_projectile => ConstructorData(TrackedProjectileData.codec, "projectile") //vehicles - case ObjectClass.ams => ConstructorData.genericCodec(VehicleData.codec(VehicleFormat.Utility), "ams") - case ObjectClass.ams_destroyed => ConstructorData.genericCodec(DestroyedVehicleData.codec, "wreckage") - case ObjectClass.ant => ConstructorData.genericCodec(VehicleData.codec(VehicleFormat.Utility), "ant") - case ObjectClass.ant_destroyed => ConstructorData.genericCodec(DestroyedVehicleData.codec, "wreckage") - case ObjectClass.apc_destroyed => ConstructorData.genericCodec(DestroyedVehicleData.codec, "wreckage") - case ObjectClass.apc_nc => ConstructorData.genericCodec(VehicleData.codec, "vehicle") - case ObjectClass.apc_tr => ConstructorData.genericCodec(VehicleData.codec, "vehicle") - case ObjectClass.apc_vs => ConstructorData.genericCodec(VehicleData.codec, "vehicle") + case ObjectClass.ams => ConstructorData(VehicleData.codec(VehicleFormat.Utility), "ams") + case ObjectClass.ams_destroyed => ConstructorData(DestroyedVehicleData.codec, "wreckage") + case ObjectClass.ant => ConstructorData(VehicleData.codec(VehicleFormat.Utility), "ant") + case ObjectClass.ant_destroyed => ConstructorData(DestroyedVehicleData.codec, "wreckage") + case ObjectClass.apc_destroyed => ConstructorData(DestroyedVehicleData.codec, "wreckage") + case ObjectClass.apc_nc => ConstructorData(VehicleData.codec, "vehicle") + case ObjectClass.apc_tr => ConstructorData(VehicleData.codec, "vehicle") + case ObjectClass.apc_vs => ConstructorData(VehicleData.codec, "vehicle") //case ObjectClass.aphelion_destroyed => normal @ 0 health - case ObjectClass.aphelion_flight => ConstructorData.genericCodec(VehicleData.codec(VehicleFormat.Battleframe), "vehicle") - case ObjectClass.aphelion_gunner => ConstructorData.genericCodec(VehicleData.codec(VehicleFormat.Battleframe), "vehicle") - case ObjectClass.aurora => ConstructorData.genericCodec(VehicleData.codec, "vehicle") - case ObjectClass.battlewagon => ConstructorData.genericCodec(VehicleData.codec, "vehicle") + case ObjectClass.aphelion_flight => ConstructorData(VehicleData.codec(VehicleFormat.Battleframe), "vehicle") + case ObjectClass.aphelion_gunner => ConstructorData(VehicleData.codec(VehicleFormat.Battleframe), "vehicle") + case ObjectClass.aurora => ConstructorData(VehicleData.codec, "vehicle") + case ObjectClass.battlewagon => ConstructorData(VehicleData.codec, "vehicle") //case ObjectClass.colossus_destroyed => normal @ 0 health - case ObjectClass.colossus_flight => ConstructorData.genericCodec(VehicleData.codec(VehicleFormat.Battleframe), "vehicle") - case ObjectClass.colossus_gunner => ConstructorData.genericCodec(VehicleData.codec(VehicleFormat.Battleframe), "vehicle") - case ObjectClass.droppod => ConstructorData.genericCodec(DroppodData.codec, "droppod") - case ObjectClass.dropship => ConstructorData.genericCodec(VehicleData.codec(VehicleFormat.Variant), "vehicle") - case ObjectClass.dropship_destroyed => ConstructorData.genericCodec(DestroyedVehicleData.codec, "wreckage") - case ObjectClass.flail => ConstructorData.genericCodec(VehicleData.codec(VehicleFormat.Variant), "vehicle") - case ObjectClass.flail_destroyed => ConstructorData.genericCodec(DestroyedVehicleData.codec, "wreckage") - case ObjectClass.fury => ConstructorData.genericCodec(VehicleData.codec, "vehicle") - case ObjectClass.galaxy_gunship => ConstructorData.genericCodec(VehicleData.codec(VehicleFormat.Variant), "vehicle") - case ObjectClass.liberator => ConstructorData.genericCodec(VehicleData.codec(VehicleFormat.Variant), "vehicle") - case ObjectClass.liberator_destroyed => ConstructorData.genericCodec(DestroyedVehicleData.codec, "wreckage") - case ObjectClass.lightgunship => ConstructorData.genericCodec(VehicleData.codec(VehicleFormat.Variant), "vehicle") - case ObjectClass.lightgunship_destroyed => ConstructorData.genericCodec(DestroyedVehicleData.codec, "wreckage") - case ObjectClass.lightning => ConstructorData.genericCodec(VehicleData.codec, "vehicle") - case ObjectClass.lightning_destroyed => ConstructorData.genericCodec(DestroyedVehicleData.codec, "wreckage") - case ObjectClass.lodestar => ConstructorData.genericCodec(VehicleData.codec(VehicleFormat.Variant), "vehicle") - case ObjectClass.lodestar_destroyed => ConstructorData.genericCodec(DestroyedVehicleData.codec, "wreckage") - case ObjectClass.magrider => ConstructorData.genericCodec(VehicleData.codec, "vehicle") - case ObjectClass.magrider_destroyed => ConstructorData.genericCodec(DestroyedVehicleData.codec, "wreckage") - case ObjectClass.mediumtransport => ConstructorData.genericCodec(VehicleData.codec, "vehicle") - case ObjectClass.mediumtransport_destroyed => ConstructorData.genericCodec(DestroyedVehicleData.codec, "wreckage") - case ObjectClass.mosquito => ConstructorData.genericCodec(VehicleData.codec(VehicleFormat.Variant), "vehicle") - case ObjectClass.mosquito_destroyed => ConstructorData.genericCodec(DestroyedVehicleData.codec, "wreckage") - case ObjectClass.orbital_shuttle => ConstructorData.genericCodec(OrbitalShuttleData.codec_pos, "HART") + case ObjectClass.colossus_flight => ConstructorData(VehicleData.codec(VehicleFormat.Battleframe), "vehicle") + case ObjectClass.colossus_gunner => ConstructorData(VehicleData.codec(VehicleFormat.Battleframe), "vehicle") + case ObjectClass.droppod => ConstructorData(DroppodData.codec, "droppod") + case ObjectClass.dropship => ConstructorData(VehicleData.codec(VehicleFormat.Variant), "vehicle") + case ObjectClass.dropship_destroyed => ConstructorData(DestroyedVehicleData.codec, "wreckage") + case ObjectClass.flail => ConstructorData(VehicleData.codec(VehicleFormat.Variant), "vehicle") + case ObjectClass.flail_destroyed => ConstructorData(DestroyedVehicleData.codec, "wreckage") + case ObjectClass.fury => ConstructorData(VehicleData.codec, "vehicle") + case ObjectClass.galaxy_gunship => ConstructorData(VehicleData.codec(VehicleFormat.Variant), "vehicle") + case ObjectClass.liberator => ConstructorData(VehicleData.codec(VehicleFormat.Variant), "vehicle") + case ObjectClass.liberator_destroyed => ConstructorData(DestroyedVehicleData.codec, "wreckage") + case ObjectClass.lightgunship => ConstructorData(VehicleData.codec(VehicleFormat.Variant), "vehicle") + case ObjectClass.lightgunship_destroyed => ConstructorData(DestroyedVehicleData.codec, "wreckage") + case ObjectClass.lightning => ConstructorData(VehicleData.codec, "vehicle") + case ObjectClass.lightning_destroyed => ConstructorData(DestroyedVehicleData.codec, "wreckage") + case ObjectClass.lodestar => ConstructorData(VehicleData.codec(VehicleFormat.Variant), "vehicle") + case ObjectClass.lodestar_destroyed => ConstructorData(DestroyedVehicleData.codec, "wreckage") + case ObjectClass.magrider => ConstructorData(VehicleData.codec, "vehicle") + case ObjectClass.magrider_destroyed => ConstructorData(DestroyedVehicleData.codec, "wreckage") + case ObjectClass.mediumtransport => ConstructorData(VehicleData.codec, "vehicle") + case ObjectClass.mediumtransport_destroyed => ConstructorData(DestroyedVehicleData.codec, "wreckage") + case ObjectClass.mosquito => ConstructorData(VehicleData.codec(VehicleFormat.Variant), "vehicle") + case ObjectClass.mosquito_destroyed => ConstructorData(DestroyedVehicleData.codec, "wreckage") + case ObjectClass.orbital_shuttle => ConstructorData(OrbitalShuttleData.codec_pos, "HART") //case ObjectClass.peregrine_destroyed => normal @ 0 health - case ObjectClass.peregrine_flight => ConstructorData.genericCodec(VehicleData.codec(VehicleFormat.Battleframe), "vehicle") - case ObjectClass.peregrine_gunner => ConstructorData.genericCodec(VehicleData.codec(VehicleFormat.Battleframe), "vehicle") - case ObjectClass.phantasm => ConstructorData.genericCodec(VehicleData.codec(VehicleFormat.Variant), "vehicle") + case ObjectClass.peregrine_flight => ConstructorData(VehicleData.codec(VehicleFormat.Battleframe), "vehicle") + case ObjectClass.peregrine_gunner => ConstructorData(VehicleData.codec(VehicleFormat.Battleframe), "vehicle") + case ObjectClass.phantasm => ConstructorData(VehicleData.codec(VehicleFormat.Variant), "vehicle") //case ObjectClass.phantasm_destroyed => normal @ 0 health - case ObjectClass.prowler => ConstructorData.genericCodec(VehicleData.codec, "vehicle") - case ObjectClass.prowler_destroyed => ConstructorData.genericCodec(DestroyedVehicleData.codec, "wreckage") - case ObjectClass.quadassault => ConstructorData.genericCodec(VehicleData.codec, "vehicle") - case ObjectClass.quadassault_destroyed => ConstructorData.genericCodec(DestroyedVehicleData.codec, "wreckage") - case ObjectClass.quadstealth => ConstructorData.genericCodec(VehicleData.codec, "vehicle") - case ObjectClass.quadstealth_destroyed => ConstructorData.genericCodec(DestroyedVehicleData.codec, "wreckage") - case ObjectClass.router => ConstructorData.genericCodec(VehicleData.codec(VehicleFormat.Variant), "vehicle") - case ObjectClass.router_destroyed => ConstructorData.genericCodec(DestroyedVehicleData.codec, "wreckage") - case ObjectClass.skyguard => ConstructorData.genericCodec(VehicleData.codec, "vehicle") - case ObjectClass.skyguard_destroyed => ConstructorData.genericCodec(DestroyedVehicleData.codec, "wreckage") - case ObjectClass.switchblade => ConstructorData.genericCodec(VehicleData.codec(VehicleFormat.Variant), "vehicle") - case ObjectClass.switchblade_destroyed => ConstructorData.genericCodec(DestroyedVehicleData.codec, "wreckage") - case ObjectClass.threemanheavybuggy => ConstructorData.genericCodec(VehicleData.codec, "vehicle") - case ObjectClass.threemanheavybuggy_destroyed => ConstructorData.genericCodec(DestroyedVehicleData.codec, "wreckage") - case ObjectClass.thunderer => ConstructorData.genericCodec(VehicleData.codec, "vehicle") - case ObjectClass.two_man_assault_buggy => ConstructorData.genericCodec(VehicleData.codec, "vehicle") - case ObjectClass.two_man_assault_buggy_destroyed => ConstructorData.genericCodec(DestroyedVehicleData.codec, "wreckage") - case ObjectClass.twomanheavybuggy => ConstructorData.genericCodec(VehicleData.codec, "vehicle") - case ObjectClass.twomanheavybuggy_destroyed => ConstructorData.genericCodec(DestroyedVehicleData.codec, "wreckage") - case ObjectClass.twomanhoverbuggy => ConstructorData.genericCodec(VehicleData.codec, "vehicle") - case ObjectClass.twomanhoverbuggy_destroyed => ConstructorData.genericCodec(DestroyedVehicleData.codec, "wreckage") - case ObjectClass.vanguard => ConstructorData.genericCodec(VehicleData.codec, "vehicle") - case ObjectClass.vanguard_destroyed => ConstructorData.genericCodec(DestroyedVehicleData.codec, "wreckage") - case ObjectClass.vulture => ConstructorData.genericCodec(VehicleData.codec(VehicleFormat.Variant), "vehicle") - case ObjectClass.wasp => ConstructorData.genericCodec(VehicleData.codec(VehicleFormat.Variant), "vehicle") + case ObjectClass.prowler => ConstructorData(VehicleData.codec, "vehicle") + case ObjectClass.prowler_destroyed => ConstructorData(DestroyedVehicleData.codec, "wreckage") + case ObjectClass.quadassault => ConstructorData(VehicleData.codec, "vehicle") + case ObjectClass.quadassault_destroyed => ConstructorData(DestroyedVehicleData.codec, "wreckage") + case ObjectClass.quadstealth => ConstructorData(VehicleData.codec, "vehicle") + case ObjectClass.quadstealth_destroyed => ConstructorData(DestroyedVehicleData.codec, "wreckage") + case ObjectClass.router => ConstructorData(VehicleData.codec(VehicleFormat.Variant), "vehicle") + case ObjectClass.router_destroyed => ConstructorData(DestroyedVehicleData.codec, "wreckage") + case ObjectClass.skyguard => ConstructorData(VehicleData.codec, "vehicle") + case ObjectClass.skyguard_destroyed => ConstructorData(DestroyedVehicleData.codec, "wreckage") + case ObjectClass.switchblade => ConstructorData(VehicleData.codec(VehicleFormat.Variant), "vehicle") + case ObjectClass.switchblade_destroyed => ConstructorData(DestroyedVehicleData.codec, "wreckage") + case ObjectClass.threemanheavybuggy => ConstructorData(VehicleData.codec, "vehicle") + case ObjectClass.threemanheavybuggy_destroyed => ConstructorData(DestroyedVehicleData.codec, "wreckage") + case ObjectClass.thunderer => ConstructorData(VehicleData.codec, "vehicle") + case ObjectClass.two_man_assault_buggy => ConstructorData(VehicleData.codec, "vehicle") + case ObjectClass.two_man_assault_buggy_destroyed => ConstructorData(DestroyedVehicleData.codec, "wreckage") + case ObjectClass.twomanheavybuggy => ConstructorData(VehicleData.codec, "vehicle") + case ObjectClass.twomanheavybuggy_destroyed => ConstructorData(DestroyedVehicleData.codec, "wreckage") + case ObjectClass.twomanhoverbuggy => ConstructorData(VehicleData.codec, "vehicle") + case ObjectClass.twomanhoverbuggy_destroyed => ConstructorData(DestroyedVehicleData.codec, "wreckage") + case ObjectClass.vanguard => ConstructorData(VehicleData.codec, "vehicle") + case ObjectClass.vanguard_destroyed => ConstructorData(DestroyedVehicleData.codec, "wreckage") + case ObjectClass.vulture => ConstructorData(VehicleData.codec(VehicleFormat.Variant), "vehicle") + case ObjectClass.wasp => ConstructorData(VehicleData.codec(VehicleFormat.Variant), "vehicle") //other - case ObjectClass.ams_respawn_tube => DroppedItemData.genericCodec(CommonTerminalData.codec, "terminal") - case ObjectClass.avatar => ConstructorData.genericCodec(PlayerData.codec(true), "avatar") - case ObjectClass.capture_flag => ConstructorData.genericCodec(CaptureFlagData.codec, "capture flag") - case ObjectClass.implant_terminal_interface => ConstructorData.genericCodec(CommonTerminalData.codec, "implant terminal") - case ObjectClass.locker_container => ConstructorData.genericCodec(LockerContainerData.codec, "locker container") - case ObjectClass.matrix_terminala => DroppedItemData.genericCodec(CommonTerminalData.codec, "terminal") - case ObjectClass.matrix_terminalb => DroppedItemData.genericCodec(CommonTerminalData.codec, "terminal") - case ObjectClass.matrix_terminalc => DroppedItemData.genericCodec(CommonTerminalData.codec, "terminal") - case ObjectClass.order_terminal => DroppedItemData.genericCodec(CommonTerminalData.codec, "terminal") - case ObjectClass.order_terminala => DroppedItemData.genericCodec(CommonTerminalData.codec, "terminal") - case ObjectClass.order_terminalb => DroppedItemData.genericCodec(CommonTerminalData.codec, "terminal") + case ObjectClass.ams_respawn_tube => DroppedItemData(CommonFieldData.codec2, "terminal") + case ObjectClass.avatar => ConstructorData(PlayerData.codec(true), "avatar") + case ObjectClass.capture_flag => ConstructorData(CaptureFlagData.codec, "capture flag") + case ObjectClass.implant_terminal_interface => ConstructorData(CommonFieldData.codec2, "implant terminal") + case ObjectClass.locker_container => ConstructorData(LockerContainerData.codec, "locker container") + case ObjectClass.matrix_terminala => DroppedItemData(CommonFieldData.codec2, "terminal") + case ObjectClass.matrix_terminalb => DroppedItemData(CommonFieldData.codec2, "terminal") + case ObjectClass.matrix_terminalc => DroppedItemData(CommonFieldData.codec2, "terminal") + case ObjectClass.order_terminal => DroppedItemData(CommonFieldData.codec2, "terminal") + case ObjectClass.order_terminala => DroppedItemData(CommonFieldData.codec2, "terminal") + case ObjectClass.order_terminalb => DroppedItemData(CommonFieldData.codec2, "terminal") //failure case case _ => defaultFailureCodec(objClass) } @@ -1298,16 +1323,10 @@ object ObjectClass { * @param cls the object class whose `Codec` we have failed to find; * @return a failure */ - private def defaultFailureCodec(cls : Int) : Codec[ConstructorData.genericPattern] = { - conditional(cls == 0, bool).exmap[ConstructorData.genericPattern] ( - { - case None | _ => - Attempt.failure(Err(s"decoding unknown object class $cls")) - }, - { - case None | _ => - Attempt.failure(Err(s"encoding unknown object class $cls")) - } + private def defaultFailureCodec(cls : Int) : Codec[ConstructorData] = { + conditional(cls == 0, bool).exmap[ConstructorData] ( + _ => Attempt.failure(Err(s"decoding unknown object class $cls")), + _ => Attempt.failure(Err(s"encoding unknown object class $cls")) ) } } diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/ObjectCreateBase.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/ObjectCreateBase.scala index 71b77fa8..c66ea269 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/ObjectCreateBase.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/ObjectCreateBase.scala @@ -84,22 +84,22 @@ object ObjectCreateBase { * @return the optional constructed object * @see `ObjectClass` */ - def decodeData(objectClass : Int, data : BitVector, getCodecFunc : (Int) => Codec[ConstructorData.genericPattern]) : Option[ConstructorData] = { - var out : Option[ConstructorData] = None + def decodeData(objectClass : Int, data : BitVector, getCodecFunc : Int => Codec[ConstructorData]) : Attempt[ConstructorData] = { try { getCodecFunc(objectClass).decode(data) match { case Attempt.Successful(decode) => - out = decode.value.asInstanceOf[ConstructorData.genericPattern] - case Attempt.Failure(err) => + Attempt.Successful(decode.value) + case result @ Attempt.Failure(err) => log.error(s"an object $objectClass failed to decode - ${err.toString}") log.debug(s"object type: $objectClass, input: ${data.toString}, problem: ${err.toString}") + result } } catch { case ex : Exception => - log.error(s"${ex.getClass.toString} - ${ex.toString} ($objectClass)") + log.error(s"Decoding error - ${ex.getClass.toString} - ${ex.toString} ($objectClass)") + Attempt.failure(Err(ex.getMessage)) } - out } /** @@ -112,22 +112,23 @@ object ObjectCreateBase { * @return the bitstream data * @see `ObjectClass` */ - def encodeData(objectClass : Int, obj : ConstructorData, getCodecFunc : (Int) => Codec[ConstructorData.genericPattern]) : BitVector = { - var out = BitVector.empty + def encodeData(objectClass : Int, obj : ConstructorData, getCodecFunc : Int => Codec[ConstructorData]) : Attempt[BitVector] = { try { - getCodecFunc(objectClass).encode(Some(obj.asInstanceOf[ConstructorData])) match { - case Attempt.Successful(encode) => - out = encode - case Attempt.Failure(err) => + getCodecFunc(objectClass).encode(obj.asInstanceOf[ConstructorData]) match { + case result @ Attempt.Successful(encode) => + result + case result @ Attempt.Failure(err) => log.error(s"an $objectClass object failed to encode - ${err.toString}") log.debug(s"object type: $objectClass, input: ${obj.toString}, problem: ${err.toString}") + result + } } catch { case ex : Exception => - log.error(s"${ex.getClass.toString} - ${ex.toString} ($objectClass)") + log.error(s"Encoding error - ${ex.getClass.toString} - ${ex.toString} ($objectClass)") + Attempt.failure(Err(ex.getMessage)) } - out } /** diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/OneMannedFieldTurretData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/OneMannedFieldTurretData.scala index 4b9c1586..9ef570bd 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/OneMannedFieldTurretData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/OneMannedFieldTurretData.scala @@ -21,7 +21,7 @@ import shapeless.{::, HNil} * @param health the amount of health the object has, as a percentage of a filled bar * @param internals data regarding the mountable weapon */ -final case class OneMannedFieldTurretData(deploy : SmallDeployableData, +final case class OneMannedFieldTurretData(deploy : CommonFieldDataWithPlacement, health : Int, internals : Option[InventoryData] = None ) extends ConstructorData { @@ -45,89 +45,89 @@ object OneMannedFieldTurretData extends Marshallable[OneMannedFieldTurretData] { * @param internals data regarding the mountable weapon * @return a `OneMannedFieldTurretData` object */ - def apply(deploy : SmallDeployableData, health : Int, internals : InventoryData) : OneMannedFieldTurretData = + def apply(deploy : CommonFieldDataWithPlacement, health : Int, internals : InventoryData) : OneMannedFieldTurretData = new OneMannedFieldTurretData(deploy, health, Some(internals)) - /** - * Prefabricated weapon data for a weaponless field turret mount (`portable_manned_turret`). - * @param wep_guid the uid to assign to the weapon - * @param wep_unk1 na; - * used by `WeaponData` - * - * @param wep_unk2 na; - * used by `WeaponData` - * @param ammo_guid the uid to assign to the ammo - * @param ammo_unk na; - * used by `AmmoBoxData` - * @return an `InternalSlot` object - */ - def generic(wep_guid : PlanetSideGUID, wep_unk1 : Int, wep_unk2 : Int, ammo_guid : PlanetSideGUID, ammo_unk : Int) : InternalSlot = - InternalSlot(ObjectClass.energy_gun, wep_guid, 1, - WeaponData(wep_unk1, wep_unk2, ObjectClass.energy_gun_ammo, ammo_guid, 0, - AmmoBoxData(ammo_unk) - ) - ) - - /** - * Prefabricated weapon data for the Terran Republic field turret, the Avenger (`portable_manned_turret_tr`). - * @param wep_guid the uid to assign to the weapon - * @param wep_unk1 na; - * used by `WeaponData` - * - * @param wep_unk2 na; - * used by `WeaponData` - * @param ammo_guid the uid to assign to the ammo - * @param ammo_unk na; - * used by `AmmoBoxData` - * @return an `InternalSlot` object - */ - def avenger(wep_guid : PlanetSideGUID, wep_unk1 : Int, wep_unk2 : Int, ammo_guid : PlanetSideGUID, ammo_unk : Int) : InternalSlot = - InternalSlot(ObjectClass.energy_gun_tr, wep_guid, 1, - WeaponData(wep_unk1, wep_unk2, ObjectClass.energy_gun_ammo, ammo_guid, 0, - AmmoBoxData(ammo_unk) - ) - ) - - /** - * Prefabricated weapon data for the New Conglomerate field turret, the Osprey (`portable_manned_turret_vnc`). - * @param wep_guid the uid to assign to the weapon - * @param wep_unk1 na; - * used by `WeaponData` - * @param wep_unk2 na; - * used by `WeaponData` - * @param ammo_guid the uid to assign to the ammo - * @param ammo_unk na; - * used by `AmmoBoxData` - * @return an `InternalSlot` object - */ - def osprey(wep_guid : PlanetSideGUID, wep_unk1 : Int, wep_unk2 : Int, ammo_guid : PlanetSideGUID, ammo_unk : Int) : InternalSlot = - InternalSlot(ObjectClass.energy_gun_nc, wep_guid, 1, - WeaponData(wep_unk1, wep_unk2, ObjectClass.energy_gun_ammo, ammo_guid, 0, - AmmoBoxData(ammo_unk) - ) - ) - - /** - * Prefabricated weapon data for the Vanu Soveriegnty field turret, the Orion (`portable_manned_turret_vs`). - * @param wep_guid the uid to assign to the weapon - * @param wep_unk1 na; - * used by `WeaponData` - * @param wep_unk2 na; - * used by `WeaponData` - * @param ammo_guid the uid to assign to the ammo - * @param ammo_unk na; - * used by `AmmoBoxData` - * @return an `InternalSlot` object - */ - def orion(wep_guid : PlanetSideGUID, wep_unk1 : Int, wep_unk2 : Int, ammo_guid : PlanetSideGUID, ammo_unk : Int) : InternalSlot = - InternalSlot(ObjectClass.energy_gun_vs, wep_guid, 1, - WeaponData(wep_unk1, wep_unk2, ObjectClass.energy_gun_ammo, ammo_guid, 0, - AmmoBoxData(ammo_unk) - ) - ) +// /** +// * Prefabricated weapon data for a weaponless field turret mount (`portable_manned_turret`). +// * @param wep_guid the uid to assign to the weapon +// * @param wep_unk1 na; +// * used by `WeaponData` +// * +// * @param wep_unk2 na; +// * used by `WeaponData` +// * @param ammo_guid the uid to assign to the ammo +// * @param ammo_unk na; +// * used by `AmmoBoxData` +// * @return an `InternalSlot` object +// */ +// def generic(wep_guid : PlanetSideGUID, wep_unk1 : Int, wep_unk2 : Int, ammo_guid : PlanetSideGUID, ammo_unk : Int) : InternalSlot = +// InternalSlot(ObjectClass.energy_gun, wep_guid, 1, +// WeaponData(wep_unk1, wep_unk2, ObjectClass.energy_gun_ammo, ammo_guid, 0, +// CommonFieldData(PlanetSideEmpire.NEUTRAL, ammo_unk(false) +// ) +// ) +// +// /** +// * Prefabricated weapon data for the Terran Republic field turret, the Avenger (`portable_manned_turret_tr`). +// * @param wep_guid the uid to assign to the weapon +// * @param wep_unk1 na; +// * used by `WeaponData` +// * +// * @param wep_unk2 na; +// * used by `WeaponData` +// * @param ammo_guid the uid to assign to the ammo +// * @param ammo_unk na; +// * used by `AmmoBoxData` +// * @return an `InternalSlot` object +// */ +// def avenger(wep_guid : PlanetSideGUID, wep_unk1 : Int, wep_unk2 : Int, ammo_guid : PlanetSideGUID, ammo_unk : Int) : InternalSlot = +// InternalSlot(ObjectClass.energy_gun_tr, wep_guid, 1, +// WeaponData(wep_unk1, wep_unk2, ObjectClass.energy_gun_ammo, ammo_guid, 0, +// CommonFieldData(PlanetSideEmpire.NEUTRAL, ammo_unk(false) +// ) +// ) +// +// /** +// * Prefabricated weapon data for the New Conglomerate field turret, the Osprey (`portable_manned_turret_vnc`). +// * @param wep_guid the uid to assign to the weapon +// * @param wep_unk1 na; +// * used by `WeaponData` +// * @param wep_unk2 na; +// * used by `WeaponData` +// * @param ammo_guid the uid to assign to the ammo +// * @param ammo_unk na; +// * used by `AmmoBoxData` +// * @return an `InternalSlot` object +// */ +// def osprey(wep_guid : PlanetSideGUID, wep_unk1 : Int, wep_unk2 : Int, ammo_guid : PlanetSideGUID, ammo_unk : Int) : InternalSlot = +// InternalSlot(ObjectClass.energy_gun_nc, wep_guid, 1, +// WeaponData(wep_unk1, wep_unk2, ObjectClass.energy_gun_ammo, ammo_guid, 0, +// CommonFieldData(PlanetSideEmpire.NEUTRAL, ammo_unk(false) +// ) +// ) +// +// /** +// * Prefabricated weapon data for the Vanu Soveriegnty field turret, the Orion (`portable_manned_turret_vs`). +// * @param wep_guid the uid to assign to the weapon +// * @param wep_unk1 na; +// * used by `WeaponData` +// * @param wep_unk2 na; +// * used by `WeaponData` +// * @param ammo_guid the uid to assign to the ammo +// * @param ammo_unk na; +// * used by `AmmoBoxData` +// * @return an `InternalSlot` object +// */ +// def orion(wep_guid : PlanetSideGUID, wep_unk1 : Int, wep_unk2 : Int, ammo_guid : PlanetSideGUID, ammo_unk : Int) : InternalSlot = +// InternalSlot(ObjectClass.energy_gun_vs, wep_guid, 1, +// WeaponData(wep_unk1, wep_unk2, ObjectClass.energy_gun_ammo, ammo_guid, 0, +// CommonFieldData(PlanetSideEmpire.NEUTRAL, ammo_unk(false) +// ) +// ) implicit val codec : Codec[OneMannedFieldTurretData] = ( - ("deploy" | SmallDeployableData.codec) :: + ("deploy" | CommonFieldDataWithPlacement.codec2) :: PlanetSideGUID.codec :: //hoist/extract with the deploy.owner_guid in field above bool :: ("health" | uint8L) :: @@ -144,30 +144,35 @@ object OneMannedFieldTurretData extends Marshallable[OneMannedFieldTurretData] { else { (health, internals) } + val data = deploy.data Attempt.successful( OneMannedFieldTurretData( - SmallDeployableData(deploy.pos, deploy.faction, deploy.bops, deploy.destroyed, deploy.unk1, deploy.jammered, deploy.unk2, player), + CommonFieldDataWithPlacement( + deploy.pos, + CommonFieldData(data.faction, data.bops, data.alternate, data.v1, data.v2, data.v3, data.v4, data.v5, player) + ), newHealth, newInternals ) ) - case _ => - Attempt.failure(Err("invalid omft data format")) + case data => + Attempt.failure(Err(s"invalid field turret data format - $data")) }, { - case OneMannedFieldTurretData(deploy, health, internals) => + case OneMannedFieldTurretData(CommonFieldDataWithPlacement(pos, data), health, internals) => val (newHealth, newInternals) = if(health == 0 || internals.isEmpty || internals.get.contents.isEmpty) { (0, None) } else { (health, internals) } - val newDeploy = SmallDeployableData(deploy.pos, deploy.faction, deploy.bops, deploy.destroyed, deploy.unk1, deploy.jammered, deploy.unk2, PlanetSideGUID(0)) - Attempt.successful(newDeploy :: deploy.owner_guid :: false :: newHealth :: 0 :: 0xF :: 0 :: newInternals :: HNil) - - case _ => - Attempt.failure(Err("invalid omft data format")) + Attempt.successful( + CommonFieldDataWithPlacement( + pos, + CommonFieldData(data.faction, data.bops, data.alternate, data.v1, data.v2, data.v3, data.v4, data.v5, PlanetSideGUID(0)) + ) :: data.guid :: false :: newHealth :: 0 :: 0xF :: 0 :: newInternals :: HNil + ) } ) } diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/OrbitalShuttleData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/OrbitalShuttleData.scala index 017a8055..a9b79e21 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/OrbitalShuttleData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/OrbitalShuttleData.scala @@ -66,6 +66,9 @@ object OrbitalShuttleData extends Marshallable[OrbitalShuttleData] { { case faction :: 0 :: 255 :: 0 :: 7 :: 0 :: HNil => Attempt.successful(OrbitalShuttleData(faction)) + + case data => + Attempt.failure(Err(s"invalid shuttle data format - $data")) }, { case OrbitalShuttleData(faction, _) => @@ -90,8 +93,8 @@ object OrbitalShuttleData extends Marshallable[OrbitalShuttleData] { case pos :: faction :: 0 :: 255 :: 0 :: 255 :: 0 :: 15 :: false :: HNil => Attempt.successful(OrbitalShuttleData(faction, Some(pos))) - case _ => - Attempt.failure(Err("invalid shuttle data format")) + case data => + Attempt.failure(Err(s"invalid shuttle data format - $data")) }, { case OrbitalShuttleData(faction, Some(pos)) => @@ -99,9 +102,6 @@ object OrbitalShuttleData extends Marshallable[OrbitalShuttleData] { case OrbitalShuttleData(_, None) => Attempt.failure(Err("invalid shuttle data format (needs position)")) - - case _ => - Attempt.failure(Err("invalid shuttle data format")) } ) } diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/PlayerData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/PlayerData.scala index 12b398d8..84613ad4 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/PlayerData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/PlayerData.scala @@ -63,9 +63,9 @@ object PlayerData extends Marshallable[PlayerData] { * technically, always `DrawnSlot.None`, but the field is preserved to maintain similarity * @return a `PlayerData` object */ - def apply(basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Boolean,Boolean)=>CharacterData, inventory : InventoryData, drawn_slot : DrawnSlot.Type) : PlayerData = { + def apply(basic_appearance : Int=>CharacterAppearanceData, character_data : (Boolean,Boolean)=>CharacterData, inventory : InventoryData, drawn_slot : DrawnSlot.Type) : PlayerData = { val appearance = basic_appearance(5) - PlayerData(None, appearance, character_data(appearance.a.altModel, true), Some(inventory), drawn_slot)(false) + PlayerData(None, appearance, character_data(appearance.altModelBit.isDefined, true), Some(inventory), drawn_slot)(false) } /** * Overloaded constructor that ignores the coordinate information and the inventory. @@ -77,9 +77,9 @@ object PlayerData extends Marshallable[PlayerData] { * technically, always `DrawnSlot.None`, but the field is preserved to maintain similarity * @return a `PlayerData` object */ - def apply(basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Boolean,Boolean)=>CharacterData, drawn_slot : DrawnSlot.Type) : PlayerData = { + def apply(basic_appearance : Int=>CharacterAppearanceData, character_data : (Boolean,Boolean)=>CharacterData, drawn_slot : DrawnSlot.Type) : PlayerData = { val appearance = basic_appearance(5) - PlayerData(None, appearance, character_data(appearance.a.altModel, true), None, drawn_slot)(false) + PlayerData(None, appearance, character_data(appearance.altModelBit.isDefined, true), None, drawn_slot)(false) } /** @@ -93,9 +93,9 @@ object PlayerData extends Marshallable[PlayerData] { * @param drawn_slot the holster that is initially drawn * @return a `PlayerData` object */ - def apply(pos : PlacementData, basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Boolean,Boolean)=>CharacterData, inventory : InventoryData, drawn_slot : DrawnSlot.Type) : PlayerData = { + def apply(pos : PlacementData, basic_appearance : Int=>CharacterAppearanceData, character_data : (Boolean,Boolean)=>CharacterData, inventory : InventoryData, drawn_slot : DrawnSlot.Type) : PlayerData = { val appearance = basic_appearance( PaddingOffset(Some(pos)) ) - PlayerData(Some(pos), appearance, character_data(appearance.a.altModel, false), Some(inventory), drawn_slot)(true) + PlayerData(Some(pos), appearance, character_data(appearance.altModelBit.isDefined, false), Some(inventory), drawn_slot)(true) } /** * Overloaded constructor that includes the coordinate information but ignores the inventory. @@ -107,9 +107,9 @@ object PlayerData extends Marshallable[PlayerData] { * @param drawn_slot the holster that is initially drawn * @return a `PlayerData` object */ - def apply(pos : PlacementData, basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Boolean,Boolean)=>CharacterData, drawn_slot : DrawnSlot.Type) : PlayerData = { + def apply(pos : PlacementData, basic_appearance : Int=>CharacterAppearanceData, character_data : (Boolean,Boolean)=>CharacterData, drawn_slot : DrawnSlot.Type) : PlayerData = { val appearance = basic_appearance( PaddingOffset(Some(pos)) ) - PlayerData(Some(pos), appearance, character_data(appearance.a.altModel, false), None, drawn_slot)(true) + PlayerData(Some(pos), appearance, character_data(appearance.altModelBit.isDefined, false), None, drawn_slot)(true) } /** diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/Prefab.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/Prefab.scala index a767591d..85eb1303 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/Prefab.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/Prefab.scala @@ -13,448 +13,448 @@ import net.psforever.types.{DriveState, PlanetSideEmpire} object Prefab { object Vehicle { def ams(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, driveState : DriveState.Value, matrix_guid : PlanetSideGUID, respawn_guid : PlanetSideGUID, term_a_guid : PlanetSideGUID, term_b_guid : PlanetSideGUID) : VehicleData = { - VehicleData(CommonFieldData(loc, faction, 0), health, driveState, false, UtilityVehicleData(0), + VehicleData(loc, CommonFieldData(faction, 0), health, driveState, false, UtilityVehicleData(0), Some(InventoryData(List( - InternalSlot(ObjectClass.matrix_terminalc, matrix_guid, 1, CommonTerminalData(faction)), - InternalSlot(ObjectClass.ams_respawn_tube, respawn_guid, 2, CommonTerminalData(faction)), - InternalSlot(ObjectClass.order_terminala, term_a_guid, 3, CommonTerminalData(faction)), - InternalSlot(ObjectClass.order_terminalb, term_b_guid, 4, CommonTerminalData(faction)) + InternalSlot(ObjectClass.matrix_terminalc, matrix_guid, 1, CommonFieldData(faction)(false)), + InternalSlot(ObjectClass.ams_respawn_tube, respawn_guid, 2, CommonFieldData(faction)(false)), + InternalSlot(ObjectClass.order_terminala, term_a_guid, 3, CommonFieldData(faction)(false)), + InternalSlot(ObjectClass.order_terminalb, term_b_guid, 4, CommonFieldData(faction)(false)) ))) ) } def ant(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, driveState : DriveState.Value) : VehicleData = { - VehicleData(CommonFieldData(loc, faction, 0), health, driveState, false, UtilityVehicleData(0), None) + VehicleData(loc, CommonFieldData(faction, 0), health, driveState, false, UtilityVehicleData(0), None) } def apc_nc(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID, weapon3_guid : PlanetSideGUID, ammo3_guid : PlanetSideGUID, weapon4_guid : PlanetSideGUID, ammo4_guid : PlanetSideGUID, weapon5_guid : PlanetSideGUID, ammo5_guid : PlanetSideGUID, weapon6_guid : PlanetSideGUID, ammo6_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None, - VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false, + //VehicleData(loc, CommonFieldData(faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None, + VehicleData(loc, CommonFieldData(faction, 2), health, DriveState.State7, false, Some(InventoryData( InventoryItemData(ObjectClass.apc_weapon_systemc_nc, weapon1_guid, 11, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_20mm, ammo1_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_20mm, ammo1_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.apc_weapon_systemb, weapon2_guid, 12, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_75mm, ammo2_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_75mm, ammo2_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.apc_weapon_systema, weapon3_guid, 13, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_75mm, ammo3_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_75mm, ammo3_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.apc_weapon_systemd_nc, weapon4_guid, 14, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_20mm, ammo4_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_20mm, ammo4_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.apc_ballgun_r, weapon5_guid, 15, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_12mm, ammo5_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_12mm, ammo5_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.apc_ballgun_l, weapon6_guid, 16, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_12mm, ammo6_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_12mm, ammo6_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def apc_tr(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID, weapon3_guid : PlanetSideGUID, ammo3_guid : PlanetSideGUID, weapon4_guid : PlanetSideGUID, ammo4_guid : PlanetSideGUID, weapon5_guid : PlanetSideGUID, ammo5_guid : PlanetSideGUID, weapon6_guid : PlanetSideGUID, ammo6_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None, - VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false, + //VehicleData(loc, CommonFieldData(faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None, + VehicleData(loc, CommonFieldData(faction, 2), health, DriveState.State7, false, Some(InventoryData( InventoryItemData(ObjectClass.apc_weapon_systemc_tr, weapon1_guid, 11, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_15mm, ammo1_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_15mm, ammo1_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.apc_weapon_systemb, weapon2_guid, 12, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_75mm, ammo2_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_75mm, ammo2_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.apc_weapon_systema, weapon3_guid, 13, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_75mm, ammo3_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_75mm, ammo3_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.apc_weapon_systemd_tr, weapon4_guid, 14, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_15mm, ammo4_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_15mm, ammo4_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.apc_ballgun_r, weapon5_guid, 15, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_12mm, ammo5_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_12mm, ammo5_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.apc_ballgun_l, weapon6_guid, 16, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_12mm, ammo6_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_12mm, ammo6_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def apc_vs(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID, weapon3_guid : PlanetSideGUID, ammo3_guid : PlanetSideGUID, weapon4_guid : PlanetSideGUID, ammo4_guid : PlanetSideGUID, weapon5_guid : PlanetSideGUID, ammo5_guid : PlanetSideGUID, weapon6_guid : PlanetSideGUID, ammo6_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None, - VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false, + //VehicleData(loc, CommonFieldData(faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None, + VehicleData(loc, CommonFieldData(faction, 2), health, DriveState.State7, false, Some(InventoryData( InventoryItemData(ObjectClass.apc_weapon_systemc_vs, weapon1_guid, 11, - WeaponData(0x6, 0x8, 0, ObjectClass.flux_cannon_thresher_battery, ammo1_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.flux_cannon_thresher_battery, ammo1_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.apc_weapon_systemb, weapon2_guid, 12, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_75mm, ammo2_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_75mm, ammo2_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.apc_weapon_systema, weapon3_guid, 13, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_75mm, ammo3_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_75mm, ammo3_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.apc_weapon_systemd_vs, weapon4_guid, 14, - WeaponData(0x6, 0x8, 0, ObjectClass.flux_cannon_thresher_battery, ammo4_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.flux_cannon_thresher_battery, ammo4_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.apc_ballgun_r, weapon5_guid, 15, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_12mm, ammo5_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_12mm, ammo5_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.apc_ballgun_l, weapon6_guid, 16, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_12mm, ammo6_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_12mm, ammo6_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def aurora(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo11_guid : PlanetSideGUID, ammo12_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo21_guid : PlanetSideGUID, ammo22_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None, - VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false, + //VehicleData(loc, CommonFieldData(faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None, + VehicleData(loc, CommonFieldData(faction, 2), health, DriveState.State7, false, Some(InventoryData( InventoryItemData(ObjectClass.aurora_weapon_systema, weapon1_guid, 5, - WeaponData(0x6, 0x8, 0, ObjectClass.fluxpod_ammo, ammo11_guid, 0, AmmoBoxData(0x8)) + WeaponData(0x6, 0x8, 0, ObjectClass.fluxpod_ammo, ammo11_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.aurora_weapon_systemb, weapon2_guid, 6, - WeaponData(0x6, 0x8, 0, ObjectClass.fluxpod_ammo, ammo21_guid, 0, AmmoBoxData(0x8)) + WeaponData(0x6, 0x8, 0, ObjectClass.fluxpod_ammo, ammo21_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def battlewagon(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID, weapon3_guid : PlanetSideGUID, ammo3_guid : PlanetSideGUID, weapon4_guid : PlanetSideGUID, ammo4_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None, - VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false, + //VehicleData(loc, CommonFieldData(faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None, + VehicleData(loc, CommonFieldData(faction, 2), health, DriveState.State7, false, Some(InventoryData( InventoryItemData(ObjectClass.battlewagon_weapon_systema, weapon1_guid, 5, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_15mm, ammo1_guid, 0, AmmoBoxData(0x8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_15mm, ammo1_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.battlewagon_weapon_systemb, weapon2_guid, 6, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_15mm, ammo2_guid, 0, AmmoBoxData(0x8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_15mm, ammo2_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.battlewagon_weapon_systemc, weapon3_guid, 7, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_15mm, ammo3_guid, 0, AmmoBoxData(0x8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_15mm, ammo3_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.battlewagon_weapon_systemd, weapon4_guid, 8, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_15mm, ammo4_guid, 0, AmmoBoxData(0x8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_15mm, ammo4_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def dropship(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID, weapon3_guid : PlanetSideGUID, ammo3_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)), - VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false, VariantVehicleData(0), + //VehicleData(loc, CommonFieldData(faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)), + VehicleData(loc, CommonFieldData(faction, 2), health, DriveState.State7, false, VariantVehicleData(0), Some(InventoryData( InventoryItemData(ObjectClass.cannon_dropship_20mm, weapon1_guid, 12, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_20mm, ammo1_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_20mm, ammo1_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.cannon_dropship_20mm, weapon2_guid, 13, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_20mm, ammo2_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_20mm, ammo2_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.dropship_rear_turret, weapon3_guid, 14, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_20mm, ammo3_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_20mm, ammo3_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def flail(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo_guid : PlanetSideGUID, terminal_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.Mobile, false, false, false, Some(VariantVehicleData(0)), - VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.Mobile, false, VariantVehicleData(0), + //VehicleData(loc, CommonFieldData(faction, 2), 0, health, false, false, DriveState.Mobile, false, false, false, Some(VariantVehicleData(0)), + VehicleData(loc, CommonFieldData(faction, 2), health, DriveState.Mobile, false, VariantVehicleData(0), Some(InventoryData( InventoryItemData(ObjectClass.flail_weapon, weapon_guid, 1, - WeaponData(0x6, 0x8, 0, ObjectClass.ancient_ammo_vehicle, ammo_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.ancient_ammo_vehicle, ammo_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: - InventoryItemData(ObjectClass.targeting_laser_dispenser, terminal_guid, 2, CommonTerminalData(faction, 2)) :: Nil + InventoryItemData(ObjectClass.targeting_laser_dispenser, terminal_guid, 2, CommonFieldData(faction, 2)(false)) :: Nil )) ) } def fury(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None, - VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false, + //VehicleData(loc, CommonFieldData(faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None, + VehicleData(loc, CommonFieldData(faction, 0), health, DriveState.State7, false, Some(InventoryData( InventoryItemData(ObjectClass.fury_weapon_systema, weapon_guid, 1, - WeaponData(0x4, 0x8, ObjectClass.hellfire_ammo, ammo_guid, 0, AmmoBoxData(0x8)) + WeaponData(0x4, 0x8, ObjectClass.hellfire_ammo, ammo_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def galaxy_gunship(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID, weapon3_guid : PlanetSideGUID, ammo3_guid : PlanetSideGUID, weapon4_guid : PlanetSideGUID, ammo4_guid : PlanetSideGUID, weapon5_guid : PlanetSideGUID, ammo5_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)), - VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false, VariantVehicleData(0), + //VehicleData(loc, CommonFieldData(faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)), + VehicleData(loc, CommonFieldData(faction, 2), health, DriveState.State7, false, VariantVehicleData(0), Some(InventoryData( InventoryItemData(ObjectClass.galaxy_gunship_cannon, weapon1_guid, 6, - WeaponData(0x6, 0x8, 0, ObjectClass.heavy_grenade_mortar, ammo1_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.heavy_grenade_mortar, ammo1_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.galaxy_gunship_cannon, weapon2_guid, 7, - WeaponData(0x6, 0x8, 0, ObjectClass.heavy_grenade_mortar, ammo2_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.heavy_grenade_mortar, ammo2_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.galaxy_gunship_tailgun, weapon3_guid, 8, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_35mm, ammo3_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_35mm, ammo3_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.galaxy_gunship_gun, weapon4_guid, 9, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_35mm, ammo4_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_35mm, ammo4_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.galaxy_gunship_gun, weapon5_guid, 10, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_35mm, ammo5_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_35mm, ammo5_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def liberator(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID, ammo3_guid : PlanetSideGUID, weapon3_guid : PlanetSideGUID, ammo4_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)), - VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false, VariantVehicleData(0), + //VehicleData(loc, CommonFieldData(faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)), + VehicleData(loc, CommonFieldData(faction, 2), health, DriveState.State7, false, VariantVehicleData(0), Some(InventoryData( InventoryItemData(ObjectClass.liberator_weapon_system, weapon1_guid, 3, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_35mm, ammo1_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_35mm, ammo1_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.liberator_bomb_bay, weapon2_guid, 4, - WeaponData(0x6, 0x8, 0, ObjectClass.liberator_bomb, ammo2_guid, 0, AmmoBoxData(8), ObjectClass.liberator_bomb, ammo3_guid, 1, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.liberator_bomb, ammo2_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2), ObjectClass.liberator_bomb, ammo3_guid, 1, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.liberator_25mm_cannon, weapon3_guid, 5, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_25mm, ammo4_guid, 0 ,AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_25mm, ammo4_guid, 0 ,CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def lightgunship(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.Mobile, false, false, false, Some(VariantVehicleData(0)), - VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.Mobile, false, VariantVehicleData(0), + //VehicleData(loc, CommonFieldData(faction, 2), 0, health, false, false, DriveState.Mobile, false, false, false, Some(VariantVehicleData(0)), + VehicleData(loc, CommonFieldData(faction, 2), health, DriveState.Mobile, false, VariantVehicleData(0), Some(InventoryData( InventoryItemData(ObjectClass.lightgunship_weapon_system, weapon_guid, 1, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_20mm, ammo1_guid, 0, AmmoBoxData(8), ObjectClass.reaver_rocket, ammo2_guid,1, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_20mm, ammo1_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2), ObjectClass.reaver_rocket, ammo2_guid,1, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def lightning(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None, - VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false, + //VehicleData(loc, CommonFieldData(faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None, + VehicleData(loc, CommonFieldData(faction, 0), health, DriveState.State7, false, Some(InventoryData( InventoryItemData(ObjectClass.lightning_weapon_system, weapon_guid, 1, - WeaponData(0x4, 0x8, 0, ObjectClass.bullet_75mm, ammo1_guid, 0, AmmoBoxData(0x0), ObjectClass.bullet_12mm, ammo2_guid, 1, AmmoBoxData(0x0)) + WeaponData(0x4, 0x8, 0, ObjectClass.bullet_75mm, ammo1_guid, 0, CommonFieldData()(false), ObjectClass.bullet_12mm, ammo2_guid, 1, CommonFieldData()(false)) ) :: Nil) ) ) } def lodestar(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, repair1_guid : PlanetSideGUID, repair2_guid : PlanetSideGUID, veh_rearm1_guid : PlanetSideGUID, veh_rearm2_guid : PlanetSideGUID, bfr_rearm1_guid : PlanetSideGUID, bfr_rearm2_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)), - VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false, VariantVehicleData(0), + //VehicleData(loc, CommonFieldData(faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)), + VehicleData(loc, CommonFieldData(faction, 2), health, DriveState.State7, false, VariantVehicleData(0), Some(InventoryData(List( - InternalSlot(ObjectClass.lodestar_repair_terminal, repair1_guid, 2, CommonTerminalData(faction, 2)), - InternalSlot(ObjectClass.lodestar_repair_terminal, repair2_guid, 3, CommonTerminalData(faction, 2)), - InternalSlot(ObjectClass.multivehicle_rearm_terminal, veh_rearm1_guid, 4, CommonTerminalData(faction, 2)), - InternalSlot(ObjectClass.multivehicle_rearm_terminal, veh_rearm2_guid, 5, CommonTerminalData(faction, 2)), - InternalSlot(ObjectClass.bfr_rearm_terminal, bfr_rearm1_guid, 6, CommonTerminalData(faction, 2)), - InternalSlot(ObjectClass.bfr_rearm_terminal, bfr_rearm2_guid, 7, CommonTerminalData(faction, 2)) + InternalSlot(ObjectClass.lodestar_repair_terminal, repair1_guid, 2, CommonFieldData(faction, 2)(false)), + InternalSlot(ObjectClass.lodestar_repair_terminal, repair2_guid, 3, CommonFieldData(faction, 2)(false)), + InternalSlot(ObjectClass.multivehicle_rearm_terminal, veh_rearm1_guid, 4, CommonFieldData(faction, 2)(false)), + InternalSlot(ObjectClass.multivehicle_rearm_terminal, veh_rearm2_guid, 5, CommonFieldData(faction, 2)(false)), + InternalSlot(ObjectClass.bfr_rearm_terminal, bfr_rearm1_guid, 6, CommonFieldData(faction, 2)(false)), + InternalSlot(ObjectClass.bfr_rearm_terminal, bfr_rearm2_guid, 7, CommonFieldData(faction, 2)(false)) ))) ) } def magrider(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None, - VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false, + //VehicleData(loc, CommonFieldData(faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None, + VehicleData(loc, CommonFieldData(faction, 2), health, DriveState.State7, false, Some(InventoryData( InventoryItemData(ObjectClass.particle_beam_magrider, weapon1_guid, 2, - WeaponData(0x6, 0x8, 0, ObjectClass.pulse_battery, ammo1_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.pulse_battery, ammo1_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.heavy_rail_beam_magrider, weapon2_guid, 3, - WeaponData(0x6, 0x8, 0, ObjectClass.heavy_rail_beam_battery, ammo2_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.heavy_rail_beam_battery, ammo2_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def mediumtransport(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID): VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None, - VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false, + //VehicleData(loc, CommonFieldData(faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None, + VehicleData(loc, CommonFieldData(faction, 0), health, DriveState.State7, false, Some(InventoryData( InventoryItemData(ObjectClass.mediumtransport_weapon_systemA, weapon1_guid, 5, - WeaponData(0x6, 0x8, ObjectClass.bullet_20mm, ammo1_guid, 0, AmmoBoxData(0x8)) + WeaponData(0x6, 0x8, ObjectClass.bullet_20mm, ammo1_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.mediumtransport_weapon_systemB, weapon2_guid, 6, - WeaponData(0x6, 0x8, ObjectClass.bullet_20mm, ammo2_guid, 0, AmmoBoxData(0x8)) + WeaponData(0x6, 0x8, ObjectClass.bullet_20mm, ammo2_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def mosquito(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)), - VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false, VariantVehicleData(0), + //VehicleData(loc, CommonFieldData(faction, 0), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)), + VehicleData(loc, CommonFieldData(faction, 0), health, DriveState.State7, false, VariantVehicleData(0), Some(InventoryData( InventoryItemData(ObjectClass.rotarychaingun_mosquito, weapon_guid, 1, - WeaponData(0x6, 0x8, ObjectClass.bullet_12mm, ammo_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, ObjectClass.bullet_12mm, ammo_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def phantasm(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)), None)(VehicleFormat.Variant) - VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false, VariantVehicleData(0), None) + //VehicleData(loc, CommonFieldData(faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)), None)(VehicleFormat.Variant) + VehicleData(loc, CommonFieldData(faction, 2), health, DriveState.State7, false, VariantVehicleData(0), None) } def prowler(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None, - VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false, + //VehicleData(loc, CommonFieldData(faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None, + VehicleData(loc, CommonFieldData(faction, 2), health, DriveState.State7, false, Some(InventoryData( InventoryItemData(ObjectClass.prowler_weapon_systemA, weapon1_guid, 3, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_105mm, ammo1_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_105mm, ammo1_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.prowler_weapon_systemB, weapon2_guid, 4, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_15mm, ammo2_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_15mm, ammo2_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def quadassault(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None, - VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false, + //VehicleData(loc, CommonFieldData(faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None, + VehicleData(loc, CommonFieldData(faction, 0), health, DriveState.State7, false, Some(InventoryData( InventoryItemData(ObjectClass.quadassault_weapon_system, weapon_guid, 1, - WeaponData(0x6, 0x8, ObjectClass.bullet_12mm, ammo_guid, 0, AmmoBoxData(0x8)) + WeaponData(0x6, 0x8, ObjectClass.bullet_12mm, ammo_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def quadstealth(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, false, false, false, None, None)(VehicleFormat.Normal) - VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false, None) + //VehicleData(loc, CommonFieldData(faction, 0), 0, health, false, false, DriveState.State7, false, false, false, None, None)(VehicleFormat.Normal) + VehicleData(loc, CommonFieldData(faction, 0), health, DriveState.State7, false, None) } def router(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, terminal_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.Mobile, false, false, false, Some(VariantVehicleData(0)), - VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.Mobile, false, VariantVehicleData(0), + //VehicleData(loc, CommonFieldData(faction, 2), 0, health, false, false, DriveState.Mobile, false, false, false, Some(VariantVehicleData(0)), + VehicleData(loc, CommonFieldData(faction, 2), health, DriveState.Mobile, false, VariantVehicleData(0), Some(InventoryData( - InventoryItemData(ObjectClass.teleportpad_terminal, terminal_guid, 1, CommonTerminalData(faction, 2)) :: Nil + InventoryItemData(ObjectClass.teleportpad_terminal, terminal_guid, 1, CommonFieldData(faction, 2)(false)) :: Nil )) ) } def skyguard(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None, - VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false, + //VehicleData(loc, CommonFieldData(faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None, + VehicleData(loc, CommonFieldData(faction, 2), health, DriveState.State7, false, Some(InventoryData( InventoryItemData(ObjectClass.skyguard_weapon_system, weapon_guid, 2, - WeaponData(0x6, 0x8, 0, ObjectClass.skyguard_flak_cannon_ammo, ammo1_guid, 0, AmmoBoxData(8), ObjectClass.bullet_12mm, ammo2_guid, 1, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.skyguard_flak_cannon_ammo, ammo1_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2), ObjectClass.bullet_12mm, ammo2_guid, 1, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def switchblade(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, driveState : DriveState.Value, weapon_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)), - VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false, VariantVehicleData(0), + //VehicleData(loc, CommonFieldData(faction, 0), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)), + VehicleData(loc, CommonFieldData(faction, 0), health, DriveState.State7, false, VariantVehicleData(0), Some(InventoryData( InventoryItemData(ObjectClass.scythe, weapon_guid, 1, - WeaponData(0x6, 0x8, 0, ObjectClass.ancient_ammo_vehicle, ammo1_guid, 0, AmmoBoxData(0x8), ObjectClass.ancient_ammo_vehicle, ammo2_guid, 1, AmmoBoxData(0x8)) + WeaponData(0x6, 0x8, 0, ObjectClass.ancient_ammo_vehicle, ammo1_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2), ObjectClass.ancient_ammo_vehicle, ammo2_guid, 1, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def threemanheavybuggy(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None, - VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false, + //VehicleData(loc, CommonFieldData(faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None, + VehicleData(loc, CommonFieldData(faction, 0), health, DriveState.State7, false, Some(InventoryData( InventoryItemData(ObjectClass.chaingun_p, weapon1_guid, 3, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_12mm, ammo1_guid, 0, AmmoBoxData(0x8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_12mm, ammo1_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.grenade_launcher_marauder, weapon2_guid, 4, - WeaponData(0x6, 0x8, 0, ObjectClass.heavy_grenade_mortar, ammo2_guid, 0, AmmoBoxData(0x8)) + WeaponData(0x6, 0x8, 0, ObjectClass.heavy_grenade_mortar, ammo2_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def thunderer(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None, - VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false, + //VehicleData(loc, CommonFieldData(faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None, + VehicleData(loc, CommonFieldData(faction, 0), health, DriveState.State7, false, Some(InventoryData( InventoryItemData(ObjectClass.thunderer_weapon_systema, weapon1_guid, 5, - WeaponData(0x6, 0x8, 0, ObjectClass.gauss_cannon_ammo, ammo1_guid, 0, AmmoBoxData(0x8)) + WeaponData(0x6, 0x8, 0, ObjectClass.gauss_cannon_ammo, ammo1_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.thunderer_weapon_systemb, weapon2_guid, 6, - WeaponData(0x6, 0x8, 0, ObjectClass.gauss_cannon_ammo, ammo2_guid, 0, AmmoBoxData(0x8)) + WeaponData(0x6, 0x8, 0, ObjectClass.gauss_cannon_ammo, ammo2_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def two_man_assault_buggy(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None, - VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false, + //VehicleData(loc, CommonFieldData(faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None, + VehicleData(loc, CommonFieldData(faction, 0), health, DriveState.State7, false, Some(InventoryData( InventoryItemData(ObjectClass.chaingun_p, weapon_guid, 2, - WeaponData(0x6, 0x8, ObjectClass.bullet_12mm, ammo_guid, 0, AmmoBoxData(0x8)) + WeaponData(0x6, 0x8, ObjectClass.bullet_12mm, ammo_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def twomanheavybuggy(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None, - VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false, + //VehicleData(loc, CommonFieldData(faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None, + VehicleData(loc, CommonFieldData(faction, 0), health, DriveState.State7, false, Some(InventoryData( InventoryItemData(ObjectClass.advanced_missile_launcher_t, weapon_guid, 2, - WeaponData(0x6, 0x8, 0, ObjectClass.firebird_missile, ammo_guid, 0, AmmoBoxData(0x8)) + WeaponData(0x6, 0x8, 0, ObjectClass.firebird_missile, ammo_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def twomanhoverbuggy(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None, - VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false, + //VehicleData(loc, CommonFieldData(faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None, + VehicleData(loc, CommonFieldData(faction, 0), health, DriveState.State7, false, Some(InventoryData( InventoryItemData(ObjectClass.flux_cannon_thresher, weapon_guid, 2, - WeaponData(0x6, 0x8, 0, ObjectClass.flux_cannon_thresher_battery, ammo_guid, 0, AmmoBoxData(0x8)) + WeaponData(0x6, 0x8, 0, ObjectClass.flux_cannon_thresher_battery, ammo_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def vanguard(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None, - VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false, + //VehicleData(loc, CommonFieldData(faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None, + VehicleData(loc, CommonFieldData(faction, 2), health, DriveState.State7, false, Some(InventoryData( InventoryItemData(ObjectClass.vanguard_weapon_system, weapon_guid, 2, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_150mm, ammo1_guid, 0, AmmoBoxData(8), ObjectClass.bullet_20mm, ammo2_guid, 1, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_150mm, ammo1_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2), ObjectClass.bullet_20mm, ammo2_guid, 1, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def vulture(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID, weapon3_guid : PlanetSideGUID, ammo3_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)), - VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false, VariantVehicleData(0), + //VehicleData(loc, CommonFieldData(faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)), + VehicleData(loc, CommonFieldData(faction, 2), health, DriveState.State7, false, VariantVehicleData(0), Some(InventoryData( InventoryItemData(ObjectClass.vulture_nose_weapon_system, weapon1_guid, 3, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_35mm, ammo1_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_35mm, ammo1_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.vulture_bomb_bay, weapon2_guid, 4, - WeaponData(0x6, 0x8, 0, ObjectClass.liberator_bomb, ammo2_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.liberator_bomb, ammo2_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: InventoryItemData(ObjectClass.vulture_tail_cannon, weapon3_guid, 5, - WeaponData(0x6, 0x8, 0, ObjectClass.bullet_25mm, ammo3_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.bullet_25mm, ammo3_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) } def wasp(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID) : VehicleData = { - //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.Mobile, false, false, false, Some(VariantVehicleData(0)), - VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.Mobile, false, VariantVehicleData(0), + //VehicleData(loc, CommonFieldData(faction, 0), 0, health, false, false, DriveState.Mobile, false, false, false, Some(VariantVehicleData(0)), + VehicleData(loc, CommonFieldData(faction, 0), health, DriveState.Mobile, false, VariantVehicleData(0), Some(InventoryData( InventoryItemData(ObjectClass.wasp_weapon_system, weapon_guid, 1, - WeaponData(0x6, 0x8, 0, ObjectClass.wasp_gun_ammo, ammo1_guid, 0, AmmoBoxData(8), ObjectClass.wasp_rocket_ammo, ammo2_guid, 0, AmmoBoxData(8)) + WeaponData(0x6, 0x8, 0, ObjectClass.wasp_gun_ammo, ammo1_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2), ObjectClass.wasp_rocket_ammo, ammo2_guid, 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) ) :: Nil )) ) diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/REKData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/REKData.scala index eabf66cb..13f6a4d9 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/REKData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/REKData.scala @@ -8,35 +8,33 @@ import shapeless.{::, HNil} /** * na - * @param unk1 na - * @param unk2 na; + * @param data na + * @param unk na; * defaults to 0 * @see `DetailedREKData` */ -final case class REKData(unk1 : Int, - unk2 : Int, - unk3 : Int = 0 +final case class REKData(data : CommonFieldData, + unk : Int = 0 ) extends ConstructorData { override def bitsize : Long = 50L } object REKData extends Marshallable[REKData] { implicit val codec : Codec[REKData] = ( - ("unk1" | uint4L) :: - ("unk2" | uint4L) :: - uint(28) :: - ("unk3" | uint4L) :: + ("data" | CommonFieldData.codec2) :: + uint8 :: + ("unk" | uint8) :: uint(10) ).exmap[REKData] ( { - case unk1 :: unk2 :: 0 :: unk3 :: 0 :: HNil => - Attempt.successful(REKData(unk1, unk2, unk3)) - case _ :: _ :: _ :: _ :: _ :: HNil => - Attempt.failure(Err("invalid rek data format")) + case data :: 0 :: unk :: 0 :: HNil => + Attempt.successful(REKData(data, unk)) + case data => + Attempt.failure(Err(s"invalid rek data format - $data")) }, { - case REKData(unk1, unk2, unk3) => - Attempt.successful(unk1 :: unk2 :: 0 :: unk3 :: 0 :: HNil) + case REKData(data, unk) => + Attempt.successful(data :: 0 :: unk :: 0 :: HNil) } ) } diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/SmallDeployableData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/SmallDeployableData.scala deleted file mode 100644 index c6ac9cd2..00000000 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/SmallDeployableData.scala +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.packet.game.objectcreate - -import net.psforever.packet.Marshallable -import net.psforever.packet.game.PlanetSideGUID -import net.psforever.types.PlanetSideEmpire -import scodec.Codec -import scodec.codecs._ - -/** - * A representation of simple objects that are spawned by the adaptive construction engine. - * //@param deploy data common to objects spawned by the (advanced) adaptive construction engine - */ -final case class SmallDeployableData(pos : PlacementData, - faction : PlanetSideEmpire.Value, - bops : Boolean, - destroyed : Boolean, - unk1 : Int, - jammered : Boolean, - unk2 : Boolean, - owner_guid : PlanetSideGUID) extends ConstructorData { - override def bitsize : Long = { - val posSize = pos.bitsize - 24 + posSize - } -} - -object SmallDeployableData extends Marshallable[SmallDeployableData] { - def apply(pos : PlacementData, faction : PlanetSideEmpire.Value, unk1 : Int, jammered : Boolean, unk2 : Boolean) : SmallDeployableData = { - SmallDeployableData(pos, faction, false, false, unk1, jammered, unk2, PlanetSideGUID(0)) - } - - implicit val codec : Codec[SmallDeployableData] = ( - ("pos" | PlacementData.codec) :: - ("faction" | PlanetSideEmpire.codec) :: - ("bops" | bool) :: - ("destroyed" | bool) :: - ("unk1" | uint2L) :: //3 - na, 2 - common, 1 - na, 0 - common? - ("jammered" | bool) :: - ("unk2" | bool) :: - ("owner_guid" | PlanetSideGUID.codec) - ).as[SmallDeployableData] -} diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/SmallTurretData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/SmallTurretData.scala index 464e2e02..f02df9dd 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/SmallTurretData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/SmallTurretData.scala @@ -3,6 +3,7 @@ package net.psforever.packet.game.objectcreate import net.psforever.packet.Marshallable import net.psforever.packet.game.PlanetSideGUID +import net.psforever.types.PlanetSideEmpire import scodec.codecs._ import scodec.{Attempt, Codec, Err} import shapeless.{::, HNil} @@ -20,7 +21,7 @@ import shapeless.{::, HNil} * @param health the amount of health the object has, as a percentage of a filled bar * @param internals data regarding the mounted weapon */ -final case class SmallTurretData(deploy : SmallDeployableData, +final case class SmallTurretData(deploy : CommonFieldDataWithPlacement, health : Int, internals : Option[InventoryData] = None ) extends ConstructorData { @@ -44,49 +45,11 @@ object SmallTurretData extends Marshallable[SmallTurretData] { * @param internals data regarding the mounted weapon * @return a `SmallTurretData` object */ - def apply(deploy : SmallDeployableData, health : Int, internals : InventoryData) : SmallTurretData = + def apply(deploy : CommonFieldDataWithPlacement, health : Int, internals : InventoryData) : SmallTurretData = new SmallTurretData(deploy, health, Some(internals)) - /** - * Prefabricated weapon data for both Spitfires (`spitfire_turret`) and Shadow Turrets (`spitfire_cloaked`). - * @param wep_guid the uid to assign to the weapon - * @param wep_unk1 na; - * used by `WeaponData` - * @param wep_unk2 na; - * used by `WeaponData` - * @param ammo_guid the uid to assign to the ammo - * @param ammo_unk na; - * used by `AmmoBoxData` - * @return an `InternalSlot` object - */ - def spitfire(wep_guid : PlanetSideGUID, wep_unk1 : Int, wep_unk2 : Int, ammo_guid : PlanetSideGUID, ammo_unk : Int) : InternalSlot = - InternalSlot(ObjectClass.spitfire_weapon, wep_guid, 0, - WeaponData(wep_unk1, wep_unk2, ObjectClass.spitfire_ammo, ammo_guid, 0, - AmmoBoxData(ammo_unk) - ) - ) - - /** - * Prefabricated weapon data for Cerebus turrets (`spitfire_aa`). - * @param wep_guid the uid to assign to the weapon - * @param wep_unk1 na; - * used by `WeaponData` - * @param ammo_guid the uid to assign to the ammo - * @param wep_unk2 na; - * used by `WeaponData` - * @param ammo_unk na; - * used by `AmmoBoxData` - * @return an `InternalSlot` object - */ - def cerebus(wep_guid : PlanetSideGUID, wep_unk1 : Int, wep_unk2 : Int, ammo_guid : PlanetSideGUID, ammo_unk : Int) : InternalSlot = - InternalSlot(ObjectClass.spitfire_aa_weapon, wep_guid, 0, - WeaponData(wep_unk1, wep_unk2, ObjectClass.spitfire_aa_ammo, ammo_guid, 0, - AmmoBoxData(ammo_unk) - ) - ) - implicit val codec : Codec[SmallTurretData] = ( - ("deploy" | SmallDeployableData.codec) :: + ("deploy" | CommonFieldDataWithPlacement.codec2) :: ("health" | uint8L) :: uintL(7) :: uint4L :: @@ -103,8 +66,8 @@ object SmallTurretData extends Marshallable[SmallTurretData] { } Attempt.successful(SmallTurretData(deploy, newHealth, newInternals)) - case _ => - Attempt.failure(Err("invalid small turret data format")) + case data => + Attempt.failure(Err(s"invalid small turret data format - $data")) }, { case SmallTurretData(deploy, health, internals) => diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/TRAPData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/TRAPData.scala index 8128965b..830d06a0 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/TRAPData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/TRAPData.scala @@ -12,7 +12,7 @@ import shapeless.{::, HNil} * @param deploy data common to objects spawned by the (advanced) adaptive construction engine * @param health the amount of health the object has, as a percentage of a filled bar */ -final case class TRAPData(deploy : SmallDeployableData, +final case class TRAPData(deploy : CommonFieldDataWithPlacement, health : Int ) extends ConstructorData { override def bitsize : Long = { @@ -22,7 +22,7 @@ final case class TRAPData(deploy : SmallDeployableData, object TRAPData extends Marshallable[TRAPData] { implicit val codec : Codec[TRAPData] = ( - ("deploy" | SmallDeployableData.codec) :: + ("deploy" | CommonFieldDataWithPlacement.codec2) :: ("health" | uint8L) :: uint(7) :: uint4L :: @@ -32,8 +32,8 @@ object TRAPData extends Marshallable[TRAPData] { case deploy :: health :: 0 :: 15 :: 0 :: HNil => Attempt.successful(TRAPData(deploy, health)) - case _ => - Attempt.failure(Err("invalid trap data format")) + case data => + Attempt.failure(Err(s"invalid trap data format - $data")) }, { case TRAPData(deploy, health) => diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/TelepadData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/TelepadData.scala deleted file mode 100644 index b4ed0f0b..00000000 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/TelepadData.scala +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.packet.game.objectcreate - -import net.psforever.packet.Marshallable -import net.psforever.packet.game.PlanetSideGUID -import scodec.{Attempt, Codec, Err} -import scodec.codecs._ -import shapeless.{::, HNil} - -/** - * A representation of the telepad portion of `ObjectCreateMessage` packet data. - * This data will help construct the "cosntruction tool" - * that can be obtained from the Router vehicle - the Router telepad. - * It issued to construct a bidirectional teleportation point associated with a Router if that Router is deployed. - * @param unk na - * @param router_guid the Router - */ -final case class TelepadData(unk : Int, router_guid : Option[PlanetSideGUID]) extends ConstructorData { - override def bitsize : Long = { - val rguidSize = if(router_guid.nonEmpty) 16 else 0 - 34L + rguidSize - } -} - -object TelepadData extends Marshallable[TelepadData] { - def apply(unk : Int) : TelepadData = TelepadData(unk, None) - - def apply(unk : Int, router_guid : PlanetSideGUID) : TelepadData = TelepadData(unk, Some(router_guid)) - - implicit val codec : Codec[TelepadData] = ( - ("unk" | uint(6)) :: - optional(bool, "router_guid" | PlanetSideGUID.codec) :: - uint(27) - ).exmap[TelepadData] ( - { - case unk :: rguid :: 0 :: HNil => - Attempt.successful(TelepadData(unk, rguid)) - case _ => - Attempt.failure(Err("invalid telepad format")) - }, - { - case TelepadData(unk, rguid) => - Attempt.successful(unk :: rguid :: 0 :: HNil) - } - ) -} diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/TelepadDeployableData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/TelepadDeployableData.scala index 369f641a..160bc490 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/TelepadDeployableData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/TelepadDeployableData.scala @@ -2,54 +2,41 @@ package net.psforever.packet.game.objectcreate import net.psforever.packet.Marshallable -import net.psforever.packet.game.PlanetSideGUID -import net.psforever.types.PlanetSideEmpire -import scodec.Codec +import scodec.{Attempt, Codec, Err} import scodec.codecs._ +import shapeless.{::, HNil} /** * A representation of simple objects that are spawned by the adaptive construction engine. - * @param pos na - * @param faction na - * @param bops na - * @param destroyed na + * @param data data common to game objects * @param unk1 na * @param unk2 na - * @param router_guid the associated Router vehicle; - * this is an essential non-blank (16u 0x0) field; - * a blanked field will cause the client to crash - * @param owner_guid the owner of this telepad - * @param unk3 na - * @param unk4 na */ -//TODO might be CommonFieldData -final case class TelepadDeployableData(pos : PlacementData, - faction : PlanetSideEmpire.Value, - bops : Boolean, - destroyed : Boolean, +final case class TelepadDeployableData(data : CommonFieldData, unk1 : Int, - unk2 : Boolean, - router_guid : PlanetSideGUID, - owner_guid : PlanetSideGUID, - unk3 : Int, - unk4 : Int) extends ConstructorData { + unk2 : Int) extends ConstructorData { override def bitsize : Long = { - val posSize = pos.bitsize - 59 + posSize + 20L + data.bitsize } } object TelepadDeployableData extends Marshallable[TelepadDeployableData] { implicit val codec : Codec[TelepadDeployableData] = ( - ("pos" | PlacementData.codec) :: - ("faction" | PlanetSideEmpire.codec) :: - ("bops" | bool) :: - ("destroyed" | bool) :: - ("unk1" | uint2L) :: //3 - na, 2 - common, 1 - na, 0 - common? - ("unk2" | bool) :: - ("router_guid" | PlanetSideGUID.codec) :: - ("owner_guid" | PlanetSideGUID.codec) :: - ("unk3" | uint16L) :: - ("unk4" | uint4) - ).as[TelepadDeployableData] + ("deploy" | CommonFieldData.codec) :: + ("unk1" | uint8) :: + uint8 :: + ("unk2" | uint4) + ).exmap[TelepadDeployableData] ( + { + case data :: unk1 :: 0 :: unk2 :: HNil => + Attempt.successful(TelepadDeployableData(data, unk1, unk2)) + + case data => + Attempt.failure(Err(s"invalid telepad data format - $data")) + }, + { + case TelepadDeployableData(data, unk1, unk2) => + Attempt.successful(data :: unk1 :: 0 :: unk2 :: HNil) + } + ) } diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/TerminalData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/TerminalData.scala new file mode 100644 index 00000000..65687cc0 --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/TerminalData.scala @@ -0,0 +1,21 @@ +// Copyright (c) 2017 PSForever +package net.psforever.packet.game.objectcreate + +import net.psforever.packet.game.PlanetSideGUID + +/** + * A representation of an object that can be interacted with when using a variety of terminals. + * This object is generally invisible. + */ +object TerminalData { + /** + * Overloaded constructor for a type of common terminal. + * @param cls the code for the type of object being constructed + * @param guid the GUID this object will be assigned + * @param parentSlot a parent-defined slot identifier that explains where the child is to be attached to the parent + * @param terminal the `TerminalData` + * @return an `InternalSlot` object + */ + def apply(cls : Int, guid : PlanetSideGUID, parentSlot : Int, terminal : CommonFieldData) : InternalSlot = + InternalSlot(cls, guid, parentSlot, terminal) +} diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/TrackedProjectileData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/TrackedProjectileData.scala index b2420ca4..dece6e29 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/TrackedProjectileData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/TrackedProjectileData.scala @@ -1,86 +1,57 @@ // Copyright (c) 2017 PSForever package net.psforever.packet.game.objectcreate -import net.psforever.packet.Marshallable +import net.psforever.packet.{Marshallable, PacketHelpers} import scodec.{Attempt, Codec, Err} import scodec.codecs._ import shapeless.{::, HNil} +object TrackedProjectile extends Enumeration { + type Type = Value + + val Meteor = Value(32) + val WaspRocket = Value(208) + val Sparrow = Value(3355579) + val OICW = Value(3355587) + val Striker = Value(6710918) + val HunterSeeker = Value(10131913) + val Starfire = Value(10131961) + + implicit val codec = PacketHelpers.createEnumerationCodec(this, uint24) +} + /** * A representation of a projectile that the server must intentionally convey to players other than the shooter. - * @param pos where and how the projectile is oriented - * @param unk1 na + * @param data na * @param unk2 na; * data specific to the type of projectile(?) + * @param unk3 na */ -final case class TrackedProjectileData(pos : PlacementData, - unk1 : Int, - unk2 : Int +final case class TrackedProjectileData(data : CommonFieldDataWithPlacement, + unk2 : TrackedProjectile.Value, + unk3 : Int = 0 ) extends ConstructorData { - override def bitsize : Long = 56L + pos.bitsize + override def bitsize : Long = 33L + data.bitsize } object TrackedProjectileData extends Marshallable[TrackedProjectileData] { - final val oicw_projectile_data = 3355587 - final val striker_missile_targetting_projectile_data = 6710918 - final val hunter_seeker_missile_projectile_data = 10131913 - final val starfire_projectile_data = 10131961 - - /** - * Overloaded constructor specifically for OICW projectiles. - * @param pos where and how the projectile is oriented - * @param unk na - * @return a `TrackedProjectileData` object - */ - def oicw(pos : PlacementData, unk : Int) : TrackedProjectileData = - new TrackedProjectileData(pos, unk, oicw_projectile_data) - - /** - * Overloaded constructor specifically for Striker projectiles. - * @param pos where and how the projectile is oriented - * @param unk na - * @return a `TrackedProjectileData` object - */ - def striker(pos : PlacementData, unk : Int) : TrackedProjectileData = - new TrackedProjectileData(pos, unk, striker_missile_targetting_projectile_data) - - /** - * Overloaded constructor specifically for Hunter Seeker (Phoenix) projectiles. - * @param pos where and how the projectile is oriented - * @param unk na - * @return a `TrackedProjectileData` object - */ - def hunter_seeker(pos : PlacementData, unk : Int) : TrackedProjectileData = - new TrackedProjectileData(pos, unk, hunter_seeker_missile_projectile_data) - - /** - * Overloaded constructor specifically for Starfire projectiles. - * @param pos where and how the projectile is oriented - * @param unk na - * @return a `TrackedProjectileData` object - */ - def starfire(pos : PlacementData, unk : Int) : TrackedProjectileData = - new TrackedProjectileData(pos, unk, starfire_projectile_data) - implicit val codec : Codec[TrackedProjectileData] = ( - ("pos" | PlacementData.codec) :: - ("unk1" | uint(3)) :: - uint4L :: - uint16L :: - ("unk2" | uint24) :: - uint4L :: - uint(5) + ("data" | CommonFieldDataWithPlacement.codec) :: + ("unk2" | TrackedProjectile.codec) :: + uint4 :: + uint(3) :: + uint2 ).exmap[TrackedProjectileData] ( { - case pos :: unk1 :: 4 :: 0 :: unk2 :: 4 :: 0 :: HNil => - Attempt.successful(TrackedProjectileData(pos, unk1, unk2)) + case data :: unk2 :: 4 :: unk3 :: 0 :: HNil => + Attempt.successful(TrackedProjectileData(data, unk2, unk3)) - case _ => - Attempt.failure(Err("invalid projectile data format")) + case data => + Attempt.failure(Err(s"invalid projectile data format - $data")) }, { - case TrackedProjectileData(pos, unk1, unk2) => - Attempt.successful(pos :: unk1 :: 4 :: 0 :: unk2 :: 4 :: 0 :: HNil) + case TrackedProjectileData(data, unk2, unk3) => + Attempt.successful(data :: unk2 :: 4 :: unk3 :: 0 :: HNil) } ) } diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/VehicleData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/VehicleData.scala index a3d271c8..4030da21 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/VehicleData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/VehicleData.scala @@ -7,7 +7,7 @@ import scodec.Attempt.{Failure, Successful} import scodec.{Attempt, Codec, Err} import shapeless.HNil //note: do not import shapeless.:: here; it messes up List's :: functionality import scodec.codecs._ -import net.psforever.types.{DriveState, PlanetSideEmpire} +import net.psforever.types.DriveState import scala.collection.mutable.ListBuffer @@ -27,7 +27,7 @@ object VehicleFormat extends Enumeration { /** * A basic `Trait` connecting all of the vehicle data formats (excepting `Normal`/`None`). */ -sealed trait SpecificVehicleData extends StreamBitSize +sealed abstract class SpecificVehicleData(val format : VehicleFormat.Value) extends StreamBitSize /** * The format of vehicle data for the type of vehicles that are considered "utility." @@ -36,7 +36,7 @@ sealed trait SpecificVehicleData extends StreamBitSize * the advanced mobile station. * @param unk na */ -final case class UtilityVehicleData(unk : Int) extends SpecificVehicleData { +final case class UtilityVehicleData(unk : Int) extends SpecificVehicleData(VehicleFormat.Utility) { override def bitsize : Long = 6L } @@ -45,24 +45,21 @@ final case class UtilityVehicleData(unk : Int) extends SpecificVehicleData { * This category includes all flying vehicles and the ancient cavern vehicles. * @param unk na */ -final case class VariantVehicleData(unk : Int) extends SpecificVehicleData { +final case class VariantVehicleData(unk : Int) extends SpecificVehicleData(VehicleFormat.Variant) { override def bitsize : Long = 8L } /** * A representation of a generic vehicle. * @param pos where the vehicle is and how it is oriented in the game world - * @param faction the faction that is aligned with this vehicle - * @param bops this vehicle belongs to the Black Ops, regardless of the faction field; - * activates the green camo and adjusts permissions - * @param destroyed this vehicle has ben destroyed; - * it's health should be less than 3/255, or 0% - * @param unk1 na. Valid values seem to be 0-3. Anything higher spawns a completely broken NC vehicle with no guns that can't move - * @param jammered this vehicle is under the influence of a jammer grenade - * @param unk2 na - * @param owner_guid the vehicle's (official) owner; - * verified as a living player in the game world on the same continent as the vehicle; - * sitting in the driver's seat or a `PlanetSideAttributeMessage` of type 21 can influence + * @param data common vehicle field data:
+ * -bops - this vehicle belongs to the Black Ops, regardless of the faction field; + * activates the green camo and adjusts permissions
+ * -destroyed - this vehicle has ben destroyed; + * health should be less than 3/255, or 0%
+ * -jammered - vehicles will not be jammered by setting this field
+ * -player_guid the vehicle's (official) owner; + * a living player in the game world on the same continent as the vehicle who may mount the driver seat * @param unk3 na * @param health the amount of health the vehicle has, as a percentage of a filled bar (255) * @param unk4 na @@ -82,13 +79,7 @@ final case class VariantVehicleData(unk : Int) extends SpecificVehicleData { * defaults to `Normal` */ final case class VehicleData(pos : PlacementData, - faction : PlanetSideEmpire.Value, - bops : Boolean, - destroyed : Boolean, - unk1 : Int, - jammered : Boolean, - unk2 : Boolean, - owner_guid : PlanetSideGUID, + data : CommonFieldData, unk3 : Boolean, health : Int, unk4 : Boolean, @@ -103,9 +94,10 @@ final case class VehicleData(pos : PlacementData, override def bitsize : Long = { //factor guard bool values into the base size, not its corresponding optional field val posSize : Long = pos.bitsize + val dataSize : Long = data.bitsize val extraBitsSize : Long = if(vehicle_format_data.isDefined) { vehicle_format_data.get.bitsize } else { 0L } val inventorySize = if(inventory.isDefined) { inventory.get.bitsize } else { 0L } - 47L + posSize + extraBitsSize + inventorySize + 23L + posSize + dataSize + extraBitsSize + inventorySize } } @@ -118,9 +110,8 @@ object VehicleData extends Marshallable[VehicleData] { * @param cloak if a vehicle (that can cloak) is cloaked * @param inventory the seats, mounted weapons, and utilities (such as terminals) that are currently included */ - def apply(basic : CommonFieldData, health : Int, driveState : DriveState.Value, cloak : Boolean, inventory : Option[InventoryData]) : VehicleData = { - VehicleData(basic.pos, basic.faction, basic.bops, basic.destroyed, 0, basic.jammered, false, basic.player_guid, - false, health, false, false, driveState, false, false, cloak, None, inventory)(VehicleFormat.Normal) + def apply(pos : PlacementData, basic : CommonFieldData, health : Int, driveState : DriveState.Value, cloak : Boolean, inventory : Option[InventoryData]) : VehicleData = { + VehicleData(pos, basic, false, health, false, false, driveState, false, false, cloak, None, inventory)(VehicleFormat.Normal) } /** @@ -131,9 +122,8 @@ object VehicleData extends Marshallable[VehicleData] { * @param cloak if a vehicle (that can cloak) is cloaked * @param inventory the seats, mounted weapons, and utilities (such as terminals) that are currently included */ - def apply(basic : CommonFieldData, health : Int, driveState : DriveState.Value, cloak : Boolean, format : UtilityVehicleData, inventory : Option[InventoryData]) : VehicleData = { - VehicleData(basic.pos, basic.faction, basic.bops, basic.destroyed, 0, basic.jammered, false, basic.player_guid, - false, health, false, false, driveState, false, false, cloak, Some(format), inventory)(VehicleFormat.Utility) + def apply(pos : PlacementData, basic : CommonFieldData, health : Int, driveState : DriveState.Value, cloak : Boolean, format : UtilityVehicleData, inventory : Option[InventoryData]) : VehicleData = { + VehicleData(pos, basic, false, health, false, false, driveState, false, false, cloak, Some(format), inventory)(VehicleFormat.Utility) } /** @@ -144,9 +134,8 @@ object VehicleData extends Marshallable[VehicleData] { * @param cloak if a vehicle (that can cloak) is cloaked * @param inventory the seats, mounted weapons, and utilities (such as terminals) that are currently included */ - def apply(basic : CommonFieldData, health : Int, driveState : DriveState.Value, cloak : Boolean, format : VariantVehicleData, inventory : Option[InventoryData]) : VehicleData = { - VehicleData(basic.pos, basic.faction, basic.bops, basic.destroyed, 0, basic.jammered, false, basic.player_guid, - false, health, false, false, driveState, false, false, cloak, Some(format), inventory)(VehicleFormat.Variant) + def apply(pos : PlacementData, basic : CommonFieldData, health : Int, driveState : DriveState.Value, cloak : Boolean, format : VariantVehicleData, inventory : Option[InventoryData]) : VehicleData = { + VehicleData(pos, basic, false, health, false, false, driveState, false, false, cloak, Some(format), inventory)(VehicleFormat.Variant) } import net.psforever.packet.game.objectcreate.{PlayerData => Player_Data} @@ -163,7 +152,7 @@ object VehicleData extends Marshallable[VehicleData] { * used to calculate the padding value for the player's name in `CharacterAppearanceData` * @return a `PlayerData` object */ - def PlayerData(basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Boolean,Boolean)=>CharacterData, inventory : InventoryData, drawn_slot : DrawnSlot.Type, accumulative : Long) : Player_Data = { + def PlayerData(basic_appearance : Int=>CharacterAppearanceData, character_data : (Boolean,Boolean)=>CharacterData, inventory : InventoryData, drawn_slot : DrawnSlot.Type, accumulative : Long) : Player_Data = { val appearance = basic_appearance(CumulativeSeatedPlayerNamePadding(accumulative)) Player_Data(None, appearance, character_data(appearance.b.backpack, true), Some(inventory), drawn_slot)(false) } @@ -179,12 +168,15 @@ object VehicleData extends Marshallable[VehicleData] { * used to calculate the padding value for the player's name in `CharacterAppearanceData` * @return a `PlayerData` object */ - def PlayerData(basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Boolean,Boolean)=>CharacterData, drawn_slot : DrawnSlot.Type, accumulative : Long) : Player_Data = { + def PlayerData(basic_appearance : Int=>CharacterAppearanceData, character_data : (Boolean,Boolean)=>CharacterData, drawn_slot : DrawnSlot.Type, accumulative : Long) : Player_Data = { val appearance = basic_appearance(CumulativeSeatedPlayerNamePadding(accumulative)) Player_Data.apply(None, appearance, character_data(appearance.b.backpack, true), None, drawn_slot)(false) } - private val driveState8u = PacketHelpers.createEnumerationCodec(DriveState, uint8L) + private val driveState8u = uint8.xmap[DriveState.Value] ( + n => DriveState(n), + n => n.id + ) /** * `Codec` for the "utility" format. @@ -241,13 +233,7 @@ object VehicleData extends Marshallable[VehicleData] { import shapeless.:: ( ("pos" | PlacementData.codec) >>:~ { pos => - ("faction" | PlanetSideEmpire.codec) :: - ("bops" | bool) :: - ("destroyed" | bool) :: - ("unk1" | uint2L) :: //3 - na, 2 - common, 1 - na, 0 - common? - ("jammered" | bool) :: - ("unk2" | bool) :: - ("owner_guid" | PlanetSideGUID.codec) :: + ("data" | CommonFieldData.codec2(false)) :: ("unk3" | bool) :: ("health" | uint8L) :: ("unk4" | bool) :: //usually 0 @@ -261,14 +247,14 @@ object VehicleData extends Marshallable[VehicleData] { } ).exmap[VehicleData] ( { - case pos :: faction :: bops :: destroyed :: u1 :: jamd :: u2 :: owner :: u3 :: health :: u4 :: no_mount :: driveState :: u5 :: u6 :: cloak :: format :: inv :: HNil => - Attempt.successful(new VehicleData(pos, faction, bops, destroyed, u1, jamd, u2, owner, u3, health, u4, no_mount, driveState, u5, u6, cloak, format, inv)(vehicle_type)) + case pos :: data :: u3 :: health :: u4 :: no_mount :: driveState :: u5 :: u6 :: cloak :: format :: inv :: HNil => + Attempt.successful(new VehicleData(pos, data, u3, health, u4, no_mount, driveState, u5, u6, cloak, format, inv)(vehicle_type)) - case _ => - Attempt.failure(Err("invalid vehicle data format")) + case data => + Attempt.failure(Err(s"invalid vehicle data format - $data")) }, { - case obj @ VehicleData(pos, faction, bops, destroyed, u1, jamd, u2, owner, u3, health, u4, no_mount, driveState, u5, u6, cloak, format, inv) => + case obj @ VehicleData(pos, data, u3, health, u4, no_mount, driveState, u5, u6, cloak, format, inv) => if(obj.vehicle_type == VehicleFormat.Normal && format.nonEmpty) { Attempt.failure(Err("invalid vehicle data format; variable bits not expected")) } @@ -276,11 +262,8 @@ object VehicleData extends Marshallable[VehicleData] { Attempt.failure(Err(s"invalid vehicle data format; variable bits for ${obj.vehicle_type} expected")) } else { - Attempt.successful(pos :: faction :: bops :: destroyed :: u1 :: jamd :: u2 :: owner :: u3 :: health :: u4 :: no_mount :: driveState :: u5 :: u6 :: cloak :: format :: inv :: HNil) + Attempt.successful(pos :: data :: u3 :: health :: u4 :: no_mount :: driveState :: u5 :: u6 :: cloak :: format :: inv :: HNil) } - - case _ => - Attempt.failure(Err("invalid vehicle data format")) } ) } diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/WeaponData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/WeaponData.scala index b27e53d8..88b63596 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/WeaponData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/WeaponData.scala @@ -3,6 +3,7 @@ package net.psforever.packet.game.objectcreate import net.psforever.packet.Marshallable import net.psforever.packet.game.PlanetSideGUID +import net.psforever.types.PlanetSideEmpire import scodec.{Attempt, Codec, Err} import scodec.codecs._ import shapeless.{::, HNil} @@ -15,32 +16,22 @@ import shapeless.{::, HNil} * The data for the weapons nests information for the default (current) type of ammunition and number of ammunitions in its magazine(s). * This ammunition data essentially is the weapon's magazines as numbered slots. * An "expected" number of ammunition slot data can be passed into the class for the purposes of validating input. - * @param unk1 na; + * @param data na; * commonly 8 - * @param unk2 na; - * commonly 12 * @param fire_mode the current mode of weapon's fire; * zero-indexed * @param ammo data regarding the currently loaded ammunition type(s) - * @param mag_capacity implicit; - * the total number of concurrently-loaded ammunition types allowed in this weapon; - * concurrent ammunition does not need to be unloaded to be switched; - * defaults to 1; - * 0 is invalid; - * -1 or less ignores the imposed checks * @see `AmmoBoxData` */ -final case class WeaponData(unk1 : Int, - unk2 : Int, +final case class WeaponData(data : CommonFieldData, fire_mode : Int, - ammo : List[InternalSlot] - )(implicit val mag_capacity : Int = 1) extends ConstructorData { + ammo : List[InternalSlot], + unk : Boolean = false + ) extends ConstructorData { override def bitsize : Long = { - var bitsize : Long = 0L - for(o <- ammo) { - bitsize += o.bitsize - } - 44L + bitsize + val dataSize = data.bitsize + val ammoSize : Long = ammo.foldLeft(0L)(_ + _.bitsize) + 21L + dataSize + ammoSize //11 + 10 (from InventoryData) + ammo } } @@ -55,8 +46,23 @@ object WeaponData extends Marshallable[WeaponData] { * @param ammo the ammunition object * @return a `WeaponData` object */ - def apply(unk1 : Int, unk2 : Int, cls : Int, guid : PlanetSideGUID, parentSlot : Int, ammo : AmmoBoxData) : WeaponData = - new WeaponData(unk1, unk2, 0, InternalSlot(cls, guid, parentSlot, ammo) :: Nil) + def apply(unk1 : Int, unk2 : Int, cls : Int, guid : PlanetSideGUID, parentSlot : Int, ammo : CommonFieldData) : WeaponData = { + WeaponData( + CommonFieldData( + PlanetSideEmpire(unk1 & 3), + false, + false, + (unk2 & 8) == 8, + None, + (unk2 & 4) == 4, + None, + None, + PlanetSideGUID(0) + ), + 0, + List(InternalSlot(cls, guid, parentSlot, ammo)) + ) + } /** * Overloaded constructor for creating `WeaponData` that mandates information about the firemode and a single type of ammunition. @@ -69,8 +75,23 @@ object WeaponData extends Marshallable[WeaponData] { * @param ammo the ammunition object * @return a `WeaponData` object */ - def apply(unk1 : Int, unk2 : Int, fire_mode : Int, cls : Int, guid : PlanetSideGUID, parentSlot : Int, ammo : AmmoBoxData) : WeaponData = - WeaponData(unk1, unk2, fire_mode, InternalSlot(cls, guid, parentSlot, ammo) :: Nil) + def apply(unk1 : Int, unk2 : Int, fire_mode : Int, cls : Int, guid : PlanetSideGUID, parentSlot : Int, ammo : CommonFieldData) : WeaponData = { + WeaponData( + CommonFieldData( + PlanetSideEmpire(unk1 & 3), + false, + false, + (unk2 & 8) == 8, + None, + (unk2 & 4) == 4, + None, + None, + PlanetSideGUID(0) + ), + fire_mode, + List(InternalSlot(cls, guid, parentSlot, ammo)) + ) + } /** * Overloaded constructor for creating `WeaponData` with two types of ammunition concurrently loaded. @@ -88,71 +109,59 @@ object WeaponData extends Marshallable[WeaponData] { * @param ammo2 the second ammunition object * @return a `WeaponData` object */ - def apply(unk1 : Int, unk2 : Int, fire_mode : Int, cls1 : Int, guid1 : PlanetSideGUID, slot1 : Int, ammo1 : AmmoBoxData, cls2 : Int, guid2 : PlanetSideGUID, slot2 : Int, ammo2 : AmmoBoxData) : WeaponData = - WeaponData(unk1, unk2, fire_mode, InternalSlot(cls1, guid1, slot1, ammo1) :: InternalSlot(cls2, guid2, slot2, ammo2) :: Nil)(2) + def apply(unk1 : Int, unk2 : Int, fire_mode : Int, cls1 : Int, guid1 : PlanetSideGUID, slot1 : Int, ammo1 : CommonFieldData, cls2 : Int, guid2 : PlanetSideGUID, slot2 : Int, ammo2 : CommonFieldData) : WeaponData ={ + WeaponData( + CommonFieldData( + PlanetSideEmpire(unk1 & 3), + false, + false, + (unk2 & 8) == 8, + None, + (unk2 & 4) == 4, + None, + None, + PlanetSideGUID(0) + ), + fire_mode, + List(InternalSlot(cls1, guid1, slot1, ammo1), InternalSlot(cls2, guid2, slot2, ammo2)) + ) + } - /** - * A `Codec` for `WeaponData`. - * @param mag_capacity the total number of concurrently-loaded ammunition types allowed in this weapon; - * defaults to 1 - * @return a `WeaponData` object or a `BitVector` - */ - def codec(mag_capacity : Int = 1) : Codec[WeaponData] = ( - ("unk1" | uintL(3)) :: - bool :: //weapon refuses to shoot if set (not weapons lock?) - ("unk2" | uint4L) :: //8 - common; 4 - jammers weapons; 2 - weapon breaks; 1, 0 - safe - uint(20) :: - ("fire_mode" | int(3)) :: //TODO size? + implicit val codec : Codec[WeaponData] = ( + ("data" | CommonFieldData.codec) :: + ("fire_mode" | int8) :: bool :: - bool :: - ("ammo" | InventoryData.codec) :: - bool + optional(bool, "ammo" | InventoryData.codec) :: + ("unk" | bool) ).exmap[WeaponData] ( { - case unk1 :: false :: unk2 :: 0 :: fmode :: false :: true :: InventoryData(ammo) :: false :: HNil => + case data :: fmode :: false :: Some(InventoryData(ammo)) :: unk :: HNil => val magSize = ammo.size - if(mag_capacity == 0 || magSize == 0) { + if(magSize == 0) { Attempt.failure(Err("weapon must decode some ammunition")) } - else if(mag_capacity > 0 && magSize != mag_capacity) { - Attempt.failure(Err(s"weapon decodes too much or too little ammunition - actual $magSize, expected $mag_capacity")) - } else { - Attempt.successful(WeaponData(unk1, unk2, fmode, ammo)(magSize)) + Attempt.successful(WeaponData(data, fmode, ammo, unk)) } - case _ => - Attempt.failure(Err("invalid weapon data format")) + case data => + Attempt.failure(Err(s"invalid weapon data format - $data")) }, { - case obj @ WeaponData(unk1, unk2, fmode, ammo) => + case WeaponData(data, fmode, ammo, unk) => val magSize = ammo.size - val magCapacity = obj.mag_capacity - if(mag_capacity == 0 || magCapacity == 0 || magSize == 0) { + if(magSize == 0) { Attempt.failure(Err("weapon must encode some ammunition")) } else if(magSize >= 255) { Attempt.failure(Err("weapon encodes too much ammunition (255+ types!)")) } - else if(magCapacity < 0 || mag_capacity < 0) { - Attempt.successful(unk1 :: false :: unk2 :: 0 :: fmode :: false :: true :: InventoryData(ammo) :: false :: HNil) - } else { - if(magCapacity != mag_capacity) { - Attempt.failure(Err(s"different encoding expectations for amount of ammunition - actual $magCapacity, expected $mag_capacity")) - } - else if(magSize != mag_capacity) { - Attempt.failure(Err(s"weapon encodes wrong amount of ammunition - actual $magSize, expected $mag_capacity")) - } - else { - Attempt.successful(unk1 :: false :: unk2 :: 0 :: fmode :: false :: true :: InventoryData(ammo) :: false :: HNil) - } + Attempt.successful(data :: fmode :: false :: Some(InventoryData(ammo)) :: unk :: HNil) } case _ => Attempt.failure(Err("invalid weapon data format")) } ) - - implicit val codec : Codec[WeaponData] = codec() } diff --git a/common/src/main/scala/net/psforever/types/DriveState.scala b/common/src/main/scala/net/psforever/types/DriveState.scala index e32c774a..07109a68 100644 --- a/common/src/main/scala/net/psforever/types/DriveState.scala +++ b/common/src/main/scala/net/psforever/types/DriveState.scala @@ -1,8 +1,5 @@ package net.psforever.types -import net.psforever.packet.PacketHelpers -import scodec.codecs.uint - /** * An `Enumeration` of the mobility states of vehicles.
*
@@ -19,6 +16,5 @@ object DriveState extends Enumeration { val Deploying = Value(2) val Deployed = Value(3) val State7 = Value(7) //unknown; not encountered on a vehicle that can deploy; functions like Mobile - - implicit val codec = PacketHelpers.createEnumerationCodec(this, uint(3)) + val State127 = Value(127) //unknown } diff --git a/common/src/test/scala/CosmeticsTest.scala b/common/src/test/scala/CosmeticsTest.scala new file mode 100644 index 00000000..4d67324d --- /dev/null +++ b/common/src/test/scala/CosmeticsTest.scala @@ -0,0 +1,84 @@ +// Copyright (c) 2019 PSForever +import net.psforever.packet.game.objectcreate.{Cosmetics, PersonalStyle} +import org.specs2.mutable._ +import net.psforever.types.Vector3 + +class CosmeticsTest extends Specification { + "Cosmetics" should { + "construct" in { + Cosmetics() + Cosmetics(3) + Cosmetics(PersonalStyle.NoHelmet) + Cosmetics(Set(PersonalStyle.NoHelmet)) + Cosmetics(true, false, false, false, false) + ok + } + + "translate into a numeric value" in { + Cosmetics().pstyles mustEqual 0 + Cosmetics(3).pstyles mustEqual 3 + Cosmetics(PersonalStyle.NoHelmet).pstyles mustEqual PersonalStyle.NoHelmet.id + Cosmetics(Set(PersonalStyle.NoHelmet, PersonalStyle.Earpiece)).pstyles mustEqual PersonalStyle.NoHelmet.id + PersonalStyle.Earpiece.id + Cosmetics(true, false, false, false, false).pstyles mustEqual PersonalStyle.NoHelmet.id + } + + "translate into a list of cosmetic style tokens" in { + Cosmetics().Styles mustEqual Set() + Cosmetics(3).Styles mustEqual Set(PersonalStyle.BrimmedCap, PersonalStyle.Earpiece) + Cosmetics(PersonalStyle.NoHelmet).Styles mustEqual Set(PersonalStyle.NoHelmet) + Cosmetics(Set(PersonalStyle.NoHelmet)).Styles mustEqual Set(PersonalStyle.NoHelmet) + Cosmetics(true, false, false, false, false).Styles mustEqual Set(PersonalStyle.NoHelmet) + } + + "report containing specific values only" in { + val cos = Cosmetics(Set(PersonalStyle.NoHelmet, PersonalStyle.Earpiece)) + cos.contains(PersonalStyle.NoHelmet) mustEqual true + cos.contains(PersonalStyle.Beret) mustEqual false + } + + "add values" in { + val cos = Cosmetics() + cos.Styles mustEqual Set() + val cos1 = cos + PersonalStyle.NoHelmet + cos1.Styles mustEqual Set(PersonalStyle.NoHelmet) + cos1.Styles mustNotEqual cos.Styles + val cos2 = cos1 + PersonalStyle.Beret + cos2.Styles mustEqual Set(PersonalStyle.NoHelmet, PersonalStyle.Beret) + cos2.Styles mustNotEqual cos.Styles + cos2.Styles mustNotEqual cos1.Styles + } + + "can not add already included values" in { + val cos = Cosmetics(Set(PersonalStyle.NoHelmet, PersonalStyle.Beret)) + cos.Styles mustEqual Set(PersonalStyle.NoHelmet, PersonalStyle.Beret) + val cos1 = cos + PersonalStyle.Beret + cos1.Styles mustEqual Set(PersonalStyle.NoHelmet, PersonalStyle.Beret) + cos ne cos1 mustEqual true + } + + "remove values" in { + val cos = Cosmetics(Set(PersonalStyle.NoHelmet, PersonalStyle.Beret)) + cos.Styles mustEqual Set(PersonalStyle.NoHelmet, PersonalStyle.Beret) + val cos1 = cos - PersonalStyle.NoHelmet + cos1.Styles mustEqual Set(PersonalStyle.Beret) + cos1.Styles mustNotEqual cos.Styles + val cos2 = cos1 - PersonalStyle.Beret + cos2.Styles mustEqual Set() + cos2.Styles mustNotEqual cos.Styles + cos2.Styles mustNotEqual cos1.Styles + } + + "can not remove un-included or already excluded values" in { + val cos = Cosmetics(Set(PersonalStyle.NoHelmet, PersonalStyle.Beret)) + cos.Styles mustEqual Set(PersonalStyle.NoHelmet, PersonalStyle.Beret) + val cos1 = cos - PersonalStyle.Beret + cos1.Styles mustEqual Set(PersonalStyle.NoHelmet) + + val cos2 = cos - PersonalStyle.Beret //again + cos2.Styles mustEqual Set(PersonalStyle.NoHelmet) + + val cos3 = cos1 - PersonalStyle.Earpiece + cos3.Styles mustEqual Set(PersonalStyle.NoHelmet) + } + } +} diff --git a/common/src/test/scala/game/ObjectCreateBaseTest.scala b/common/src/test/scala/game/ObjectCreateBaseTest.scala deleted file mode 100644 index c3ebe1bd..00000000 --- a/common/src/test/scala/game/ObjectCreateBaseTest.scala +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2017 PSForever -package game - -import org.specs2.mutable._ -import net.psforever.packet._ -import net.psforever.packet.game.{ObjectCreateDetailedMessage, _} -import net.psforever.packet.game.objectcreate._ -import scodec.bits._ - -class ObjectCreateBaseTest extends Specification { - val packet217 = hex"17 F8 00 00 00 BC 8C 10 90 3B 45 C6 FA 94 00 9F F0 00 00 40 00 08 C0 44 00 69 00 66 00 66 00 45" //fake data - val packet218 = hex"18 F8 00 00 00 BC 8C 10 90 3B 45 C6 FA 94 00 9F F0 00 00 40 00 08 C0 44 00 69 00 66 00 66 00 45" //fake data - - "ObjectCreateDetailedMessage" should { - "fail to decode" in { - //an invalid bit representation will fail to turn into an object - PacketCoding.DecodePacket(packet217).require match { - case ObjectCreateMessage(len, cls, guid, parent, data) => - len mustEqual 248 - cls mustEqual ObjectClass.avatar - guid mustEqual PlanetSideGUID(2497) - parent mustEqual None - data.isDefined mustEqual false - case _ => - ko - } - } - - "fail to encode" in { - //the lack of an object will fail to turn into a bad bitstream - val msg = ObjectCreateMessage(0L, ObjectClass.avatar, PlanetSideGUID(2497), None, None) - PacketCoding.EncodePacket(msg).isFailure mustEqual true - } - } - - "ObjectCreateDetailedMessage" should { - "fail to decode" in { - //an invalid bit representation will fail to turn into an object - PacketCoding.DecodePacket(packet218).require match { - case ObjectCreateDetailedMessage(len, cls, guid, parent, data) => - len mustEqual 248 - cls mustEqual ObjectClass.avatar - guid mustEqual PlanetSideGUID(2497) - parent mustEqual None - data.isDefined mustEqual false - case _ => - ko - } - } - - "fail to encode" in { - //the lack of an object will fail to turn into a bad bitstream - val msg = ObjectCreateDetailedMessage(0L, ObjectClass.avatar, PlanetSideGUID(2497), None, None) - PacketCoding.EncodePacket(msg).isFailure mustEqual true - } - } - - "StreamBitSize" should { - "have zero size by default" in { - new StreamBitSize() {}.bitsize mustEqual 0L - } - } -} diff --git a/common/src/test/scala/game/objectcreate/ACEDataTest.scala b/common/src/test/scala/game/objectcreate/ACEDataTest.scala deleted file mode 100644 index 980e4d56..00000000 --- a/common/src/test/scala/game/objectcreate/ACEDataTest.scala +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2017 PSForever -package game.objectcreate - -import net.psforever.packet.PacketCoding -import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} -import net.psforever.packet.game.objectcreate._ -import org.specs2.mutable._ -import scodec.bits._ - -class ACEDataTest extends Specification { - val string_ace_held = hex"17 76000000 0406900650C80480000000" - val string_ace_dropped = hex"17 AF000000 90024113B329C5D5A2D1200005B440000000" - - "ACEData" should { - "decode (held)" in { - PacketCoding.DecodePacket(string_ace_held).require match { - case ObjectCreateMessage(len, cls, guid, parent, data) => - len mustEqual 118 - cls mustEqual ObjectClass.ace - guid mustEqual PlanetSideGUID(3173) - parent.isDefined mustEqual true - parent.get.guid mustEqual PlanetSideGUID(3336) - parent.get.slot mustEqual 0 - data.isDefined mustEqual true - data.get.isInstanceOf[ACEData] mustEqual true - val ace = data.get.asInstanceOf[ACEData] - ace.unk1 mustEqual 4 - ace.unk2 mustEqual 8 - ace.unk3 mustEqual 0 - case _ => - ko - } - } - - "decode (dropped)" in { - PacketCoding.DecodePacket(string_ace_dropped).require match { - case ObjectCreateMessage(len, cls, guid, parent, data) => - len mustEqual 175 - cls mustEqual ObjectClass.ace - guid mustEqual PlanetSideGUID(4388) - parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[DroppedItemData[_]] mustEqual true - val drop = data.get.asInstanceOf[DroppedItemData[_]] - drop.pos.coord.x mustEqual 4708.461f - drop.pos.coord.y mustEqual 5547.539f - drop.pos.coord.z mustEqual 72.703125f - drop.pos.orient.x mustEqual 0f - drop.pos.orient.y mustEqual 0f - drop.pos.orient.z mustEqual 194.0625f - drop.obj.isInstanceOf[ACEData] mustEqual true - val ace = drop.obj.asInstanceOf[ACEData] - ace.unk1 mustEqual 8 - ace.unk2 mustEqual 8 - case _ => - ko - } - } - - "encode (held)" in { - val obj = ACEData(4, 8) - val msg = ObjectCreateMessage(ObjectClass.ace, PlanetSideGUID(3173), ObjectCreateMessageParent(PlanetSideGUID(3336), 0), obj) - val pkt = PacketCoding.EncodePacket(msg).require.toByteVector - pkt mustEqual string_ace_held - } - - "encode (dropped)" in { - val obj = DroppedItemData( - PlacementData(4708.461f, 5547.539f, 72.703125f, 0f, 0f, 194.0625f), - ACEData(8, 8) - ) - val msg = ObjectCreateMessage(ObjectClass.ace, PlanetSideGUID(4388), obj) - val pkt = PacketCoding.EncodePacket(msg).require.toByteVector - pkt mustEqual string_ace_dropped - } - } -} diff --git a/common/src/test/scala/game/objectcreate/AegisShieldGeneratorDataTest.scala b/common/src/test/scala/game/objectcreate/AegisShieldGeneratorDataTest.scala index 8772daf2..49d16d86 100644 --- a/common/src/test/scala/game/objectcreate/AegisShieldGeneratorDataTest.scala +++ b/common/src/test/scala/game/objectcreate/AegisShieldGeneratorDataTest.scala @@ -19,15 +19,24 @@ class AegisShieldGeneratorDataTest extends Specification { cls mustEqual ObjectClass.deployable_shield_generator guid mustEqual PlanetSideGUID(2556) parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[AegisShieldGeneratorData] mustEqual true - val aegis = data.get.asInstanceOf[AegisShieldGeneratorData] - aegis.deploy.pos.coord mustEqual Vector3(3571.2266f, 3278.0938f, 114.0f) - aegis.deploy.pos.orient mustEqual Vector3(0, 0, 90) - aegis.deploy.faction mustEqual PlanetSideEmpire.VS - aegis.deploy.unk mustEqual 2 - aegis.health mustEqual 255 - aegis.deploy.player_guid mustEqual PlanetSideGUID(2366) + data match { + case AegisShieldGeneratorData(basic, health) => + basic.pos.coord mustEqual Vector3(3571.2266f, 3278.0938f, 114.0f) + basic.pos.orient mustEqual Vector3.z(90.0f) + + basic.data.faction mustEqual PlanetSideEmpire.VS + basic.data.bops mustEqual false + basic.data.alternate mustEqual false + basic.data.v1 mustEqual true + basic.data.v2.isDefined mustEqual false + basic.data.v3 mustEqual false + basic.data.v5.isDefined mustEqual false + basic.data.guid mustEqual PlanetSideGUID(2366) + + health mustEqual 255 + case _ => + ko + } case _ => ko } @@ -35,7 +44,7 @@ class AegisShieldGeneratorDataTest extends Specification { "encode" in { val obj = AegisShieldGeneratorData( - CommonFieldData( + CommonFieldDataWithPlacement( PlacementData(Vector3(3571.2266f, 3278.0938f, 114.0f), Vector3(0, 0, 90)), PlanetSideEmpire.VS, 2, PlanetSideGUID(2366) ), diff --git a/common/src/test/scala/game/objectcreate/AmmoBoxDataTest.scala b/common/src/test/scala/game/objectcreate/AmmoBoxDataTest.scala deleted file mode 100644 index a3da9440..00000000 --- a/common/src/test/scala/game/objectcreate/AmmoBoxDataTest.scala +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2017 PSForever -package game.objectcreate - -import net.psforever.packet.PacketCoding -import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} -import net.psforever.packet.game.objectcreate._ -import org.specs2.mutable._ -import scodec.bits._ - -class AmmoBoxDataTest extends Specification { - val string_shotgunshell_dropped = hex"17 A5000000 F9A7D0D 5E269 BED5A F114 0000596000000" - - "AmmoBoxData" should { - "decode (shotgun shells, dropped)" in { - PacketCoding.DecodePacket(string_shotgunshell_dropped).require match { - case ObjectCreateMessage(len, cls, guid, parent, data) => - len mustEqual 165 - cls mustEqual ObjectClass.shotgun_shell - guid mustEqual PlanetSideGUID(3453) - parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[DroppedItemData[_]] mustEqual true - val drop = data.get.asInstanceOf[DroppedItemData[_]] - drop.pos.coord.x mustEqual 4684.7344f - drop.pos.coord.y mustEqual 5547.4844f - drop.pos.coord.z mustEqual 83.765625f - drop.pos.orient.x mustEqual 0f - drop.pos.orient.y mustEqual 0f - drop.pos.orient.z mustEqual 199.6875f - drop.obj.isInstanceOf[AmmoBoxData] mustEqual true - val box = drop.obj.asInstanceOf[AmmoBoxData] - box.unk mustEqual 0 - case _ => - ko - } - } - - "encode (shotgun shells, dropped)" in { - val obj = DroppedItemData( - PlacementData(4684.7344f, 5547.4844f, 83.765625f, 0f, 0f, 199.6875f), - AmmoBoxData() - ) - val msg = ObjectCreateMessage(ObjectClass.shotgun_shell, PlanetSideGUID(3453), obj) - val pkt = PacketCoding.EncodePacket(msg).require.toByteVector - pkt mustEqual string_shotgunshell_dropped - } - } -} diff --git a/common/src/test/scala/game/objectcreate/BoomerTriggerDataTest.scala b/common/src/test/scala/game/objectcreate/BoomerTriggerDataTest.scala deleted file mode 100644 index db5c61d2..00000000 --- a/common/src/test/scala/game/objectcreate/BoomerTriggerDataTest.scala +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2017 PSForever -package game.objectcreate - -import net.psforever.packet.PacketCoding -import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} -import net.psforever.packet.game.objectcreate._ -import org.specs2.mutable._ -import scodec.bits._ - -class BoomerTriggerDataTest extends Specification { - val string_boomertrigger = hex"17 76000000 58084A8100E80C00000000" //reconstructed from an inventory entry - - "BoomerTriggerData" should { - "decode (held)" in { - PacketCoding.DecodePacket(string_boomertrigger).require match { - case ObjectCreateMessage(len, cls, guid, parent, data) => - len mustEqual 118 - cls mustEqual ObjectClass.boomer_trigger - guid mustEqual PlanetSideGUID(3600) - parent.isDefined mustEqual true - parent.get.guid mustEqual PlanetSideGUID(4272) - parent.get.slot mustEqual 0 - data.isDefined mustEqual true - data.get.isInstanceOf[BoomerTriggerData] mustEqual true - data.get.asInstanceOf[BoomerTriggerData].unk mustEqual 0 - case _ => - ko - } - } - - "encode (held)" in { - val obj = BoomerTriggerData(0) - val msg = ObjectCreateMessage(ObjectClass.boomer_trigger, PlanetSideGUID(3600), ObjectCreateMessageParent(PlanetSideGUID(4272), 0), obj) - val pkt = PacketCoding.EncodePacket(msg).require.toByteVector - pkt mustEqual string_boomertrigger - } - } -} diff --git a/common/src/test/scala/game/objectcreate/CaptureFlagDataTest.scala b/common/src/test/scala/game/objectcreate/CaptureFlagDataTest.scala index ee78c7ef..ddd0d872 100644 --- a/common/src/test/scala/game/objectcreate/CaptureFlagDataTest.scala +++ b/common/src/test/scala/game/objectcreate/CaptureFlagDataTest.scala @@ -19,9 +19,8 @@ class CaptureFlagDataTest extends Specification { cls mustEqual ObjectClass.capture_flag guid mustEqual PlanetSideGUID(4330) parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[CaptureFlagData] mustEqual true - val flag = data.get.asInstanceOf[CaptureFlagData] + data.isInstanceOf[CaptureFlagData] mustEqual true + val flag = data.asInstanceOf[CaptureFlagData] flag.pos.coord.x mustEqual 3912.0312f flag.pos.coord.y mustEqual 5169.4375f flag.pos.coord.z mustEqual 59.96875f diff --git a/common/src/test/scala/game/objectcreate/CharacterDataTest.scala b/common/src/test/scala/game/objectcreate/CharacterDataTest.scala index d0d14d1b..eece5121 100644 --- a/common/src/test/scala/game/objectcreate/CharacterDataTest.scala +++ b/common/src/test/scala/game/objectcreate/CharacterDataTest.scala @@ -27,7 +27,7 @@ class CharacterDataTest extends Specification { guid mustEqual PlanetSideGUID(3902) parent.isDefined mustEqual false data match { - case Some(PlayerData(Some(pos), basic, char, inv, hand)) => + case PlayerData(Some(pos), basic, char, inv, hand) => pos.coord mustEqual Vector3(3674.8438f, 2726.789f, 91.15625f) pos.orient mustEqual Vector3(0f, 0f, 64.6875f) pos.vel.isDefined mustEqual true @@ -40,13 +40,13 @@ class CharacterDataTest extends Specification { a.app.sex mustEqual CharacterGender.Male a.app.head mustEqual 5 a.app.voice mustEqual CharacterVoice.Voice5 - a.black_ops mustEqual false - a.jammered mustEqual false + a.data.bops mustEqual false + a.data.v1 mustEqual false + a.data.v2.isEmpty mustEqual true + a.data.v3 mustEqual false + a.data.v4.isEmpty mustEqual true + a.data.v5.isEmpty mustEqual true a.exosuit mustEqual ExoSuitType.Reinforced - a.unk1 mustEqual false - a.unk2 mustEqual None - a.unk3 mustEqual None - a.unk4 mustEqual 0 a.unk5 mustEqual 0 a.unk6 mustEqual 30777081L a.unk7 mustEqual 1 @@ -63,7 +63,7 @@ class CharacterDataTest extends Specification { b.grenade_state mustEqual GrenadeState.None b.is_cloaking mustEqual false b.charging_pose mustEqual false - b.on_zipline mustEqual None + b.on_zipline.isEmpty mustEqual true b.unk0 mustEqual 316554L b.unk1 mustEqual false b.unk2 mustEqual false @@ -87,12 +87,12 @@ class CharacterDataTest extends Specification { char.command_rank mustEqual 5 char.implant_effects.length mustEqual 1 char.implant_effects.head mustEqual ImplantEffects.NoEffects - char.cosmetics.isDefined mustEqual true - char.cosmetics.get.no_helmet mustEqual true - char.cosmetics.get.beret mustEqual true - char.cosmetics.get.sunglasses mustEqual true - char.cosmetics.get.earpiece mustEqual true - char.cosmetics.get.brimmed_cap mustEqual false + char.cosmetics match { + case Some(c : Cosmetics) => + c.Styles mustEqual Set(PersonalStyle.NoHelmet, PersonalStyle.Beret, PersonalStyle.Sunglasses, PersonalStyle.Earpiece) + case None => + ko + } char.unk mustEqual 7 //short test of inventory items inv.isDefined mustEqual true @@ -149,9 +149,9 @@ class CharacterDataTest extends Specification { len mustEqual 1795 cls mustEqual ObjectClass.avatar guid mustEqual PlanetSideGUID(3902) - parent mustEqual Some(ObjectCreateMessageParent(PlanetSideGUID(1234), 0)) + parent.contains(ObjectCreateMessageParent(PlanetSideGUID(1234), 0)) mustEqual true data match { - case Some(PlayerData(None, basic, char, inv, hand)) => + case PlayerData(None, basic, _, _, _) => basic match { case CharacterAppearanceData(a, b, ribbons) => a.app.name mustEqual "ScrawnyRonnie" @@ -159,13 +159,13 @@ class CharacterDataTest extends Specification { a.app.sex mustEqual CharacterGender.Male a.app.head mustEqual 5 a.app.voice mustEqual CharacterVoice.Voice5 - a.black_ops mustEqual false - a.jammered mustEqual false + a.data.bops mustEqual false + a.data.v1 mustEqual false + a.data.v2.isEmpty mustEqual true + a.data.v3 mustEqual false + a.data.v4.isEmpty mustEqual true + a.data.v5.isEmpty mustEqual true a.exosuit mustEqual ExoSuitType.Reinforced - a.unk1 mustEqual false - a.unk2 mustEqual None - a.unk3 mustEqual None - a.unk4 mustEqual 0 a.unk5 mustEqual 0 a.unk6 mustEqual 192L a.unk7 mustEqual 0 @@ -182,7 +182,7 @@ class CharacterDataTest extends Specification { b.grenade_state mustEqual GrenadeState.None b.is_cloaking mustEqual false b.charging_pose mustEqual false - b.on_zipline mustEqual None + b.on_zipline.isEmpty mustEqual true b.unk0 mustEqual 26L b.unk1 mustEqual false b.unk2 mustEqual false @@ -216,7 +216,7 @@ class CharacterDataTest extends Specification { guid mustEqual PlanetSideGUID(3380) parent.isDefined mustEqual false data match { - case Some(PlayerData(Some(pos), basic, char, None, hand)) => + case PlayerData(Some(pos), basic, char, None, hand) => pos.coord mustEqual Vector3(4629.8906f, 6316.4453f, 54.734375f) pos.orient mustEqual Vector3(0, 0, 126.5625f) pos.vel.isDefined mustEqual false @@ -228,13 +228,13 @@ class CharacterDataTest extends Specification { a.app.sex mustEqual CharacterGender.Male a.app.head mustEqual 10 a.app.voice mustEqual CharacterVoice.Voice2 - a.black_ops mustEqual false - a.jammered mustEqual false + a.data.bops mustEqual false + a.data.v1 mustEqual false + a.data.v2.isEmpty mustEqual true + a.data.v3 mustEqual false + a.data.v4.isEmpty mustEqual true + a.data.v5.isEmpty mustEqual true a.exosuit mustEqual ExoSuitType.MAX - a.unk1 mustEqual false - a.unk2 mustEqual None - a.unk3 mustEqual None - a.unk4 mustEqual 0 a.unk5 mustEqual 1 a.unk6 mustEqual 0L a.unk7 mustEqual 0 @@ -251,7 +251,7 @@ class CharacterDataTest extends Specification { b.grenade_state mustEqual GrenadeState.None b.is_cloaking mustEqual false b.charging_pose mustEqual false - b.on_zipline mustEqual None + b.on_zipline.isEmpty mustEqual true b.unk0 mustEqual 529687L b.unk1 mustEqual false b.unk2 mustEqual false @@ -275,12 +275,12 @@ class CharacterDataTest extends Specification { char.uniform_upgrade mustEqual UniformStyle.ThirdUpgrade char.command_rank mustEqual 2 char.implant_effects.isEmpty mustEqual true - char.cosmetics.isDefined mustEqual true - char.cosmetics.get.no_helmet mustEqual true - char.cosmetics.get.beret mustEqual true - char.cosmetics.get.sunglasses mustEqual true - char.cosmetics.get.earpiece mustEqual true - char.cosmetics.get.brimmed_cap mustEqual false + char.cosmetics match { + case Some(c : Cosmetics) => + c.Styles mustEqual Set(PersonalStyle.NoHelmet, PersonalStyle.Beret, PersonalStyle.Sunglasses, PersonalStyle.Earpiece) + case None => + ko + } char.unk mustEqual 1 hand mustEqual DrawnSlot.Pistol1 @@ -306,14 +306,18 @@ class CharacterDataTest extends Specification { 5, CharacterVoice.Voice5 ), - false, - false, - false, - None, - false, + CommonFieldData( + PlanetSideEmpire.TR, + false, + false, + false, + None, + false, + None, + None, + PlanetSideGUID(0) + ), ExoSuitType.Reinforced, - None, - 0, 0, 30777081L, 1, @@ -341,7 +345,7 @@ class CharacterDataTest extends Specification { None ) - val app : (Int)=>CharacterAppearanceData = CharacterAppearanceData( + val app : Int=>CharacterAppearanceData = CharacterAppearanceData( a, b, RibbonBars( MeritCommendation.MarkovVeteran, @@ -359,11 +363,11 @@ class CharacterDataTest extends Specification { Some(Cosmetics(true, true, true, true, false)) ) val inv = InventoryData( - InventoryItemData(ObjectClass.plasma_grenade, PlanetSideGUID(3662), 0, WeaponData(0, 0, ObjectClass.plasma_grenade_ammo, PlanetSideGUID(3751), 0, AmmoBoxData())) :: - InventoryItemData(ObjectClass.bank, PlanetSideGUID(3908), 1, WeaponData(0, 0, 1, ObjectClass.armor_canister, PlanetSideGUID(4143), 0, AmmoBoxData())) :: - InventoryItemData(ObjectClass.mini_chaingun, PlanetSideGUID(4164), 2, WeaponData(0, 0, ObjectClass.bullet_9mm, PlanetSideGUID(3728), 0, AmmoBoxData())) :: - InventoryItemData(ObjectClass.phoenix, PlanetSideGUID(3603), 3, WeaponData(0, 0, ObjectClass.phoenix_missile, PlanetSideGUID(3056), 0, AmmoBoxData())) :: - InventoryItemData(ObjectClass.chainblade, PlanetSideGUID(4088), 4, WeaponData(0, 0, 1, ObjectClass.melee_ammo, PlanetSideGUID(3279), 0, AmmoBoxData())) :: + InventoryItemData(ObjectClass.plasma_grenade, PlanetSideGUID(3662), 0, WeaponData(0, 0, ObjectClass.plasma_grenade_ammo, PlanetSideGUID(3751), 0, CommonFieldData()(false))) :: + InventoryItemData(ObjectClass.bank, PlanetSideGUID(3908), 1, WeaponData(0, 0, 1, ObjectClass.armor_canister, PlanetSideGUID(4143), 0, CommonFieldData()(false))) :: + InventoryItemData(ObjectClass.mini_chaingun, PlanetSideGUID(4164), 2, WeaponData(0, 0, ObjectClass.bullet_9mm, PlanetSideGUID(3728), 0, CommonFieldData()(false))) :: + InventoryItemData(ObjectClass.phoenix, PlanetSideGUID(3603), 3, WeaponData(0, 0, ObjectClass.phoenix_missile, PlanetSideGUID(3056), 0, CommonFieldData()(false))) :: + InventoryItemData(ObjectClass.chainblade, PlanetSideGUID(4088), 4, WeaponData(0, 0, 1, ObjectClass.melee_ammo, PlanetSideGUID(3279), 0, CommonFieldData()(false))) :: Nil ) val obj = PlayerData(pos, app, char, inv, DrawnSlot.Rifle1) @@ -382,14 +386,18 @@ class CharacterDataTest extends Specification { 5, CharacterVoice.Voice5 ), - false, - false, - false, - None, - false, + CommonFieldData( + PlanetSideEmpire.TR, + false, + false, + false, + None, + false, + None, + None, + PlanetSideGUID(0) + ), ExoSuitType.Reinforced, - None, - 0, 0, 192L, 0, @@ -417,7 +425,7 @@ class CharacterDataTest extends Specification { None ) - val app : (Int)=>CharacterAppearanceData = CharacterAppearanceData( + val app : Int=>CharacterAppearanceData = CharacterAppearanceData( a, b, RibbonBars( MeritCommendation.MarkovVeteran, @@ -434,11 +442,11 @@ class CharacterDataTest extends Specification { Some(Cosmetics(true, true, true, true, false)) ) val inv = InventoryData( - InventoryItemData(ObjectClass.plasma_grenade, PlanetSideGUID(3662), 0, WeaponData(0, 0, ObjectClass.plasma_grenade_ammo, PlanetSideGUID(3751), 0, AmmoBoxData())) :: - InventoryItemData(ObjectClass.bank, PlanetSideGUID(3908), 1, WeaponData(0, 0, 1, ObjectClass.armor_canister, PlanetSideGUID(4143), 0, AmmoBoxData())) :: - InventoryItemData(ObjectClass.mini_chaingun, PlanetSideGUID(4164), 2, WeaponData(0, 0, ObjectClass.bullet_9mm, PlanetSideGUID(3728), 0, AmmoBoxData())) :: - InventoryItemData(ObjectClass.phoenix, PlanetSideGUID(3603), 3, WeaponData(0, 0, ObjectClass.phoenix_missile, PlanetSideGUID(3056), 0, AmmoBoxData())) :: - InventoryItemData(ObjectClass.chainblade, PlanetSideGUID(4088), 4, WeaponData(0, 0, 1, ObjectClass.melee_ammo, PlanetSideGUID(3279), 0, AmmoBoxData())) :: + InventoryItemData(ObjectClass.plasma_grenade, PlanetSideGUID(3662), 0, WeaponData(0, 0, ObjectClass.plasma_grenade_ammo, PlanetSideGUID(3751), 0, CommonFieldData()(false))) :: + InventoryItemData(ObjectClass.bank, PlanetSideGUID(3908), 1, WeaponData(0, 0, 1, ObjectClass.armor_canister, PlanetSideGUID(4143), 0, CommonFieldData()(false))) :: + InventoryItemData(ObjectClass.mini_chaingun, PlanetSideGUID(4164), 2, WeaponData(0, 0, ObjectClass.bullet_9mm, PlanetSideGUID(3728), 0, CommonFieldData()(false))) :: + InventoryItemData(ObjectClass.phoenix, PlanetSideGUID(3603), 3, WeaponData(0, 0, ObjectClass.phoenix_missile, PlanetSideGUID(3056), 0, CommonFieldData()(false))) :: + InventoryItemData(ObjectClass.chainblade, PlanetSideGUID(4088), 4, WeaponData(0, 0, 1, ObjectClass.melee_ammo, PlanetSideGUID(3279), 0, CommonFieldData()(false))) :: Nil ) val obj = PlayerData(app, char, inv, DrawnSlot.Rifle1) @@ -461,14 +469,18 @@ class CharacterDataTest extends Specification { 10, CharacterVoice.Voice2 ), - false, - true, - false, - None, - false, + CommonFieldData( + PlanetSideEmpire.VS, + false, + true, + false, + None, + false, + None, + None, + PlanetSideGUID(0) + ), ExoSuitType.MAX, - None, - 0, 1, 0L, 0, @@ -496,7 +508,7 @@ class CharacterDataTest extends Specification { None ) - val app : (Int)=>CharacterAppearanceData = CharacterAppearanceData( + val app : Int=>CharacterAppearanceData = CharacterAppearanceData( a, b, RibbonBars( MeritCommendation.Jacking2, diff --git a/common/src/test/scala/game/objectcreate/CommandDetonaterDataTest.scala b/common/src/test/scala/game/objectcreate/CommandDetonaterDataTest.scala deleted file mode 100644 index c01dece3..00000000 --- a/common/src/test/scala/game/objectcreate/CommandDetonaterDataTest.scala +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2017 PSForever -package game.objectcreate - -import net.psforever.packet.PacketCoding -import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} -import net.psforever.packet.game.objectcreate._ -import org.specs2.mutable._ -import scodec.bits._ - -class CommandDetonaterDataTest extends Specification { - val string_detonater_held = hex"17 76000000 1A886A8421080400000000" - val string_detonater_dropped = hex"17 AF000000 EA8620ED1549B4B6A741500001B000000000" - - "CommandDetonaterData" should { - "decode (held)" in { - PacketCoding.DecodePacket(string_detonater_held).require match { - case ObjectCreateMessage(len, cls, guid, parent, data) => - len mustEqual 118 - cls mustEqual ObjectClass.command_detonater - guid mustEqual PlanetSideGUID(4162) - parent.isDefined mustEqual true - parent.get.guid mustEqual PlanetSideGUID(4149) - parent.get.slot mustEqual 0 - data.isDefined mustEqual true - data.get.isInstanceOf[CommandDetonaterData] mustEqual true - val cud = data.get.asInstanceOf[CommandDetonaterData] - cud.unk1 mustEqual 4 - cud.unk2 mustEqual 0 - case _ => - ko - } - } - - "decode (dropped)" in { - PacketCoding.DecodePacket(string_detonater_dropped).require match { - case ObjectCreateMessage(len, cls, guid, parent, data) => - len mustEqual 175 - cls mustEqual ObjectClass.command_detonater - guid mustEqual PlanetSideGUID(3682) - parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[DroppedItemData[_]] mustEqual true - val drop = data.get.asInstanceOf[DroppedItemData[_]] - drop.pos.coord.x mustEqual 4777.633f - drop.pos.coord.y mustEqual 5485.4062f - drop.pos.coord.z mustEqual 85.8125f - drop.pos.orient.x mustEqual 0f - drop.pos.orient.y mustEqual 0f - drop.pos.orient.z mustEqual 14.0625f - drop.obj.isInstanceOf[CommandDetonaterData] mustEqual true - case _ => - ko - } - } - - "encode (held)" in { - val obj = CommandDetonaterData(4) - val msg = ObjectCreateMessage(ObjectClass.command_detonater, PlanetSideGUID(4162), ObjectCreateMessageParent(PlanetSideGUID(4149), 0), obj) - val pkt = PacketCoding.EncodePacket(msg).require.toByteVector - pkt mustEqual string_detonater_held - } - - "encode (dropped)" in { - val obj = DroppedItemData( - PlacementData(4777.633f, 5485.4062f, 85.8125f, 0f, 0f, 14.0625f), - CommandDetonaterData() - ) - val msg = ObjectCreateMessage(ObjectClass.command_detonater, PlanetSideGUID(3682), obj) - val pkt = PacketCoding.EncodePacket(msg).require.toByteVector - pkt mustEqual string_detonater_dropped - } - } -} diff --git a/common/src/test/scala/game/objectcreate/CommonFieldDataTest.scala b/common/src/test/scala/game/objectcreate/CommonFieldDataTest.scala index 3ce92333..57ba9438 100644 --- a/common/src/test/scala/game/objectcreate/CommonFieldDataTest.scala +++ b/common/src/test/scala/game/objectcreate/CommonFieldDataTest.scala @@ -1,16 +1,123 @@ -// Copyright (c) 2017 PSForever +// Copyright (c) 2019 PSForever package game.objectcreate -import net.psforever.packet.game.PlanetSideGUID +import net.psforever.packet.PacketCoding +import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} import net.psforever.packet.game.objectcreate._ import net.psforever.types.PlanetSideEmpire -import org.specs2.mutable._ +import org.specs2.mutable.Specification +import scodec.bits._ -class CommonFieldDataTest extends Specification { - "CommonFieldData" should { - "construct" in { - CommonFieldData(PlacementData(0f, 0f, 0f), PlanetSideEmpire.NC, true, 5) mustEqual - CommonFieldData(PlacementData(0f, 0f, 0f), PlanetSideEmpire.NC, false, true, 5, false, PlanetSideGUID(0)) +object CommonFieldDataTest extends Specification { + val string_shotgunshell_dropped = hex"17 A5000000 F9A7D0D 5E269 BED5A F114 0000596000000" + val string_implant_interface = hex"17 6C000000 01014C93304818000000" + val string_order_terminala = hex"17 A5000000 B2AF30EACF1889F7A3D1200007D2000000" + + "AmmoBoxData" should { + "decode (shotgun shells, dropped)" in { + PacketCoding.DecodePacket(string_shotgunshell_dropped).require match { + case ObjectCreateMessage(len, cls, guid, parent, data) => + len mustEqual 165 + cls mustEqual ObjectClass.shotgun_shell + guid mustEqual PlanetSideGUID(3453) + parent.isDefined mustEqual false + data.isInstanceOf[DroppedItemData[_]] mustEqual true + val drop = data.asInstanceOf[DroppedItemData[_]] + drop.pos.coord.x mustEqual 4684.7344f + drop.pos.coord.y mustEqual 5547.4844f + drop.pos.coord.z mustEqual 83.765625f + drop.pos.orient.x mustEqual 0f + drop.pos.orient.y mustEqual 0f + drop.pos.orient.z mustEqual 199.6875f + drop.obj match { + case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid) => + faction mustEqual PlanetSideEmpire.NEUTRAL + bops mustEqual false + alternate mustEqual false + v1 mustEqual false + v2.isEmpty mustEqual true + v3 mustEqual false + v4.contains(false) mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + case _ => + ko + } + } + + "encode (shotgun shells, dropped)" in { + val obj = DroppedItemData( + PlacementData(4684.7344f, 5547.4844f, 83.765625f, 0f, 0f, 199.6875f), + CommonFieldData()(false) + ) + val msg = ObjectCreateMessage(ObjectClass.shotgun_shell, PlanetSideGUID(3453), obj) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + pkt mustEqual string_shotgunshell_dropped + } + } + + + "TerminalData" should { + "decode (implant interface)" in { + PacketCoding.DecodePacket(string_implant_interface).require match { + case ObjectCreateMessage(len, cls, guid, parent, data) => + len mustEqual 108 + cls mustEqual 0x199 + guid mustEqual PlanetSideGUID(1075) + parent.isDefined mustEqual true + parent.get.guid mustEqual PlanetSideGUID(514) + parent.get.slot mustEqual 1 + data.isInstanceOf[CommonFieldData] mustEqual true + case _ => + ko + } + } + + "decode (order terminal a)" in { + PacketCoding.DecodePacket(string_order_terminala).require match { + case ObjectCreateMessage(len, cls, guid, parent, data) => + len mustEqual 165 + cls mustEqual ObjectClass.order_terminala + guid mustEqual PlanetSideGUID(3827) + parent.isDefined mustEqual false + data.isInstanceOf[DroppedItemData[_]] mustEqual true + val drop = data.asInstanceOf[DroppedItemData[_]] + drop.pos.coord.x mustEqual 4579.3438f + drop.pos.coord.y mustEqual 5615.0703f + drop.pos.coord.z mustEqual 72.953125f + drop.pos.orient.x mustEqual 0f + drop.pos.orient.y mustEqual 0f + drop.pos.orient.z mustEqual 98.4375f + drop.obj.isInstanceOf[CommonFieldData] mustEqual true + drop.obj.asInstanceOf[CommonFieldData].faction mustEqual PlanetSideEmpire.NC + case _ => + ko + } + } + + "encode (implant interface)" in { + val obj = CommonFieldData(PlanetSideEmpire.VS)(false) + val msg = ObjectCreateMessage(0x199, PlanetSideGUID(1075), ObjectCreateMessageParent(PlanetSideGUID(514), 1), obj) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + pkt mustEqual string_implant_interface + } + + "encode (order terminal a)" in { + val obj = DroppedItemData( + PlacementData(4579.3438f, 5615.0703f, 72.953125f, 0f, 0f, 98.4375f), + CommonFieldData(PlanetSideEmpire.NC)(false) + ) + val msg = ObjectCreateMessage(ObjectClass.order_terminala, PlanetSideGUID(3827), obj) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + pkt mustEqual string_order_terminala + } + + "InternalSlot" in { + TerminalData(ObjectClass.order_terminala, PlanetSideGUID(1), 1, CommonFieldData(PlanetSideEmpire.NC)(false)) mustEqual + InternalSlot(ObjectClass.order_terminala, PlanetSideGUID(1), 1, CommonFieldData(PlanetSideEmpire.NC)(false)) } } } diff --git a/common/src/test/scala/game/objectcreate/CommonFieldDataWithPlacementTest.scala b/common/src/test/scala/game/objectcreate/CommonFieldDataWithPlacementTest.scala new file mode 100644 index 00000000..65737f1e --- /dev/null +++ b/common/src/test/scala/game/objectcreate/CommonFieldDataWithPlacementTest.scala @@ -0,0 +1,58 @@ +// Copyright (c) 2017 PSForever +package game.objectcreate + +import net.psforever.packet.PacketCoding +import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} +import net.psforever.packet.game.objectcreate._ +import net.psforever.types.{PlanetSideEmpire, Vector3} +import org.specs2.mutable._ +import scodec.bits._ + +class CommonFieldDataWithPlacementTest extends Specification { + val string_boomer = hex"17 A5000000 CA0000F1630938D5A8F1400003F0031100" + + "Boomer" should { + "decode" in { + PacketCoding.DecodePacket(string_boomer).require match { + case ObjectCreateMessage(len, cls, guid, parent, data) => + len mustEqual 165 + cls mustEqual ObjectClass.boomer + guid mustEqual PlanetSideGUID(3840) + parent.isDefined mustEqual false + data match { + case CommonFieldDataWithPlacement(pos, com) => + pos.coord mustEqual Vector3(4704.172f, 5546.4375f, 82.234375f) + pos.orient mustEqual Vector3.z(272.8125f) + com match { + case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid) => + faction mustEqual PlanetSideEmpire.TR + bops mustEqual false + alternate mustEqual false + v1 mustEqual false + v2.isEmpty mustEqual true + v3 mustEqual false + v4.contains(false) mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(8290) + case _ => + ko + } + case _ => + ko + } + case _ => + ko + } + } + + "encode" in { + val obj = CommonFieldDataWithPlacement( + PlacementData(Vector3(4704.172f, 5546.4375f, 82.234375f), Vector3.z(272.8125f)), + CommonFieldData(PlanetSideEmpire.TR, false, false, false, None, false, Some(false), None, PlanetSideGUID(8290)) + ) + val msg = ObjectCreateMessage(ObjectClass.boomer, PlanetSideGUID(3840), obj) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + pkt mustEqual string_boomer + } + } +} diff --git a/common/src/test/scala/game/objectcreate/CommonTerminalDataTest.scala b/common/src/test/scala/game/objectcreate/CommonTerminalDataTest.scala deleted file mode 100644 index 2e4a4d70..00000000 --- a/common/src/test/scala/game/objectcreate/CommonTerminalDataTest.scala +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) 2017 PSForever -package game.objectcreate - -import net.psforever.packet.PacketCoding -import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} -import net.psforever.packet.game.objectcreate._ -import net.psforever.types.PlanetSideEmpire -import org.specs2.mutable._ -import scodec.bits._ - -class CommonTerminalDataTest extends Specification { - val string_implant_interface = hex"17 6C000000 01014C93304818000000" - val string_order_terminala = hex"17 A5000000 B2AF30EACF1889F7A3D1200007D2000000" - - "CommonTerminalData" should { - "decode (implant interface)" in { - PacketCoding.DecodePacket(string_implant_interface).require match { - case ObjectCreateMessage(len, cls, guid, parent, data) => - len mustEqual 108 - cls mustEqual 0x199 - guid mustEqual PlanetSideGUID(1075) - parent.isDefined mustEqual true - parent.get.guid mustEqual PlanetSideGUID(514) - parent.get.slot mustEqual 1 - data.isDefined mustEqual true - data.get.isInstanceOf[CommonTerminalData] mustEqual true - data.get.asInstanceOf[CommonTerminalData].faction mustEqual PlanetSideEmpire.VS - case _ => - ko - } - } - - "decode (order terminal a)" in { - PacketCoding.DecodePacket(string_order_terminala).require match { - case ObjectCreateMessage(len, cls, guid, parent, data) => - len mustEqual 165 - cls mustEqual ObjectClass.order_terminala - guid mustEqual PlanetSideGUID(3827) - parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[DroppedItemData[_]] mustEqual true - val drop = data.get.asInstanceOf[DroppedItemData[_]] - drop.pos.coord.x mustEqual 4579.3438f - drop.pos.coord.y mustEqual 5615.0703f - drop.pos.coord.z mustEqual 72.953125f - drop.pos.orient.x mustEqual 0f - drop.pos.orient.y mustEqual 0f - drop.pos.orient.z mustEqual 98.4375f - drop.obj.isInstanceOf[CommonTerminalData] mustEqual true - val term = drop.obj.asInstanceOf[CommonTerminalData] - term.faction mustEqual PlanetSideEmpire.NC - term.unk mustEqual 0 - case _ => - ko - } - } - - "encode (implant interface)" in { - val obj = CommonTerminalData(PlanetSideEmpire.VS) - val msg = ObjectCreateMessage(0x199, PlanetSideGUID(1075), ObjectCreateMessageParent(PlanetSideGUID(514), 1), obj) - val pkt = PacketCoding.EncodePacket(msg).require.toByteVector - pkt mustEqual string_implant_interface - } - - "encode (order terminal a)" in { - val obj = DroppedItemData( - PlacementData(4579.3438f, 5615.0703f, 72.953125f, 0f, 0f, 98.4375f), - CommonTerminalData(PlanetSideEmpire.NC) - ) - val msg = ObjectCreateMessage(ObjectClass.order_terminala, PlanetSideGUID(3827), obj) - val pkt = PacketCoding.EncodePacket(msg).require.toByteVector - pkt mustEqual string_order_terminala - } - - "InternalSlot" in { - CommonTerminalData(ObjectClass.order_terminala, PlanetSideGUID(1), 1, CommonTerminalData(PlanetSideEmpire.NC)) mustEqual - InternalSlot(ObjectClass.order_terminala, PlanetSideGUID(1), 1, CommonTerminalData(PlanetSideEmpire.NC)) - } - } -} diff --git a/common/src/test/scala/game/objectcreate/ContainedTelepadDeployableDataTest.scala b/common/src/test/scala/game/objectcreate/ContainedTelepadDeployableDataTest.scala deleted file mode 100644 index f32b7c26..00000000 --- a/common/src/test/scala/game/objectcreate/ContainedTelepadDeployableDataTest.scala +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2017 PSForever -package game.objectcreate - -import net.psforever.packet.PacketCoding -import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} -import net.psforever.packet.game.objectcreate._ -import org.specs2.mutable._ -import scodec.bits._ - -class ContainedTelepadDeployableDataTest extends Specification { - val string = hex"178f0000004080f42b00182cb0202000100000" - - "ContainedTelepadDeployableData" should { - "decode" in { - PacketCoding.DecodePacket(string).require match { - case ObjectCreateMessage(len, cls, guid, parent, data) => - len mustEqual 143 - cls mustEqual 744 - guid mustEqual PlanetSideGUID(432) - parent.isDefined mustEqual true - parent.get.guid mustEqual PlanetSideGUID(385) - parent.get.slot mustEqual 2 - data.isDefined mustEqual true - data.get.isInstanceOf[ContainedTelepadDeployableData] mustEqual true - data.get.asInstanceOf[ContainedTelepadDeployableData].unk mustEqual 101 - data.get.asInstanceOf[ContainedTelepadDeployableData].router_guid mustEqual PlanetSideGUID(385) - case _ => - ko - } - } - "encode" in { - val obj = ContainedTelepadDeployableData(101, PlanetSideGUID(385)) - val msg = ObjectCreateMessage(744, PlanetSideGUID(432), ObjectCreateMessageParent(PlanetSideGUID(385), 2), obj) - val pkt = PacketCoding.EncodePacket(msg).require.toByteVector - pkt mustEqual string - } - } -} diff --git a/common/src/test/scala/game/objectcreate/HandheldDataTest.scala b/common/src/test/scala/game/objectcreate/HandheldDataTest.scala new file mode 100644 index 00000000..94078f9a --- /dev/null +++ b/common/src/test/scala/game/objectcreate/HandheldDataTest.scala @@ -0,0 +1,249 @@ +// Copyright (c) 2017 PSForever +package game.objectcreate + +import net.psforever.packet.PacketCoding +import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} +import net.psforever.packet.game.objectcreate._ +import net.psforever.types.{PlanetSideEmpire, Vector3} +import org.specs2.mutable._ +import scodec.bits._ + +class HandheldDataTest extends Specification { + val string_ace_held = hex"17 76000000 0406900650C80480000000" + val string_ace_dropped = hex"17 AF000000 90024113B329C5D5A2D1200005B440000000" + + "ACE" should { + "decode (held)" in { + PacketCoding.DecodePacket(string_ace_held).require match { + case ObjectCreateMessage(len, cls, guid, parent, data) => + len mustEqual 118 + cls mustEqual ObjectClass.ace + guid mustEqual PlanetSideGUID(3173) + parent.isDefined mustEqual true + parent.get.guid mustEqual PlanetSideGUID(3336) + parent.get.slot mustEqual 0 + data match { + case HandheldData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid)) => + faction mustEqual PlanetSideEmpire.NC + bops mustEqual false + alternate mustEqual false + v1 mustEqual true + v2.isEmpty mustEqual true + v3 mustEqual false + v4.isEmpty mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + case _ => + ko + } + } + + "decode (dropped)" in { + PacketCoding.DecodePacket(string_ace_dropped).require match { + case ObjectCreateMessage(len, cls, guid, parent, data) => + len mustEqual 175 + cls mustEqual ObjectClass.ace + guid mustEqual PlanetSideGUID(4388) + parent.isDefined mustEqual false + data.isInstanceOf[DroppedItemData[_]] mustEqual true + data match { + case DroppedItemData(pos, HandheldData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid))) => + pos.coord mustEqual Vector3(4708.461f, 5547.539f, 72.703125f) + pos.orient mustEqual Vector3.z(194.0625f) + + faction mustEqual PlanetSideEmpire.VS + bops mustEqual false + alternate mustEqual false + v1 mustEqual true + v2.isEmpty mustEqual true + v3 mustEqual false + v4.isEmpty mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + case _ => + ko + } + } + + "encode (held)" in { + val obj = HandheldData(CommonFieldData(PlanetSideEmpire.NC, false, false, true, None, false, None, None, PlanetSideGUID(0))) + val msg = ObjectCreateMessage(ObjectClass.ace, PlanetSideGUID(3173), ObjectCreateMessageParent(PlanetSideGUID(3336), 0), obj) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + pkt mustEqual string_ace_held + } + + "encode (dropped)" in { + val obj = DroppedItemData( + PlacementData(4708.461f, 5547.539f, 72.703125f, 0f, 0f, 194.0625f), + HandheldData(CommonFieldData(PlanetSideEmpire.VS, false, false, true, None, false, None, None, PlanetSideGUID(0))) + ) + val msg = ObjectCreateMessage(ObjectClass.ace, PlanetSideGUID(4388), obj) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + pkt mustEqual string_ace_dropped + } + } + + val string_telepad = hex"17 86000000 5700 f3a a201 80 0302020000000" + + "Telepad" should { + "decode" in { + PacketCoding.DecodePacket(string_telepad).require match { + case ObjectCreateMessage(len, cls, guid, parent, data) => + len mustEqual 134 + cls mustEqual ObjectClass.router_telepad + guid mustEqual PlanetSideGUID(418) + parent.isDefined mustEqual true + parent.get.guid mustEqual PlanetSideGUID(430) + parent.get.slot mustEqual 0 + data match { + case HandheldData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid)) => + faction mustEqual PlanetSideEmpire.TR + bops mustEqual false + alternate mustEqual false + v1 mustEqual false + v2.isEmpty mustEqual true + v3 mustEqual false + v4.isEmpty mustEqual true + v5.contains(385) mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + case _ => + ko + } + } + + "encode" in { + val obj = HandheldData(CommonFieldData(PlanetSideEmpire.TR, false, false, false, None, false, None, Some(385), PlanetSideGUID(0))) + val msg = ObjectCreateMessage(ObjectClass.router_telepad, PlanetSideGUID(418), ObjectCreateMessageParent(PlanetSideGUID(430), 0), obj) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_telepad + } + } + + val string_boomertrigger = hex"17 76000000 58084A8100E80C00000000" //reconstructed from an inventory entry + + "Boomer Trigger" should { + "decode" in { + PacketCoding.DecodePacket(string_boomertrigger).require match { + case ObjectCreateMessage(len, cls, guid, parent, data) => + len mustEqual 118 + cls mustEqual ObjectClass.boomer_trigger + guid mustEqual PlanetSideGUID(3600) + parent.isDefined mustEqual true + parent.get.guid mustEqual PlanetSideGUID(4272) + parent.get.slot mustEqual 0 + data match { + case HandheldData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid)) => + faction mustEqual PlanetSideEmpire.NEUTRAL + bops mustEqual false + alternate mustEqual false + v1 mustEqual false + v2.isEmpty mustEqual true + v3 mustEqual false + v4.isEmpty mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + case _ => + ko + } + } + + "encode" in { + val obj = HandheldData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0))) + val msg = ObjectCreateMessage(ObjectClass.boomer_trigger, PlanetSideGUID(3600), ObjectCreateMessageParent(PlanetSideGUID(4272), 0), obj) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + pkt mustEqual string_boomertrigger + } + } + + val string_detonater_held = hex"17 76000000 1A886A8421080400000000" + val string_detonater_dropped = hex"17 AF000000 EA8620ED1549B4B6A741500001B000000000" + + "Command Detonater" should { + "decode (held)" in { + PacketCoding.DecodePacket(string_detonater_held).require match { + case ObjectCreateMessage(len, cls, guid, parent, data) => + len mustEqual 118 + cls mustEqual ObjectClass.command_detonater + guid mustEqual PlanetSideGUID(4162) + parent.isDefined mustEqual true + parent.get.guid mustEqual PlanetSideGUID(4149) + parent.get.slot mustEqual 0 + data match { + case HandheldData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid)) => + faction mustEqual PlanetSideEmpire.NC + bops mustEqual false + alternate mustEqual false + v1 mustEqual false + v2.isEmpty mustEqual true + v3 mustEqual false + v4.isEmpty mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + case _ => + ko + } + } + + "decode (dropped)" in { + PacketCoding.DecodePacket(string_detonater_dropped).require match { + case ObjectCreateMessage(len, cls, guid, parent, data) => + len mustEqual 175 + cls mustEqual ObjectClass.command_detonater + guid mustEqual PlanetSideGUID(3682) + parent.isDefined mustEqual false + data match { + case DroppedItemData(pos, HandheldData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid))) => + pos.coord mustEqual Vector3(4777.633f, 5485.4062f, 85.8125f) + pos.orient mustEqual Vector3.z(14.0625f) + + faction mustEqual PlanetSideEmpire.TR + bops mustEqual false + alternate mustEqual false + v1 mustEqual false + v2.isEmpty mustEqual true + v3 mustEqual false + v4.isEmpty mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + case _ => + ko + } + } + + "encode (held)" in { + val obj = HandheldData(CommonFieldData(PlanetSideEmpire.NC, false, false, false, None, false, None, None, PlanetSideGUID(0))) + val msg = ObjectCreateMessage(ObjectClass.command_detonater, PlanetSideGUID(4162), ObjectCreateMessageParent(PlanetSideGUID(4149), 0), obj) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + pkt mustEqual string_detonater_held + } + + "encode (dropped)" in { + val obj = DroppedItemData( + PlacementData(4777.633f, 5485.4062f, 85.8125f, 0f, 0f, 14.0625f), + HandheldData(CommonFieldData(PlanetSideEmpire.TR, false, false, false, None, false, None, None, PlanetSideGUID(0))) + ) + val msg = ObjectCreateMessage(ObjectClass.command_detonater, PlanetSideGUID(3682), obj) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + pkt mustEqual string_detonater_dropped + } + } +} diff --git a/common/src/test/scala/game/objectcreate/LockerContainerDataTest.scala b/common/src/test/scala/game/objectcreate/LockerContainerDataTest.scala index 2c81aea9..f960c318 100644 --- a/common/src/test/scala/game/objectcreate/LockerContainerDataTest.scala +++ b/common/src/test/scala/game/objectcreate/LockerContainerDataTest.scala @@ -4,6 +4,7 @@ package game.objectcreate import net.psforever.packet.PacketCoding import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} import net.psforever.packet.game.objectcreate._ +import net.psforever.types.PlanetSideEmpire import org.specs2.mutable._ import scodec.bits._ @@ -18,36 +19,43 @@ class LockerContainerDataTest extends Specification { cls mustEqual ObjectClass.locker_container guid mustEqual PlanetSideGUID(3148) parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[LockerContainerData] mustEqual true - val locker = data.get.asInstanceOf[LockerContainerData] - val contents = locker.inventory.contents - contents.size mustEqual 3 - //0 - contents.head.objectClass mustEqual ObjectClass.nano_dispenser - contents.head.guid mustEqual PlanetSideGUID(2935) - contents.head.parentSlot mustEqual 0 - contents.head.obj.isInstanceOf[WeaponData] mustEqual true - val dispenser = contents.head.obj.asInstanceOf[WeaponData] - dispenser.unk1 mustEqual 0x6 - dispenser.unk2 mustEqual 0x0 - dispenser.ammo.head.objectClass mustEqual ObjectClass.armor_canister - dispenser.ammo.head.guid mustEqual PlanetSideGUID(3426) - dispenser.ammo.head.parentSlot mustEqual 0 - dispenser.ammo.head.obj.isInstanceOf[AmmoBoxData] mustEqual true - dispenser.ammo.head.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0 - //1 - contents(1).objectClass mustEqual ObjectClass.armor_canister - contents(1).guid mustEqual PlanetSideGUID(4090) - contents(1).parentSlot mustEqual 45 - contents(1).obj.isInstanceOf[AmmoBoxData] mustEqual true - contents(1).obj.asInstanceOf[AmmoBoxData].unk mustEqual 0 - //2 - contents(2).objectClass mustEqual ObjectClass.armor_canister - contents(2).guid mustEqual PlanetSideGUID(3326) - contents(2).parentSlot mustEqual 78 - contents(2).obj.isInstanceOf[AmmoBoxData] mustEqual true - contents(2).obj.asInstanceOf[AmmoBoxData].unk mustEqual 0 + data.isInstanceOf[LockerContainerData] mustEqual true + val locker = data.asInstanceOf[LockerContainerData] + locker.inventory match { + case Some(InventoryData(contents)) => + contents.size mustEqual 3 + //0 + contents.head.objectClass mustEqual ObjectClass.nano_dispenser + contents.head.guid mustEqual PlanetSideGUID(2935) + contents.head.parentSlot mustEqual 0 + contents.head.obj match { + case WeaponData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid), _, _, _) => + faction mustEqual PlanetSideEmpire.NEUTRAL + bops mustEqual false + alternate mustEqual false + v1 mustEqual false + v2.isEmpty mustEqual true + v3 mustEqual false + v4.isEmpty mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + //1 + contents(1).objectClass mustEqual ObjectClass.armor_canister + contents(1).guid mustEqual PlanetSideGUID(4090) + contents(1).parentSlot mustEqual 45 + contents(1).obj.isInstanceOf[CommonFieldData] mustEqual true + //2 + contents(2).objectClass mustEqual ObjectClass.armor_canister + contents(2).guid mustEqual PlanetSideGUID(3326) + contents(2).parentSlot mustEqual 78 + contents(2).obj.isInstanceOf[CommonFieldData] mustEqual true + case None => + ko + } + case _ => ko } @@ -55,12 +63,17 @@ class LockerContainerDataTest extends Specification { "encode" in { val obj = LockerContainerData( - InventoryData( - InventoryItemData(ObjectClass.nano_dispenser, PlanetSideGUID(2935), 0, WeaponData(0x6, 0x0, ObjectClass.armor_canister, PlanetSideGUID(3426), 0, AmmoBoxData())) :: - InventoryItemData(ObjectClass.armor_canister, PlanetSideGUID(4090), 45, AmmoBoxData()) :: - InventoryItemData(ObjectClass.armor_canister, PlanetSideGUID(3326), 78, AmmoBoxData()) :: - Nil - ) + InventoryData(List( + InventoryItemData(ObjectClass.nano_dispenser, PlanetSideGUID(2935), 0, + WeaponData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)), + 0, + List(InternalSlot(ObjectClass.armor_canister, PlanetSideGUID(3426), 0, CommonFieldData()(false))) + ) + ), + InventoryItemData(ObjectClass.armor_canister, PlanetSideGUID(4090), 45, CommonFieldData()(false)), + InventoryItemData(ObjectClass.armor_canister, PlanetSideGUID(3326), 78, CommonFieldData()(false)) + )) ) val msg = ObjectCreateMessage(ObjectClass.locker_container, PlanetSideGUID(3148), obj) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector diff --git a/common/src/test/scala/game/objectcreate/OneMannedFieldTurretDataTest.scala b/common/src/test/scala/game/objectcreate/OneMannedFieldTurretDataTest.scala index e7815d72..b94884ab 100644 --- a/common/src/test/scala/game/objectcreate/OneMannedFieldTurretDataTest.scala +++ b/common/src/test/scala/game/objectcreate/OneMannedFieldTurretDataTest.scala @@ -19,31 +19,62 @@ class OneMannedFieldTurretDataTest extends Specification { cls mustEqual ObjectClass.portable_manned_turret_vs guid mustEqual PlanetSideGUID(2916) parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[OneMannedFieldTurretData] mustEqual true - val omft = data.get.asInstanceOf[OneMannedFieldTurretData] - omft.deploy.pos.coord mustEqual Vector3(3567.1406f, 2988.0078f, 71.84375f) - omft.deploy.pos.orient mustEqual Vector3(0, 0, 185.625f) - omft.deploy.faction mustEqual PlanetSideEmpire.VS - omft.deploy.unk1 mustEqual 2 - omft.deploy.owner_guid mustEqual PlanetSideGUID(2502) - omft.health mustEqual 255 - omft.internals.isDefined mustEqual true - val internals = omft.internals.get.contents - internals.head.objectClass mustEqual ObjectClass.energy_gun_vs - internals.head.guid mustEqual PlanetSideGUID(2615) - internals.head.parentSlot mustEqual 1 - internals.head.obj.isInstanceOf[WeaponData] mustEqual true - val wep = internals.head.obj.asInstanceOf[WeaponData] - wep.unk1 mustEqual 0x6 - wep.unk2 mustEqual 0x8 - wep.fire_mode mustEqual 0 - val ammo = wep.ammo.head - ammo.objectClass mustEqual ObjectClass.energy_gun_ammo - ammo.guid mustEqual PlanetSideGUID(2510) - ammo.parentSlot mustEqual 0 - ammo.obj.isInstanceOf[AmmoBoxData] mustEqual true - ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 8 + data match { + case OneMannedFieldTurretData(CommonFieldDataWithPlacement(pos, deploy), health, Some(InventoryData(inv))) => + pos.coord mustEqual Vector3(3567.1406f, 2988.0078f, 71.84375f) + pos.orient mustEqual Vector3.z(185.625f) + deploy.faction mustEqual PlanetSideEmpire.VS + deploy.bops mustEqual false + deploy.alternate mustEqual false + deploy.v1 mustEqual true + deploy.v2.isEmpty mustEqual true + deploy.v3 mustEqual false + deploy.v4.contains(false) mustEqual true + deploy.v5.isEmpty mustEqual true + deploy.guid mustEqual PlanetSideGUID(2502) + + health mustEqual 255 + + inv.head.objectClass mustEqual ObjectClass.energy_gun_vs + inv.head.guid mustEqual PlanetSideGUID(2615) + inv.head.parentSlot mustEqual 1 + inv.head.obj match { + case WeaponData(CommonFieldData(wfaction, wbops, walternate, wv1, wv2, wv3, wv4, wv5, wfguid), fmode, List(ammo), _) => + wfaction mustEqual PlanetSideEmpire.NEUTRAL + wbops mustEqual false + walternate mustEqual false + wv1 mustEqual true + wv2.isEmpty mustEqual true + wv3 mustEqual false + wv4.isEmpty mustEqual true + wv5.isEmpty mustEqual true + wfguid mustEqual PlanetSideGUID(0) + + fmode mustEqual 0 + + ammo.objectClass mustEqual ObjectClass.energy_gun_ammo + ammo.guid mustEqual PlanetSideGUID(2510) + ammo.parentSlot mustEqual 0 + ammo.obj match { + case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid) => + faction mustEqual PlanetSideEmpire.NEUTRAL + bops mustEqual false + alternate mustEqual false + v1 mustEqual true + v2.isEmpty mustEqual true + v3 mustEqual false + v4.contains(false) mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + case _ => + ko + } + case _ => + ko + } case _ => ko } @@ -51,52 +82,26 @@ class OneMannedFieldTurretDataTest extends Specification { "encode (orion)" in { val obj = OneMannedFieldTurretData( - SmallDeployableData( - PlacementData(Vector3(3567.1406f, 2988.0078f, 71.84375f), Vector3(0, 0, 185.625f)), - PlanetSideEmpire.VS, false, false, 2, false, false, PlanetSideGUID(2502) + CommonFieldDataWithPlacement( + PlacementData(Vector3(3567.1406f, 2988.0078f, 71.84375f), Vector3.z(185.625f)), + CommonFieldData(PlanetSideEmpire.VS, false, false, true, None, false, Some(false), None, PlanetSideGUID(2502)) ), 255, - InventoryData(List(OneMannedFieldTurretData.orion(PlanetSideGUID(2615), 0x6, 0x8, PlanetSideGUID(2510), 8))) + InventoryData(List( + InternalSlot(ObjectClass.energy_gun_vs, PlanetSideGUID(2615), 1, + WeaponData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), + 0, + List(InternalSlot(ObjectClass.energy_gun_ammo, PlanetSideGUID(2510), 0, + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, Some(false), None, PlanetSideGUID(0))) + ) + ) + ) + )) ) val msg = ObjectCreateMessage(ObjectClass.portable_manned_turret_vs, PlanetSideGUID(2916), obj) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector pkt mustEqual string_orion } - - "avenger" in { - OneMannedFieldTurretData.avenger(PlanetSideGUID(1), 2, 3, PlanetSideGUID(4), 5) mustEqual - InternalSlot(ObjectClass.energy_gun_tr, PlanetSideGUID(1), 1, - WeaponData(2, 3, ObjectClass.energy_gun_ammo, PlanetSideGUID(4), 0, - AmmoBoxData(5) - ) - ) - } - - "generic" in { - OneMannedFieldTurretData.generic(PlanetSideGUID(1), 2, 3, PlanetSideGUID(4), 5) mustEqual - InternalSlot(ObjectClass.energy_gun, PlanetSideGUID(1), 1, - WeaponData(2, 3, ObjectClass.energy_gun_ammo, PlanetSideGUID(4), 0, - AmmoBoxData(5) - ) - ) - } - - "orion" in { - OneMannedFieldTurretData.orion(PlanetSideGUID(1), 2, 3, PlanetSideGUID(4), 5) mustEqual - InternalSlot(ObjectClass.energy_gun_vs, PlanetSideGUID(1), 1, - WeaponData(2, 3, ObjectClass.energy_gun_ammo, PlanetSideGUID(4), 0, - AmmoBoxData(5) - ) - ) - } - - "osprey" in { - OneMannedFieldTurretData.osprey(PlanetSideGUID(1), 2, 3, PlanetSideGUID(4), 5) mustEqual - InternalSlot(ObjectClass.energy_gun_nc, PlanetSideGUID(1), 1, - WeaponData(2, 3, ObjectClass.energy_gun_ammo, PlanetSideGUID(4), 0, - AmmoBoxData(5) - ) - ) - } } } diff --git a/common/src/test/scala/game/objectcreate/REKDataTest.scala b/common/src/test/scala/game/objectcreate/REKDataTest.scala index 3de8dc63..328c10db 100644 --- a/common/src/test/scala/game/objectcreate/REKDataTest.scala +++ b/common/src/test/scala/game/objectcreate/REKDataTest.scala @@ -4,6 +4,7 @@ package game.objectcreate import net.psforever.packet.PacketCoding import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} import net.psforever.packet.game.objectcreate._ +import net.psforever.types.{PlanetSideEmpire, Vector3} import org.specs2.mutable._ import scodec.bits._ @@ -21,12 +22,21 @@ class REKDataTest extends Specification { parent.isDefined mustEqual true parent.get.guid mustEqual PlanetSideGUID(4174) parent.get.slot mustEqual 0 - data.isDefined mustEqual true - data.get.isInstanceOf[REKData] mustEqual true - val rek = data.get.asInstanceOf[REKData] - rek.unk1 mustEqual 0 - rek.unk2 mustEqual 8 - rek.unk3 mustEqual 0 + data match { + case REKData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid), unk) => + faction mustEqual PlanetSideEmpire.TR + bops mustEqual false + alternate mustEqual false + v1 mustEqual true + v2.isEmpty mustEqual true + v3 mustEqual false + v4.contains(false) mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + unk mustEqual 0 + case _ => + ko + } case _ => ko } @@ -39,27 +49,32 @@ class REKDataTest extends Specification { cls mustEqual ObjectClass.remote_electronics_kit guid mustEqual PlanetSideGUID(4355) parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[DroppedItemData[_]] mustEqual true - val dropped = data.get.asInstanceOf[DroppedItemData[_]] - dropped.pos.coord.x mustEqual 4675.039f - dropped.pos.coord.y mustEqual 5506.953f - dropped.pos.coord.z mustEqual 72.703125f - dropped.pos.orient.x mustEqual 0f - dropped.pos.orient.y mustEqual 0f - dropped.pos.orient.z mustEqual 230.625f - dropped.obj.isInstanceOf[REKData] mustEqual true - val rek = dropped.obj.asInstanceOf[REKData] - rek.unk1 mustEqual 8 - rek.unk2 mustEqual 0 - rek.unk3 mustEqual 3 + data match { + case DroppedItemData(pos, REKData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid), unk)) => + pos.coord mustEqual Vector3(4675.039f, 5506.953f, 72.703125f) + pos.orient mustEqual Vector3.z(230.625f) + + faction mustEqual PlanetSideEmpire.VS + bops mustEqual false + alternate mustEqual false + v1 mustEqual false + v2.isEmpty mustEqual true + v3 mustEqual false + v4.contains(false) mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + + unk mustEqual 3 + case _ => + ko + } case _ => ko } } "encode (held)" in { - val obj = REKData(0, 8) + val obj = REKData(CommonFieldData(PlanetSideEmpire.TR, false, false, true, None, false, Some(false), None, PlanetSideGUID(0))) val msg = ObjectCreateMessage(ObjectClass.remote_electronics_kit, PlanetSideGUID(3893), ObjectCreateMessageParent(PlanetSideGUID(4174), 0), obj) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector pkt mustEqual string_rek_held @@ -68,7 +83,7 @@ class REKDataTest extends Specification { "encode (dropped)" in { val obj = DroppedItemData( PlacementData(4675.039f, 5506.953f, 72.703125f, 0f, 0f, 230.625f), - REKData(8, 0, 3) + REKData(CommonFieldData(PlanetSideEmpire.VS, false, false, false, None, false, Some(false), None, PlanetSideGUID(0)), 3) ) val msg = ObjectCreateMessage(ObjectClass.remote_electronics_kit, PlanetSideGUID(4355), obj) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector diff --git a/common/src/test/scala/game/objectcreate/SmallDeployableDataTest.scala b/common/src/test/scala/game/objectcreate/SmallDeployableDataTest.scala deleted file mode 100644 index 6ce53364..00000000 --- a/common/src/test/scala/game/objectcreate/SmallDeployableDataTest.scala +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2017 PSForever -package game.objectcreate - -import net.psforever.packet.PacketCoding -import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} -import net.psforever.packet.game.objectcreate._ -import net.psforever.types.{PlanetSideEmpire, Vector3} -import org.specs2.mutable._ -import scodec.bits._ - -class SmallDeployableDataTest extends Specification { - val string_boomer = hex"17 A5000000 CA0000F1630938D5A8F1400003F0031100" - - "SmallDeployableData" should { - "decode (boomer)" in { - PacketCoding.DecodePacket(string_boomer).require match { - case ObjectCreateMessage(len, cls, guid, parent, data) => - len mustEqual 165 - cls mustEqual ObjectClass.boomer - guid mustEqual PlanetSideGUID(3840) - parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[SmallDeployableData] mustEqual true - val boomer = data.get.asInstanceOf[SmallDeployableData] - boomer.pos.coord.x mustEqual 4704.172f - boomer.pos.coord.y mustEqual 5546.4375f - boomer.pos.coord.z mustEqual 82.234375f - boomer.pos.orient.x mustEqual 0f - boomer.pos.orient.y mustEqual 0f - boomer.pos.orient.z mustEqual 272.8125f - boomer.unk1 mustEqual 0 - boomer.owner_guid mustEqual PlanetSideGUID(8290) - case _ => - ko - } - } - - "encode (boomer)" in { - val obj = SmallDeployableData( - PlacementData(Vector3(4704.172f, 5546.4375f, 82.234375f), Vector3.z(272.8125f)), - PlanetSideEmpire.TR, false, false, 0, false, false, PlanetSideGUID(8290) - ) - val msg = ObjectCreateMessage(ObjectClass.boomer, PlanetSideGUID(3840), obj) - val pkt = PacketCoding.EncodePacket(msg).require.toByteVector - pkt mustEqual string_boomer - } - } -} diff --git a/common/src/test/scala/game/objectcreate/SmallTurretDataTest.scala b/common/src/test/scala/game/objectcreate/SmallTurretDataTest.scala index ea0124d3..fc901305 100644 --- a/common/src/test/scala/game/objectcreate/SmallTurretDataTest.scala +++ b/common/src/test/scala/game/objectcreate/SmallTurretDataTest.scala @@ -3,7 +3,7 @@ package game.objectcreate import net.psforever.packet.PacketCoding import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} -import net.psforever.packet.game.objectcreate.{SmallDeployableData, _} +import net.psforever.packet.game.objectcreate._ import net.psforever.types.{PlanetSideEmpire, Vector3} import org.specs2.mutable._ import scodec.bits._ @@ -20,17 +20,25 @@ class SmallTurretDataTest extends Specification { cls mustEqual ObjectClass.spitfire_turret guid mustEqual PlanetSideGUID(4208) parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[SmallTurretData] mustEqual true - val turret = data.get.asInstanceOf[SmallTurretData] - turret.deploy.pos.coord mustEqual Vector3(4577.7812f, 5624.828f, 72.046875f) - turret.deploy.pos.orient mustEqual Vector3(0, 2.8125f, 264.375f) - turret.deploy.faction mustEqual PlanetSideEmpire.NC - turret.deploy.destroyed mustEqual true - turret.deploy.unk1 mustEqual 2 - turret.deploy.owner_guid mustEqual PlanetSideGUID(7742) - turret.health mustEqual 0 - turret.internals.isDefined mustEqual false + data match { + case SmallTurretData(CommonFieldDataWithPlacement(pos, deploy), health, None) => + pos.coord mustEqual Vector3(4577.7812f, 5624.828f, 72.046875f) + pos.orient mustEqual Vector3(0, 2.8125f, 264.375f) + + deploy.faction mustEqual PlanetSideEmpire.NC + deploy.bops mustEqual false + deploy.alternate mustEqual true + deploy.v1 mustEqual true + deploy.v2.isEmpty mustEqual true + deploy.v3 mustEqual false + deploy.v4.contains(false) mustEqual true + deploy.v5.isEmpty mustEqual true + deploy.guid mustEqual PlanetSideGUID(7742) + + health mustEqual 0 + case _ => + ko + } case _ => ko } @@ -43,31 +51,64 @@ class SmallTurretDataTest extends Specification { cls mustEqual ObjectClass.spitfire_turret guid mustEqual PlanetSideGUID(4265) parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[SmallTurretData] mustEqual true - val turret = data.get.asInstanceOf[SmallTurretData] - turret.deploy.pos.coord mustEqual Vector3(4527.633f, 6271.3594f, 70.265625f) - turret.deploy.pos.orient mustEqual Vector3(0, 0, 154.6875f) - turret.deploy.faction mustEqual PlanetSideEmpire.VS - turret.deploy.unk1 mustEqual 2 - turret.deploy.owner_guid mustEqual PlanetSideGUID(8208) - turret.health mustEqual 255 - turret.internals.isDefined mustEqual true - val internals = turret.internals.get.contents - internals.head.objectClass mustEqual ObjectClass.spitfire_weapon - internals.head.guid mustEqual PlanetSideGUID(3064) - internals.head.parentSlot mustEqual 0 - internals.head.obj.isInstanceOf[WeaponData] mustEqual true - val wep = internals.head.obj.asInstanceOf[WeaponData] - wep.unk1 mustEqual 0x6 - wep.unk2 mustEqual 0x8 - wep.fire_mode mustEqual 0 - val ammo = wep.ammo.head - ammo.objectClass mustEqual ObjectClass.spitfire_ammo - ammo.guid mustEqual PlanetSideGUID(3694) - ammo.parentSlot mustEqual 0 - ammo.obj.isInstanceOf[AmmoBoxData] mustEqual true - ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 8 + data match { + case SmallTurretData(CommonFieldDataWithPlacement(pos, deploy), health, Some(InventoryData(inv))) => + pos.coord mustEqual Vector3(4527.633f, 6271.3594f, 70.265625f) + pos.orient mustEqual Vector3.z(154.6875f) + + deploy.faction mustEqual PlanetSideEmpire.VS + deploy.bops mustEqual false + deploy.alternate mustEqual false + deploy.v1 mustEqual true + deploy.v2.isEmpty mustEqual true + deploy.v3 mustEqual false + deploy.v4.contains(true) mustEqual true + deploy.v5.isEmpty mustEqual true + deploy.guid mustEqual PlanetSideGUID(8208) + + health mustEqual 255 + + inv.head.objectClass mustEqual ObjectClass.spitfire_weapon + inv.head.guid mustEqual PlanetSideGUID(3064) + inv.head.parentSlot mustEqual 0 + inv.head.obj.isInstanceOf[WeaponData] mustEqual true + inv.head.obj match { + case WeaponData(CommonFieldData(wfaction, wbops, walternate, wv1, wv2, wv3, wv4, wv5, wfguid), fmode, List(ammo), _) => + wfaction mustEqual PlanetSideEmpire.NEUTRAL + wbops mustEqual false + walternate mustEqual false + wv1 mustEqual true + wv2.isEmpty mustEqual true + wv3 mustEqual false + wv4.isEmpty mustEqual true + wv5.isEmpty mustEqual true + wfguid mustEqual PlanetSideGUID(0) + + fmode mustEqual 0 + + ammo.objectClass mustEqual ObjectClass.spitfire_ammo + ammo.guid mustEqual PlanetSideGUID(3694) + ammo.parentSlot mustEqual 0 + ammo.obj match { + case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid) => + faction mustEqual PlanetSideEmpire.NEUTRAL + bops mustEqual false + alternate mustEqual false + v1 mustEqual true + v2.isEmpty mustEqual true + v3 mustEqual false + v4.contains(false) mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + case _ => + ko + } + case _ => + ko + } case _ => ko } @@ -75,11 +116,11 @@ class SmallTurretDataTest extends Specification { "encode (spitfire, short)" in { val obj = SmallTurretData( - SmallDeployableData( + CommonFieldDataWithPlacement( PlacementData(Vector3(4577.7812f, 5624.828f, 72.046875f), Vector3(0, 2.8125f, 264.375f)), - PlanetSideEmpire.NC, false, true, 2, false, false, PlanetSideGUID(7742) + CommonFieldData(PlanetSideEmpire.NC, false, true, true, None, false, Some(false), None, PlanetSideGUID(7742)) ), - 255 //sets to 0 + 0 ) val msg = ObjectCreateMessage(ObjectClass.spitfire_turret, PlanetSideGUID(4208), obj) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector @@ -88,12 +129,23 @@ class SmallTurretDataTest extends Specification { "encode (spitfire)" in { val obj = SmallTurretData( - SmallDeployableData( + CommonFieldDataWithPlacement( PlacementData(Vector3(4527.633f, 6271.3594f, 70.265625f), Vector3(0, 0, 154.6875f)), - PlanetSideEmpire.VS, false, false, 2, false, true, PlanetSideGUID(8208) + CommonFieldData(PlanetSideEmpire.VS, false, false, true, None, false, Some(true), None, PlanetSideGUID(8208)) ), 255, - InventoryData(List(SmallTurretData.spitfire(PlanetSideGUID(3064), 0x6, 0x8, PlanetSideGUID(3694), 8))) + InventoryData(List( + InternalSlot(ObjectClass.spitfire_weapon, PlanetSideGUID(3064), 0, + WeaponData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), + 0, + List(InternalSlot(ObjectClass.spitfire_ammo, PlanetSideGUID(3694), 0, + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, Some(false), None, PlanetSideGUID(0)) + )) + ) + ) + //SmallTurretData.spitfire(PlanetSideGUID(3064), 0x6, 0x8, PlanetSideGUID(3694), 8) + )) ) val msg = ObjectCreateMessage(ObjectClass.spitfire_turret, PlanetSideGUID(4265), obj) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector diff --git a/common/src/test/scala/game/objectcreate/TRAPDataTest.scala b/common/src/test/scala/game/objectcreate/TRAPDataTest.scala index b8b89b6a..6e899523 100644 --- a/common/src/test/scala/game/objectcreate/TRAPDataTest.scala +++ b/common/src/test/scala/game/objectcreate/TRAPDataTest.scala @@ -19,14 +19,23 @@ class TRAPDataTest extends Specification { cls mustEqual ObjectClass.tank_traps guid mustEqual PlanetSideGUID(2659) parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[TRAPData] mustEqual true - val trap = data.get.asInstanceOf[TRAPData] - trap.deploy.pos.coord mustEqual Vector3(3572.4453f, 3277.9766f, 114.0f) - trap.deploy.pos.orient mustEqual Vector3(0, 0, 90) - trap.deploy.faction mustEqual PlanetSideEmpire.VS - trap.deploy.owner_guid mustEqual PlanetSideGUID(4748) - trap.health mustEqual 255 + data match { + case TRAPData(CommonFieldDataWithPlacement(pos, deploy), health) => + pos.coord mustEqual Vector3(3572.4453f, 3277.9766f, 114.0f) + pos.orient mustEqual Vector3.z(90) + deploy.faction mustEqual PlanetSideEmpire.VS + deploy.bops mustEqual false + deploy.alternate mustEqual false + deploy.v1 mustEqual true + deploy.v2.isEmpty mustEqual true + deploy.v3 mustEqual false + deploy.v4.contains(true) mustEqual true + deploy.v5.isEmpty mustEqual true + deploy.guid mustEqual PlanetSideGUID(4748) + health mustEqual 255 + case _ => + ko + } case _ => ko } @@ -34,9 +43,9 @@ class TRAPDataTest extends Specification { "encode" in { val obj = TRAPData( - SmallDeployableData( - PlacementData(3572.4453f, 3277.9766f, 114.0f, 0f, 0f, 90.0f), - PlanetSideEmpire.VS, false, false, 2, false, true, PlanetSideGUID(4748) + CommonFieldDataWithPlacement( + PlacementData(Vector3(3572.4453f, 3277.9766f, 114.0f), Vector3.z(90)), + CommonFieldData(PlanetSideEmpire.VS, false, false, true, None, false, Some(true), None, PlanetSideGUID(4748)) ), 255 ) diff --git a/common/src/test/scala/game/objectcreate/TelepadDataTest.scala b/common/src/test/scala/game/objectcreate/TelepadDataTest.scala deleted file mode 100644 index 10507986..00000000 --- a/common/src/test/scala/game/objectcreate/TelepadDataTest.scala +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2017 PSForever -package game.objectcreate - -import net.psforever.packet._ -import net.psforever.packet.game._ -import net.psforever.packet.game.objectcreate._ -import org.specs2.mutable._ -import scodec.bits._ - -class TelepadDataTest extends Specification { - val string = hex"17 86000000 5700 f3a a201 80 0302020000000" - //TODO validate the unknown fields before router_guid for testing - - "TelepadData" should { - "decode" in { - PacketCoding.DecodePacket(string).require match { - case ObjectCreateMessage(len, cls, guid, parent, data) => - len mustEqual 134 - cls mustEqual ObjectClass.router_telepad - guid mustEqual PlanetSideGUID(418) - parent.isDefined mustEqual true - parent.get.guid mustEqual PlanetSideGUID(430) - parent.get.slot mustEqual 0 - data.isDefined mustEqual true - data.get.isInstanceOf[TelepadData] mustEqual true - data.get.asInstanceOf[TelepadData].router_guid mustEqual Some(PlanetSideGUID(385)) - case _ => - ko - } - } - - "encode" in { - val obj = TelepadData(0, PlanetSideGUID(385)) - val msg = ObjectCreateMessage(ObjectClass.router_telepad, PlanetSideGUID(418), ObjectCreateMessageParent(PlanetSideGUID(430), 0), obj) - val pkt = PacketCoding.EncodePacket(msg).require.toByteVector - - pkt mustEqual string - } - } -} diff --git a/common/src/test/scala/game/objectcreate/TelepadDeployableDataTest.scala b/common/src/test/scala/game/objectcreate/TelepadDeployableDataTest.scala index e0d74b44..7f342a49 100644 --- a/common/src/test/scala/game/objectcreate/TelepadDeployableDataTest.scala +++ b/common/src/test/scala/game/objectcreate/TelepadDeployableDataTest.scala @@ -20,37 +20,57 @@ class TelepadDeployableDataTest extends Specification { cls mustEqual ObjectClass.router_telepad_deployable guid mustEqual PlanetSideGUID(353) parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[TelepadDeployableData] mustEqual true - val teledata = data.get.asInstanceOf[TelepadDeployableData] - teledata.pos.coord mustEqual Vector3(6559.961f, 1960.1172f, 13.640625f) - teledata.pos.orient mustEqual Vector3.z(109.6875f) - teledata.pos.vel.isDefined mustEqual false - teledata.faction mustEqual PlanetSideEmpire.TR - teledata.bops mustEqual false - teledata.destroyed mustEqual false - teledata.unk1 mustEqual 2 - teledata.unk2 mustEqual true - teledata.router_guid mustEqual PlanetSideGUID(385) - teledata.owner_guid mustEqual PlanetSideGUID(430) - teledata.unk3 mustEqual 87 - teledata.unk4 mustEqual 12 + data match { + case DroppedItemData(pos, telepad) => + pos.coord mustEqual Vector3(6559.961f, 1960.1172f, 13.640625f) + pos.orient mustEqual Vector3.z(109.6875f) + pos.vel.isDefined mustEqual false + + telepad match { + case TelepadDeployableData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid), u1, u2) => + faction mustEqual PlanetSideEmpire.TR + bops mustEqual false + alternate mustEqual false + v1 mustEqual true + v2.isEmpty mustEqual true + v3 mustEqual false + v4.isEmpty mustEqual true + v5.contains(385) mustEqual true + fguid mustEqual PlanetSideGUID(430) + + u1 mustEqual 87 + u2 mustEqual 12 + case _ => + ko + } + case _ => + ko + } case _ => ko } } "encode" in { - val obj = TelepadDeployableData( + val obj = DroppedItemData( PlacementData( Vector3(6559.961f, 1960.1172f, 13.640625f), Vector3.z(109.6875f) ), - PlanetSideEmpire.TR, - false, false, 2, true, - PlanetSideGUID(385), - PlanetSideGUID(430), - 87, 12 + TelepadDeployableData( + CommonFieldData( + PlanetSideEmpire.TR, + bops = false, + alternate = false, + true, + None, + false, + None, + Some(385), + PlanetSideGUID(430) + ), + 87, 12 + ) ) val msg = ObjectCreateMessage(ObjectClass.router_telepad_deployable, PlanetSideGUID(353), obj) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector diff --git a/common/src/test/scala/game/objectcreate/TrackedProjectileDataTest.scala b/common/src/test/scala/game/objectcreate/TrackedProjectileDataTest.scala index 480c33be..998a50a3 100644 --- a/common/src/test/scala/game/objectcreate/TrackedProjectileDataTest.scala +++ b/common/src/test/scala/game/objectcreate/TrackedProjectileDataTest.scala @@ -3,7 +3,8 @@ package game.objectcreate import net.psforever.packet.PacketCoding import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} -import net.psforever.packet.game.objectcreate.{ObjectClass, PlacementData, TrackedProjectileData} +import net.psforever.packet.game.objectcreate._ +import net.psforever.types.{PlanetSideEmpire, Vector3} import org.specs2.mutable._ import scodec.bits._ @@ -11,32 +12,45 @@ class TrackedProjectileDataTest extends Specification { val string_striker_projectile = hex"17 C5000000 A4B 009D 4C129 0CB0A 9814 00 F5 E3 040000666686400" "TrackedProjectileData" should { - "decode (striker projectile)" in { + "decode" in { PacketCoding.DecodePacket(string_striker_projectile).require match { case ObjectCreateMessage(len, cls, guid, parent, data) => len mustEqual 197 cls mustEqual ObjectClass.striker_missile_targeting_projectile guid mustEqual PlanetSideGUID(40192) parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[TrackedProjectileData] mustEqual true - val projectile = data.get.asInstanceOf[TrackedProjectileData] - projectile.pos.coord.x mustEqual 4644.5938f - projectile.pos.coord.y mustEqual 5472.0938f - projectile.pos.coord.z mustEqual 82.375f - projectile.pos.orient.x mustEqual 0f - projectile.pos.orient.y mustEqual 30.9375f - projectile.pos.orient.z mustEqual 171.5625f - projectile.unk1 mustEqual 0 - projectile.unk2 mustEqual TrackedProjectileData.striker_missile_targetting_projectile_data + data match { + case TrackedProjectileData(CommonFieldDataWithPlacement(pos, deploy), unk2, unk3) => + pos.coord mustEqual Vector3(4644.5938f, 5472.0938f, 82.375f) + pos.orient mustEqual Vector3(0, 30.9375f, 171.5625f) + deploy.faction mustEqual PlanetSideEmpire.TR + deploy.bops mustEqual false + deploy.alternate mustEqual false + deploy.v1 mustEqual true + deploy.v2.isEmpty mustEqual true + deploy.v3 mustEqual false + deploy.v4.isEmpty mustEqual true + deploy.v5.isEmpty mustEqual true + deploy.guid mustEqual PlanetSideGUID(0) + + unk2 mustEqual TrackedProjectile.Striker + + unk3 mustEqual 0 + case _ => + ko + } case _ => ko } } - "encode (striker projectile)" in { - val obj = TrackedProjectileData.striker( - PlacementData(4644.5938f, 5472.0938f, 82.375f, 0f, 30.9375f, 171.5625f), + "encode" in { + val obj = TrackedProjectileData( + CommonFieldDataWithPlacement( + PlacementData(4644.5938f, 5472.0938f, 82.375f, 0f, 30.9375f, 171.5625f), + CommonFieldData(PlanetSideEmpire.TR, false, false, true, None, false, None, None, PlanetSideGUID(0)) + ), + TrackedProjectile.Striker, 0 ) val msg = ObjectCreateMessage(ObjectClass.striker_missile_targeting_projectile, PlanetSideGUID(40192), obj) @@ -46,25 +60,5 @@ class TrackedProjectileDataTest extends Specification { pkt.toBitVector.drop(133).take(7) mustEqual string_striker_projectile.toBitVector.drop(133).take(7) pkt.toBitVector.drop(141) mustEqual string_striker_projectile.toBitVector.drop(141) } - - "hunter_seeker" in { - TrackedProjectileData.hunter_seeker(PlacementData(0f, 0f, 0f), 0) mustEqual - TrackedProjectileData(PlacementData(0f, 0f, 0f), 0, TrackedProjectileData.hunter_seeker_missile_projectile_data) - } - - "oicw" in { - TrackedProjectileData.oicw(PlacementData(0f, 0f, 0f), 0) mustEqual - TrackedProjectileData(PlacementData(0f, 0f, 0f), 0, TrackedProjectileData.oicw_projectile_data) - } - - "starfire" in { - TrackedProjectileData.starfire(PlacementData(0f, 0f, 0f), 0) mustEqual - TrackedProjectileData(PlacementData(0f, 0f, 0f), 0, TrackedProjectileData.starfire_projectile_data) - } - - "striker" in { - TrackedProjectileData.striker(PlacementData(0f, 0f, 0f), 0) mustEqual - TrackedProjectileData(PlacementData(0f, 0f, 0f), 0, TrackedProjectileData.striker_missile_targetting_projectile_data) - } } } diff --git a/common/src/test/scala/game/objectcreate/WeaponDataTest.scala b/common/src/test/scala/game/objectcreate/WeaponDataTest.scala index b4b87b0c..c9e504bd 100644 --- a/common/src/test/scala/game/objectcreate/WeaponDataTest.scala +++ b/common/src/test/scala/game/objectcreate/WeaponDataTest.scala @@ -4,6 +4,7 @@ package game.objectcreate import net.psforever.packet.PacketCoding import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} import net.psforever.packet.game.objectcreate._ +import net.psforever.types.PlanetSideEmpire import org.specs2.mutable._ import scodec.bits._ @@ -23,18 +24,40 @@ class WeaponDataTest extends Specification { parent.isDefined mustEqual true parent.get.guid mustEqual PlanetSideGUID(4141) parent.get.slot mustEqual 3 - data.isDefined mustEqual true - data.get.isInstanceOf[WeaponData] mustEqual true - val wep = data.get.asInstanceOf[WeaponData] - wep.unk1 mustEqual 4 - wep.unk2 mustEqual 8 - wep.fire_mode mustEqual 0 - wep.ammo.head.objectClass mustEqual ObjectClass.energy_cell - wep.ammo.head.guid mustEqual PlanetSideGUID(3548) - wep.ammo.head.parentSlot mustEqual 0 - wep.ammo.head.obj.isInstanceOf[AmmoBoxData] mustEqual true - val ammo = wep.ammo.head.obj.asInstanceOf[AmmoBoxData] - ammo.unk mustEqual 8 + data match { + case WeaponData(CommonFieldData(wfaction, wbops, walternate, wv1, wv2, wv3, wv4, wv5, wfguid), fmode, List(ammo), _) => + wfaction mustEqual PlanetSideEmpire.VS + wbops mustEqual false + walternate mustEqual false + wv1 mustEqual true + wv2.isEmpty mustEqual true + wv3 mustEqual false + wv4.isEmpty mustEqual true + wv5.isEmpty mustEqual true + wfguid mustEqual PlanetSideGUID(0) + + fmode mustEqual 0 + + ammo.objectClass mustEqual ObjectClass.energy_cell + ammo.guid mustEqual PlanetSideGUID(3548) + ammo.parentSlot mustEqual 0 + ammo.obj match { + case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid) => + faction mustEqual PlanetSideEmpire.NEUTRAL + bops mustEqual false + alternate mustEqual false + v1 mustEqual true + v2.isEmpty mustEqual true + v3 mustEqual false + v4.contains(false) mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + case _ => + ko + } case _ => ko } @@ -49,26 +72,59 @@ class WeaponDataTest extends Specification { parent.isDefined mustEqual true parent.get.guid mustEqual PlanetSideGUID(3092) parent.get.slot mustEqual 3 - data.isDefined mustEqual true - data.get.isInstanceOf[WeaponData] mustEqual true - val wep = data.get.asInstanceOf[WeaponData] - wep.unk1 mustEqual 4 - wep.unk2 mustEqual 8 - wep.fire_mode mustEqual 0 - val ammo = wep.ammo - ammo.size mustEqual 2 - //0 - ammo.head.objectClass mustEqual ObjectClass.bullet_9mm - ammo.head.guid mustEqual PlanetSideGUID(3918) - ammo.head.parentSlot mustEqual 0 - ammo.head.obj.isInstanceOf[AmmoBoxData] mustEqual true - ammo.head.obj.asInstanceOf[AmmoBoxData].unk mustEqual 8 - //1 - ammo(1).objectClass mustEqual ObjectClass.rocket - ammo(1).guid mustEqual PlanetSideGUID(3941) - ammo(1).parentSlot mustEqual 1 - ammo(1).obj.isInstanceOf[AmmoBoxData] mustEqual true - ammo(1).obj.asInstanceOf[AmmoBoxData].unk mustEqual 8 + data match { + case WeaponData(CommonFieldData(wfaction, wbops, walternate, wv1, wv2, wv3, wv4, wv5, wfguid), fmode, ammo, _) => + wfaction mustEqual PlanetSideEmpire.VS + wbops mustEqual false + walternate mustEqual false + wv1 mustEqual true + wv2.isEmpty mustEqual true + wv3 mustEqual false + wv4.isEmpty mustEqual true + wv5.isEmpty mustEqual true + wfguid mustEqual PlanetSideGUID(0) + + fmode mustEqual 0 + //0 + ammo.head.objectClass mustEqual ObjectClass.bullet_9mm + ammo.head.guid mustEqual PlanetSideGUID(3918) + ammo.head.parentSlot mustEqual 0 + ammo.head.obj match { + case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid) => + faction mustEqual PlanetSideEmpire.NEUTRAL + bops mustEqual false + alternate mustEqual false + v1 mustEqual true + v2.isEmpty mustEqual true + v3 mustEqual false + v4.contains(false) mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + //1 + //1 + ammo(1).objectClass mustEqual ObjectClass.rocket + ammo(1).guid mustEqual PlanetSideGUID(3941) + ammo(1).parentSlot mustEqual 1 + ammo(1).obj match { + case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid) => + faction mustEqual PlanetSideEmpire.NEUTRAL + bops mustEqual false + alternate mustEqual false + v1 mustEqual true + v2.isEmpty mustEqual true + v3 mustEqual false + v4.contains(false) mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + case _ => + ko + } case _ => ko } @@ -81,26 +137,48 @@ class WeaponDataTest extends Specification { cls mustEqual ObjectClass.lasher guid mustEqual PlanetSideGUID(3074) parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[DroppedItemData[_]] mustEqual true - val drop = data.get.asInstanceOf[DroppedItemData[_]] + data.isInstanceOf[DroppedItemData[_]] mustEqual true + val drop = data.asInstanceOf[DroppedItemData[_]] drop.pos.coord.x mustEqual 4691.1953f drop.pos.coord.y mustEqual 5537.039f drop.pos.coord.z mustEqual 65.484375f drop.pos.orient.x mustEqual 0f drop.pos.orient.y mustEqual 0f drop.pos.orient.z mustEqual 0f - drop.obj.isInstanceOf[WeaponData] mustEqual true - val wep = drop.obj.asInstanceOf[WeaponData] - wep.unk1 mustEqual 4 - wep.unk2 mustEqual 0 - wep.fire_mode mustEqual 0 - wep.ammo.head.objectClass mustEqual ObjectClass.energy_cell - wep.ammo.head.guid mustEqual PlanetSideGUID(3268) - wep.ammo.head.parentSlot mustEqual 0 - wep.ammo.head.obj.isInstanceOf[AmmoBoxData] mustEqual true - val ammo = wep.ammo.head.obj.asInstanceOf[AmmoBoxData] - ammo.unk mustEqual 0 + drop.obj match { + case WeaponData(CommonFieldData(wfaction, wbops, walternate, wv1, wv2, wv3, wv4, wv5, wfguid), fmode, List(ammo), _) => + wfaction mustEqual PlanetSideEmpire.VS + wbops mustEqual false + walternate mustEqual false + wv1 mustEqual false + wv2.isEmpty mustEqual true + wv3 mustEqual false + wv4.isEmpty mustEqual true + wv5.isEmpty mustEqual true + wfguid mustEqual PlanetSideGUID(0) + + fmode mustEqual 0 + + ammo.objectClass mustEqual ObjectClass.energy_cell + ammo.guid mustEqual PlanetSideGUID(3268) + ammo.parentSlot mustEqual 0 + ammo.obj match { + case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid) => + faction mustEqual PlanetSideEmpire.NEUTRAL + bops mustEqual false + alternate mustEqual false + v1 mustEqual false + v2.isEmpty mustEqual true + v3 mustEqual false + v4.contains(false) mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + case _ => + ko + } case _ => ko } @@ -113,41 +191,78 @@ class WeaponDataTest extends Specification { cls mustEqual ObjectClass.punisher guid mustEqual PlanetSideGUID(2978) parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[DroppedItemData[_]] mustEqual true - val drop = data.get.asInstanceOf[DroppedItemData[_]] + data.isInstanceOf[DroppedItemData[_]] mustEqual true + val drop = data.asInstanceOf[DroppedItemData[_]] drop.pos.coord.x mustEqual 4789.133f drop.pos.coord.y mustEqual 5522.3125f drop.pos.coord.z mustEqual 72.3125f drop.pos.orient.x mustEqual 0f drop.pos.orient.y mustEqual 0f drop.pos.orient.z mustEqual 306.5625f - drop.obj.isInstanceOf[WeaponData] mustEqual true - val wep = drop.obj.asInstanceOf[WeaponData] - wep.unk1 mustEqual 2 - wep.unk2 mustEqual 0 - wep.fire_mode mustEqual 0 - val ammo = wep.ammo - ammo.size mustEqual 2 - //0 - ammo.head.objectClass mustEqual ObjectClass.bullet_9mm - ammo.head.guid mustEqual PlanetSideGUID(3528) - ammo.head.parentSlot mustEqual 0 - ammo.head.obj.isInstanceOf[AmmoBoxData] mustEqual true - ammo.head.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0 - //1 - ammo(1).objectClass mustEqual ObjectClass.rocket - ammo(1).guid mustEqual PlanetSideGUID(3031) - ammo(1).parentSlot mustEqual 1 - ammo(1).obj.isInstanceOf[AmmoBoxData] mustEqual true - ammo(1).obj.asInstanceOf[AmmoBoxData].unk mustEqual 0 + drop.obj match { + case WeaponData(CommonFieldData(wfaction, wbops, walternate, wv1, wv2, wv3, wv4, wv5, wfguid), fmode, ammo, _) => + wfaction mustEqual PlanetSideEmpire.NC + wbops mustEqual false + walternate mustEqual false + wv1 mustEqual false + wv2.isEmpty mustEqual true + wv3 mustEqual false + wv4.isEmpty mustEqual true + wv5.isEmpty mustEqual true + wfguid mustEqual PlanetSideGUID(0) + + fmode mustEqual 0 + //0 + ammo.head.objectClass mustEqual ObjectClass.bullet_9mm + ammo.head.guid mustEqual PlanetSideGUID(3528) + ammo.head.parentSlot mustEqual 0 + ammo.head.obj match { + case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid) => + faction mustEqual PlanetSideEmpire.NEUTRAL + bops mustEqual false + alternate mustEqual false + v1 mustEqual false + v2.isEmpty mustEqual true + v3 mustEqual false + v4.contains(false) mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + //1 + //1 + ammo(1).objectClass mustEqual ObjectClass.rocket + ammo(1).guid mustEqual PlanetSideGUID(3031) + ammo(1).parentSlot mustEqual 1 + ammo(1).obj match { + case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid) => + faction mustEqual PlanetSideEmpire.NEUTRAL + bops mustEqual false + alternate mustEqual false + v1 mustEqual false + v2.isEmpty mustEqual true + v3 mustEqual false + v4.contains(false) mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + case _ => + ko + } case _ => ko } } "encode (lasher, held)" in { - val obj = WeaponData(4, 8, ObjectClass.energy_cell, PlanetSideGUID(3548), 0, AmmoBoxData(8)) + val obj = WeaponData( + CommonFieldData(PlanetSideEmpire.VS, false, false, true, None, false, None, None, PlanetSideGUID(0)), + 0, + List(InternalSlot(ObjectClass.energy_cell, PlanetSideGUID(3548), 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false))) + ) val msg = ObjectCreateMessage(ObjectClass.lasher, PlanetSideGUID(3033), ObjectCreateMessageParent(PlanetSideGUID(4141), 3), obj) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector pkt mustEqual string_lasher_held @@ -155,11 +270,14 @@ class WeaponDataTest extends Specification { "encode (punisher, held)" in { val obj = - WeaponData(4, 8, 0, - AmmoBoxData(ObjectClass.bullet_9mm, PlanetSideGUID(3918), 0, AmmoBoxData(8)) :: - AmmoBoxData(ObjectClass.rocket, PlanetSideGUID(3941), 1, AmmoBoxData(8)) :: - Nil - )(2) + WeaponData( + CommonFieldData(PlanetSideEmpire.VS, false, false, true, None, false, None, None, PlanetSideGUID(0)), + 0, + List( + AmmoBoxData(ObjectClass.bullet_9mm, PlanetSideGUID(3918), 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)), + AmmoBoxData(ObjectClass.rocket, PlanetSideGUID(3941), 1, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) + ) + ) val msg = ObjectCreateMessage(ObjectClass.punisher, PlanetSideGUID(4147), ObjectCreateMessageParent(PlanetSideGUID(3092), 3), obj) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector pkt mustEqual string_punisher_held @@ -168,7 +286,11 @@ class WeaponDataTest extends Specification { "encode (lasher, dropped)" in { val obj = DroppedItemData( PlacementData(4691.1953f, 5537.039f, 65.484375f, 0.0f, 0.0f, 0.0f), - WeaponData(4, 0, ObjectClass.energy_cell, PlanetSideGUID(3268), 0, AmmoBoxData()) + WeaponData( + CommonFieldData(PlanetSideEmpire.VS, false, false, false, None, false, None, None, PlanetSideGUID(0)), + 0, + List(InternalSlot(ObjectClass.energy_cell, PlanetSideGUID(3268), 0, CommonFieldData()(false))) + ) ) val msg = ObjectCreateMessage(ObjectClass.lasher, PlanetSideGUID(3074), obj) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector @@ -178,11 +300,14 @@ class WeaponDataTest extends Specification { "encode (punisher, dropped)" in { val obj = DroppedItemData( PlacementData(4789.133f, 5522.3125f, 72.3125f, 0f, 0f, 306.5625f), - WeaponData(2, 0, 0, - AmmoBoxData(ObjectClass.bullet_9mm, PlanetSideGUID(3528), 0, AmmoBoxData()) :: - AmmoBoxData(ObjectClass.rocket, PlanetSideGUID(3031), 1, AmmoBoxData()) :: - Nil - )(2) + WeaponData( + CommonFieldData(PlanetSideEmpire.NC, false, false, false, None, false, None, None, PlanetSideGUID(0)), + 0, + List( + AmmoBoxData(ObjectClass.bullet_9mm, PlanetSideGUID(3528), 0, CommonFieldData()(false)), + AmmoBoxData(ObjectClass.rocket, PlanetSideGUID(3031), 1, CommonFieldData()(false)) + ) + ) ) val msg = ObjectCreateMessage(ObjectClass.punisher, PlanetSideGUID(2978), obj) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector diff --git a/common/src/test/scala/game/objectcreatedetailed/DetailedACEDataTest.scala b/common/src/test/scala/game/objectcreatedetailed/DetailedACEDataTest.scala deleted file mode 100644 index 24214f09..00000000 --- a/common/src/test/scala/game/objectcreatedetailed/DetailedACEDataTest.scala +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2017 PSForever -package game.objectcreatedetailed - -import org.specs2.mutable._ -import net.psforever.packet._ -import net.psforever.packet.game.{ObjectCreateDetailedMessage, _} -import net.psforever.packet.game.objectcreate._ -import scodec.bits._ - -class DetailedACEDataTest extends Specification { - val string_ace = hex"18 87000000 1006 100 C70B 80 8800000200008" - - "DetailedACEData" should { - "decode" in { - PacketCoding.DecodePacket(string_ace).require match { - case ObjectCreateDetailedMessage(len, cls, guid, parent, data) => - len mustEqual 135 - cls mustEqual ObjectClass.ace - guid mustEqual PlanetSideGUID(3015) - parent.isDefined mustEqual true - parent.get.guid mustEqual PlanetSideGUID(3104) - parent.get.slot mustEqual 0 - data.isDefined mustEqual true - data.get.isInstanceOf[DetailedACEData] mustEqual true - data.get.asInstanceOf[DetailedACEData].unk mustEqual 8 - case _ => - ko - } - } - - "encode" in { - val obj = DetailedACEData(8) - val msg = ObjectCreateDetailedMessage(ObjectClass.ace, PlanetSideGUID(3015), ObjectCreateMessageParent(PlanetSideGUID(3104), 0), obj) - val pkt = PacketCoding.EncodePacket(msg).require.toByteVector - - pkt mustEqual string_ace - } - } -} diff --git a/common/src/test/scala/game/objectcreatedetailed/DetailedAmmoBoxDataTest.scala b/common/src/test/scala/game/objectcreatedetailed/DetailedAmmoBoxDataTest.scala index 0b9ae180..b3afa5cf 100644 --- a/common/src/test/scala/game/objectcreatedetailed/DetailedAmmoBoxDataTest.scala +++ b/common/src/test/scala/game/objectcreatedetailed/DetailedAmmoBoxDataTest.scala @@ -20,8 +20,7 @@ class DetailedAmmoBoxDataTest extends Specification { parent.isDefined mustEqual true parent.get.guid mustEqual PlanetSideGUID(75) parent.get.slot mustEqual 33 - data.isDefined mustEqual true - data.get.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 50 + data.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 50 case _ => ko } @@ -30,7 +29,8 @@ class DetailedAmmoBoxDataTest extends Specification { "encode (9mm)" in { val obj = DetailedAmmoBoxData(8, 50) val msg = ObjectCreateDetailedMessage(ObjectClass.bullet_9mm, PlanetSideGUID(1280), ObjectCreateMessageParent(PlanetSideGUID(75), 33), obj) - val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + val out = PacketCoding.EncodePacket(msg) + val pkt = out.require.toByteVector pkt mustEqual string_9mm } diff --git a/common/src/test/scala/game/objectcreatedetailed/DetailedBoomerTriggerDataTest.scala b/common/src/test/scala/game/objectcreatedetailed/DetailedBoomerTriggerDataTest.scala deleted file mode 100644 index e67d5de6..00000000 --- a/common/src/test/scala/game/objectcreatedetailed/DetailedBoomerTriggerDataTest.scala +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2017 PSForever -package game.objectcreatedetailed - -import org.specs2.mutable._ -import net.psforever.packet._ -import net.psforever.packet.game.{ObjectCreateDetailedMessage, _} -import net.psforever.packet.game.objectcreate._ -import scodec.bits._ - -class DetailedBoomerTriggerDataTest extends Specification { - val string_boomer_trigger = hex"18 87000000 6304CA8760B 80 C800000200008" - - "DetailedBoomerTriggerData" should { - "decode" in { - PacketCoding.DecodePacket(string_boomer_trigger).require match { - case ObjectCreateDetailedMessage(len, cls, guid, parent, data) => - len mustEqual 135 - cls mustEqual ObjectClass.boomer_trigger - guid mustEqual PlanetSideGUID(2934) - parent.isDefined mustEqual true - parent.get.guid mustEqual PlanetSideGUID(2502) - parent.get.slot mustEqual 0 - data.isDefined mustEqual true - data.get.isInstanceOf[DetailedBoomerTriggerData] mustEqual true - case _ => - ko - } - } - - "encode" in { - val obj = DetailedBoomerTriggerData() - val msg = ObjectCreateDetailedMessage(ObjectClass.boomer_trigger, PlanetSideGUID(2934), ObjectCreateMessageParent(PlanetSideGUID(2502), 0), obj) - val pkt = PacketCoding.EncodePacket(msg).require.toByteVector - - pkt mustEqual string_boomer_trigger - } - } -} diff --git a/common/src/test/scala/game/objectcreatedetailed/DetailedCharacterDataTest.scala b/common/src/test/scala/game/objectcreatedetailed/DetailedCharacterDataTest.scala index b611f048..84bdd517 100644 --- a/common/src/test/scala/game/objectcreatedetailed/DetailedCharacterDataTest.scala +++ b/common/src/test/scala/game/objectcreatedetailed/DetailedCharacterDataTest.scala @@ -55,7 +55,7 @@ class DetailedCharacterDataTest extends Specification { guid mustEqual PlanetSideGUID(75) parent.isDefined mustEqual false data match { - case Some(DetailedPlayerData(Some(pos), basic, char, inv, hand)) => + case DetailedPlayerData(Some(pos), basic, char, inv, hand) => pos.coord mustEqual Vector3(3674.8438f, 2726.789f, 91.15625f) pos.orient mustEqual Vector3(0, 0, 36.5625f) pos.vel.isDefined mustEqual false @@ -67,13 +67,13 @@ class DetailedCharacterDataTest extends Specification { a.app.sex mustEqual CharacterGender.Female a.app.head mustEqual 41 a.app.voice mustEqual CharacterVoice.Voice1 - a.black_ops mustEqual false - a.jammered mustEqual false + a.data.bops mustEqual false + a.data.v1 mustEqual true + a.data.v2.isEmpty mustEqual true + a.data.v3 mustEqual false + a.data.v4.isEmpty mustEqual true + a.data.v5.isEmpty mustEqual true a.exosuit mustEqual ExoSuitType.Standard - a.unk1 mustEqual true - a.unk2 mustEqual None - a.unk3 mustEqual None - a.unk4 mustEqual 0 a.unk5 mustEqual 0 a.unk6 mustEqual 41605313L a.unk7 mustEqual 0 @@ -90,7 +90,7 @@ class DetailedCharacterDataTest extends Specification { b.grenade_state mustEqual GrenadeState.None b.is_cloaking mustEqual false b.charging_pose mustEqual false - b.on_zipline mustEqual None + b.on_zipline.isEmpty mustEqual true b.unk0 mustEqual 0L b.unk1 mustEqual false b.unk2 mustEqual false @@ -117,7 +117,7 @@ class DetailedCharacterDataTest extends Specification { a.armor mustEqual 50 //standard exosuit value a.staminaMax mustEqual 100 a.stamina mustEqual 100 - a.max_field mustEqual None + a.max_field.isEmpty mustEqual true a.certs mustEqual List( CertificationType.StandardAssault, CertificationType.MediumAssault, @@ -145,8 +145,8 @@ class DetailedCharacterDataTest extends Specification { "map13" ) b.tutorials mustEqual Nil - b.cosmetics mustEqual None - b.unk1 mustEqual None + b.cosmetics.isEmpty mustEqual true + b.unk1.isEmpty mustEqual true b.unk2 mustEqual Nil b.unk3 mustEqual Nil b.unk4 mustEqual 0L @@ -154,7 +154,7 @@ class DetailedCharacterDataTest extends Specification { b.unk6 mustEqual 0L b.unk7 mustEqual 0L b.unk8 mustEqual 0L - b.unk9 mustEqual Some(DCDExtra2(0, 0)) + b.unk9.contains(DCDExtra2(0, 0)) mustEqual true b.unkA mustEqual Nil b.unkB mustEqual Nil b.unkC mustEqual false @@ -247,7 +247,7 @@ class DetailedCharacterDataTest extends Specification { parent.get.guid mustEqual PlanetSideGUID(43981) parent.get.slot mustEqual 0 data match { - case Some(DetailedPlayerData(None, basic, char, inv, hand)) => + case DetailedPlayerData(None, basic, char, inv, hand) => basic match { case CharacterAppearanceData(a, b, ribbons) => a.app.name mustEqual "IlllIIIlllIlIllIlllIllI" @@ -255,13 +255,13 @@ class DetailedCharacterDataTest extends Specification { a.app.sex mustEqual CharacterGender.Female a.app.head mustEqual 41 a.app.voice mustEqual CharacterVoice.Voice1 - a.black_ops mustEqual false - a.jammered mustEqual false + a.data.bops mustEqual false + a.data.v1 mustEqual false + a.data.v2.isEmpty mustEqual true + a.data.v3 mustEqual false + a.data.v4.isEmpty mustEqual true + a.data.v5.isEmpty mustEqual true a.exosuit mustEqual ExoSuitType.Standard - a.unk1 mustEqual false - a.unk2 mustEqual None - a.unk3 mustEqual None - a.unk4 mustEqual 0 a.unk5 mustEqual 0 a.unk6 mustEqual 192L a.unk7 mustEqual 0 @@ -278,7 +278,7 @@ class DetailedCharacterDataTest extends Specification { b.grenade_state mustEqual GrenadeState.None b.is_cloaking mustEqual false b.charging_pose mustEqual false - b.on_zipline mustEqual None + b.on_zipline.isEmpty mustEqual true b.unk0 mustEqual 0L b.unk1 mustEqual false b.unk2 mustEqual false @@ -305,7 +305,7 @@ class DetailedCharacterDataTest extends Specification { a.armor mustEqual 50 //standard exosuit value a.staminaMax mustEqual 100 a.stamina mustEqual 100 - a.max_field mustEqual None + a.max_field.isEmpty mustEqual true a.certs mustEqual List( CertificationType.StandardAssault, CertificationType.MediumAssault, @@ -333,8 +333,8 @@ class DetailedCharacterDataTest extends Specification { "map13" ) b.tutorials mustEqual Nil - b.cosmetics mustEqual None - b.unk1 mustEqual None + b.cosmetics.isEmpty mustEqual true + b.unk1.isEmpty mustEqual true b.unk2 mustEqual Nil b.unk3 mustEqual Nil b.unk4 mustEqual 0L @@ -342,7 +342,7 @@ class DetailedCharacterDataTest extends Specification { b.unk6 mustEqual 0L b.unk7 mustEqual 0L b.unk8 mustEqual 0L - b.unk9 mustEqual Some(DCDExtra2(0, 0)) + b.unk9.contains(DCDExtra2(0, 0)) mustEqual true b.unkA mustEqual Nil b.unkB mustEqual Nil b.unkC mustEqual false @@ -432,7 +432,7 @@ class DetailedCharacterDataTest extends Specification { //the object produced is massive and most of it is already covered in other tests //only certain details towards the end of the stream will be checked data match { - case Some(DetailedPlayerData(Some(p), basic, char, inv, hand)) => + case DetailedPlayerData(Some(_), basic, char, inv, hand) => basic match { case CharacterAppearanceData(a, b, ribbons) => a.app.name mustEqual "HaHaATRMax" @@ -440,13 +440,13 @@ class DetailedCharacterDataTest extends Specification { a.app.sex mustEqual CharacterGender.Male a.app.head mustEqual 57 a.app.voice mustEqual CharacterVoice.Voice1 - a.black_ops mustEqual false - a.jammered mustEqual false + a.data.bops mustEqual false + a.data.v1 mustEqual true + a.data.v2.isEmpty mustEqual true + a.data.v3 mustEqual false + a.data.v4.isEmpty mustEqual true + a.data.v5.isEmpty mustEqual true a.exosuit mustEqual ExoSuitType.MAX - a.unk1 mustEqual true - a.unk2 mustEqual None - a.unk3 mustEqual None - a.unk4 mustEqual 0 a.unk5 mustEqual 1 a.unk6 mustEqual 41605870L a.unk7 mustEqual 0 @@ -463,7 +463,7 @@ class DetailedCharacterDataTest extends Specification { b.grenade_state mustEqual GrenadeState.None b.is_cloaking mustEqual false b.charging_pose mustEqual false - b.on_zipline mustEqual None + b.on_zipline.isEmpty mustEqual true b.unk0 mustEqual 0L b.unk1 mustEqual false b.unk2 mustEqual false @@ -491,7 +491,7 @@ class DetailedCharacterDataTest extends Specification { a.armor mustEqual 641 a.staminaMax mustEqual 100 a.stamina mustEqual 100 - a.max_field mustEqual Some(0) //important! + a.max_field.contains(0) mustEqual true //important! a.certs mustEqual List( CertificationType.StandardAssault, CertificationType.MediumAssault, @@ -561,8 +561,8 @@ class DetailedCharacterDataTest extends Specification { "map02" ) b.tutorials mustEqual Nil - b.cosmetics mustEqual None - b.unk1 mustEqual None + b.cosmetics.isEmpty mustEqual true + b.unk1.isEmpty mustEqual true b.unk2 mustEqual Nil b.unk3 mustEqual Nil b.unk4 mustEqual 0L @@ -570,7 +570,7 @@ class DetailedCharacterDataTest extends Specification { b.unk6 mustEqual 0L b.unk7 mustEqual 0L b.unk8 mustEqual 0L - b.unk9 mustEqual Some(DCDExtra2(0, 0)) + b.unk9.contains(DCDExtra2(0, 0)) mustEqual true b.unkA mustEqual Nil b.unkB mustEqual Nil b.unkC mustEqual false @@ -583,18 +583,29 @@ class DetailedCharacterDataTest extends Specification { val contents = inv.get.contents //0 contents.head mustEqual InternalSlot(889, PlanetSideGUID(2), 0, - DetailedWeaponData(0,8,0, List( - InternalSlot(265, PlanetSideGUID(3), 0, DetailedAmmoBoxData(8,200)), - InternalSlot(265, PlanetSideGUID(4), 1, DetailedAmmoBoxData(8,200)), - InternalSlot(265, PlanetSideGUID(5), 2, DetailedAmmoBoxData(8,200)) - )) + DetailedWeaponData( + CommonFieldData(PlanetSideEmpire.TR, false, false, true, None, false, None, None, PlanetSideGUID(0)), + 0, + List( + InternalSlot(265, PlanetSideGUID(3), 0, DetailedAmmoBoxData(8,200)), + InternalSlot(265, PlanetSideGUID(4), 1, DetailedAmmoBoxData(8,200)), + InternalSlot(265, PlanetSideGUID(5), 2, DetailedAmmoBoxData(8,200)) + ) + ) ) contents(1) mustEqual InternalSlot(175, PlanetSideGUID(6), 4, - DetailedWeaponData(0,8,0, List( - InternalSlot(540, PlanetSideGUID(7), 0, DetailedAmmoBoxData(8,1)) - )) + DetailedWeaponData( + CommonFieldData(PlanetSideEmpire.TR, false, false, true, None, false, None, None, PlanetSideGUID(0)), + 0, + List( + InternalSlot(540, PlanetSideGUID(7), 0, DetailedAmmoBoxData(8,1)) + ) + ) ) - contents(2) mustEqual InternalSlot(456, PlanetSideGUID(8), 5, DetailedLockerContainerData(8, None)) + contents(2) mustEqual InternalSlot(456, PlanetSideGUID(8), 5, DetailedLockerContainerData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), + None + )) contents(3) mustEqual InternalSlot(265, PlanetSideGUID(9), 6, DetailedAmmoBoxData(8, 36)) contents(4) mustEqual InternalSlot(265, PlanetSideGUID(10), 10, DetailedAmmoBoxData(8, 100)) contents(5) mustEqual InternalSlot(265, PlanetSideGUID(11), 14, DetailedAmmoBoxData(8, 100)) @@ -629,7 +640,7 @@ class DetailedCharacterDataTest extends Specification { //the object produced is massive and most of it is already covered in other tests //only certain details towards the end of the stream will be checked data match { - case Some(DetailedPlayerData(Some(_), basic, char, inv, hand)) => + case DetailedPlayerData(Some(_), basic, char, inv, hand) => basic match { case CharacterAppearanceData(a, b, ribbons) => a.app.name mustEqual "KiCkJr" @@ -637,13 +648,13 @@ class DetailedCharacterDataTest extends Specification { a.app.sex mustEqual CharacterGender.Male a.app.head mustEqual 24 a.app.voice mustEqual CharacterVoice.Voice4 - a.black_ops mustEqual false - a.jammered mustEqual false + a.data.bops mustEqual false + a.data.v1 mustEqual true + a.data.v2.isEmpty mustEqual true + a.data.v3 mustEqual false + a.data.v4.isEmpty mustEqual true + a.data.v5.isEmpty mustEqual true a.exosuit mustEqual ExoSuitType.Agile - a.unk1 mustEqual true - a.unk2 mustEqual None - a.unk3 mustEqual None - a.unk4 mustEqual 0 a.unk5 mustEqual 0 a.unk6 mustEqual 733931L a.unk7 mustEqual 0 @@ -660,7 +671,7 @@ class DetailedCharacterDataTest extends Specification { b.grenade_state mustEqual GrenadeState.None b.is_cloaking mustEqual false b.charging_pose mustEqual false - b.on_zipline mustEqual None + b.on_zipline.isEmpty mustEqual true b.unk0 mustEqual 556539L b.unk1 mustEqual false b.unk2 mustEqual false @@ -688,7 +699,7 @@ class DetailedCharacterDataTest extends Specification { a.armor mustEqual 100 //standard exosuit value a.staminaMax mustEqual 100 a.stamina mustEqual 46 - a.max_field mustEqual None + a.max_field.isEmpty mustEqual true a.certs mustEqual List( CertificationType.StandardAssault, CertificationType.MediumAssault, @@ -1026,10 +1037,13 @@ class DetailedCharacterDataTest extends Specification { "training_ui", "training_map" ) - b.cosmetics mustEqual Some( - Cosmetics(true, true, true, true, false) - ) - b.unk1 mustEqual None + b.cosmetics match { + case Some(c : Cosmetics) => + c.Styles mustEqual Set(PersonalStyle.NoHelmet, PersonalStyle.Beret, PersonalStyle.Sunglasses, PersonalStyle.Earpiece) + case None => + ko + } + b.unk1.isEmpty mustEqual true b.unk2 mustEqual Nil b.unk3 mustEqual Nil b.unk4 mustEqual 0L @@ -1037,7 +1051,7 @@ class DetailedCharacterDataTest extends Specification { b.unk6 mustEqual 0L b.unk7 mustEqual 0L b.unk8 mustEqual 0L - b.unk9 mustEqual None + b.unk9.isEmpty mustEqual true b.unkA mustEqual Nil b.unkB mustEqual Nil b.unkC mustEqual false @@ -1051,31 +1065,77 @@ class DetailedCharacterDataTest extends Specification { inv.get.contents.head.objectClass mustEqual 531 inv.get.contents.head.guid mustEqual PlanetSideGUID(4202) inv.get.contents.head.parentSlot mustEqual 0 - val wep1 = inv.get.contents.head.obj.asInstanceOf[DetailedWeaponData] - wep1.unk1 mustEqual 2 - wep1.unk2 mustEqual 8 - wep1.ammo.head.objectClass mustEqual 389 - wep1.ammo.head.guid mustEqual PlanetSideGUID(3942) - wep1.ammo.head.parentSlot mustEqual 0 - wep1.ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].unk mustEqual 8 - wep1.ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 100 + inv.get.contents.head.obj match { + case DetailedWeaponData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid), fmode, ammo, _) => + faction mustEqual PlanetSideEmpire.NC + bops mustEqual false + alternate mustEqual false + v1 mustEqual true + v2.isEmpty mustEqual true + v3 mustEqual false + v4.isEmpty mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + + fmode mustEqual 0 + + ammo.head.objectClass mustEqual 389 + ammo.head.guid mustEqual PlanetSideGUID(3942) + ammo.head.parentSlot mustEqual 0 + ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].data.v1 mustEqual true + ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 100 + case _ => + ko + } //4 inv.get.contents(4).objectClass mustEqual 456 inv.get.contents(4).guid mustEqual PlanetSideGUID(5374) inv.get.contents(4).parentSlot mustEqual 5 inv.get.contents(4).obj.asInstanceOf[DetailedLockerContainerData].inventory.get.contents.size mustEqual 61 + //10 + inv.get.contents(10).objectClass mustEqual 32 + inv.get.contents(10).guid mustEqual PlanetSideGUID(5523) + inv.get.contents(10).parentSlot mustEqual 39 + inv.get.contents(10).obj match { + case cdata : DetailedConstructionToolData => + cdata.data.faction mustEqual PlanetSideEmpire.NC + cdata.data.bops mustEqual false + cdata.data.alternate mustEqual false + cdata.data.v1 mustEqual true + cdata.data.v2.isEmpty mustEqual true + cdata.data.v3 mustEqual false + cdata.data.v4.isEmpty mustEqual true + cdata.data.v5.isEmpty mustEqual true + cdata.data.guid mustEqual PlanetSideGUID(0) + case _ => + ko + } //11 inv.get.contents(11).objectClass mustEqual 673 inv.get.contents(11).guid mustEqual PlanetSideGUID(3661) inv.get.contents(11).parentSlot mustEqual 60 - val wep2 = inv.get.contents(11).obj.asInstanceOf[DetailedWeaponData] - wep2.unk1 mustEqual 2 - wep2.unk2 mustEqual 8 - wep2.ammo.head.objectClass mustEqual 674 - wep2.ammo.head.guid mustEqual PlanetSideGUID(8542) - wep2.ammo.head.parentSlot mustEqual 0 - wep2.ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].unk mustEqual 8 - wep2.ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 3 + inv.get.contents(11).obj match { + case DetailedWeaponData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid), fmode, ammo, _) => + faction mustEqual PlanetSideEmpire.NC + bops mustEqual false + alternate mustEqual false + v1 mustEqual true + v2.isEmpty mustEqual true + v3 mustEqual false + v4.isEmpty mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + + fmode mustEqual 0 + + ammo.head.objectClass mustEqual 674 + ammo.head.guid mustEqual PlanetSideGUID(8542) + ammo.head.parentSlot mustEqual 0 + ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].data.v1 mustEqual true + ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 3 + case _ => + ko + } hand mustEqual DrawnSlot.None case _ => @@ -1091,18 +1151,18 @@ class DetailedCharacterDataTest extends Specification { case ObjectCreateDetailedMessage(len, _, _, None, data) => len mustEqual 51018L data match { - case Some(DetailedPlayerData(_, basic, char, _, _)) => + case DetailedPlayerData(_, basic, char, inv, _) => basic match { case CharacterAppearanceData(a, b, ribbons) => a.app mustEqual BasicCharacterData("CCRIDER", PlanetSideEmpire.NC, CharacterGender.Male, 20, CharacterVoice.Voice3) - a.black_ops mustEqual false - a.altModel mustEqual false - a.unk1 mustEqual false - a.unk2 mustEqual None - a.jammered mustEqual false + a.data.bops mustEqual false + a.data.alternate mustEqual false + a.data.v1 mustEqual false + a.data.v2.isEmpty mustEqual true + a.data.v3 mustEqual false + a.data.v4.isEmpty mustEqual true + a.data.v5.isEmpty mustEqual true a.exosuit mustEqual ExoSuitType.Standard - a.unk3 mustEqual None - a.unk4 mustEqual 0 a.unk5 mustEqual 0 a.unk6 mustEqual 1176612L a.unk7 mustEqual 15 @@ -1127,7 +1187,7 @@ class DetailedCharacterDataTest extends Specification { b.unk6 mustEqual false b.charging_pose mustEqual false b.unk7 mustEqual false - b.on_zipline mustEqual None + b.on_zipline.isEmpty mustEqual true ribbons.upper mustEqual MeritCommendation.DefenseNC5 ribbons.middle mustEqual MeritCommendation.HackingSupport5 @@ -1151,7 +1211,7 @@ class DetailedCharacterDataTest extends Specification { a.unk5 mustEqual 32831L a.staminaMax mustEqual 100 a.stamina mustEqual 100 - a.max_field mustEqual None + a.max_field.isEmpty mustEqual true a.unk6 mustEqual 0 a.unk7 mustEqual 6 a.unk8 mustEqual 3165669L @@ -1172,7 +1232,7 @@ class DetailedCharacterDataTest extends Specification { CertificationType.Engineering ) - b.unk1 mustEqual Some(14140) + b.unk1.contains(14140) mustEqual true b.implants mustEqual List( ImplantEntry(ImplantType.Surge, Some(94), false), ImplantEntry(ImplantType.DarklightVision, Some(91), false), @@ -1196,7 +1256,7 @@ class DetailedCharacterDataTest extends Specification { b.unk6 mustEqual 0L b.unk7 mustEqual 0L b.unk8 mustEqual 0L - b.unk9 mustEqual None + b.unk9.isEmpty mustEqual true b.unkA.size mustEqual 86 b.unkA mustEqual List( 9, @@ -1212,7 +1272,13 @@ class DetailedCharacterDataTest extends Specification { ) b.unkB mustEqual List() b.unkC mustEqual false - b.cosmetics mustEqual Some(Cosmetics(true, false, true, true, true)) + b.cosmetics match { + case Some(c : Cosmetics) => + c.Styles mustEqual Set(PersonalStyle.NoHelmet, PersonalStyle.Sunglasses, PersonalStyle.Earpiece, PersonalStyle.BrimmedCap) + case None => + ko + } + b.cosmetics.contains(Cosmetics(true, false, true, true, true)) mustEqual true case _ => ko } @@ -1237,14 +1303,18 @@ class DetailedCharacterDataTest extends Specification { 41, CharacterVoice.Voice1 ), - false, - false, - true, - None, - false, + CommonFieldData( + PlanetSideEmpire.VS, + false, + false, + true, + None, + false, + None, + None, + PlanetSideGUID(0) + ), ExoSuitType.Standard, - None, - 0, 0, 41605313L, 0, @@ -1272,7 +1342,7 @@ class DetailedCharacterDataTest extends Specification { None ) - val app : (Int)=>CharacterAppearanceData = CharacterAppearanceData( + val app : Int=>CharacterAppearanceData = CharacterAppearanceData( aa, ab, RibbonBars( MeritCommendation.None, @@ -1319,25 +1389,38 @@ class DetailedCharacterDataTest extends Specification { Nil, Nil, false, None ) - val char : (Option[Int])=>DetailedCharacterData = + val char : Option[Int]=>DetailedCharacterData = (pad_length : Option[Int]) => DetailedCharacterData(ba, bb(ba.bep, pad_length))(pad_length) - val inv = InventoryData( + val inv = InventoryData(List( InventoryItemData(ObjectClass.beamer, PlanetSideGUID(76), 0, - DetailedWeaponData(4, 8, ObjectClass.energy_cell, PlanetSideGUID(77), 0, DetailedAmmoBoxData(8, 16))) :: + DetailedWeaponData( + CommonFieldData(PlanetSideEmpire.VS, false, false, true, None, false, None, None, PlanetSideGUID(0)), + 0, + List(InternalSlot(ObjectClass.energy_cell, PlanetSideGUID(77), 0, DetailedAmmoBoxData(8, 16))) + ) + ), InventoryItemData(ObjectClass.suppressor, PlanetSideGUID(78), 2, - DetailedWeaponData(4, 8, ObjectClass.bullet_9mm, PlanetSideGUID(79), 0, DetailedAmmoBoxData(8, 25))) :: + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.VS, false, false, true, None, false, None, None, PlanetSideGUID(0)), + 0, + List(InternalSlot(ObjectClass.bullet_9mm, PlanetSideGUID(79), 0, DetailedAmmoBoxData(8, 25))) + ) + ), InventoryItemData(ObjectClass.forceblade, PlanetSideGUID(80), 4, - DetailedWeaponData(4, 8, ObjectClass.melee_ammo, PlanetSideGUID(81), 0, DetailedAmmoBoxData(8, 1))) :: - InventoryItemData(ObjectClass.locker_container, PlanetSideGUID(82), 5, DetailedLockerContainerData(8)) :: - InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(83), 6, DetailedAmmoBoxData(8, 50)) :: - InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(84), 9, DetailedAmmoBoxData(8, 50)) :: - InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(85), 12, DetailedAmmoBoxData(8, 50)) :: - InventoryItemData(ObjectClass.bullet_9mm_AP, PlanetSideGUID(86), 33, DetailedAmmoBoxData(8, 50)) :: - InventoryItemData(ObjectClass.energy_cell, PlanetSideGUID(87), 36, DetailedAmmoBoxData(8, 50)) :: - InventoryItemData(ObjectClass.remote_electronics_kit, PlanetSideGUID(88), 39, DetailedREKData(8)) :: - Nil - ) + DetailedWeaponData( + CommonFieldData(PlanetSideEmpire.VS, false, false, true, None, false, None, None, PlanetSideGUID(0)), + 0, + List(InternalSlot(ObjectClass.melee_ammo, PlanetSideGUID(81), 0, DetailedAmmoBoxData(8, 1))) + ) + ), + InventoryItemData(ObjectClass.locker_container, PlanetSideGUID(82), 5, DetailedLockerContainerData(8)), + InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(83), 6, DetailedAmmoBoxData(8, 50)), + InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(84), 9, DetailedAmmoBoxData(8, 50)), + InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(85), 12, DetailedAmmoBoxData(8, 50)), + InventoryItemData(ObjectClass.bullet_9mm_AP, PlanetSideGUID(86), 33, DetailedAmmoBoxData(8, 50)), + InventoryItemData(ObjectClass.energy_cell, PlanetSideGUID(87), 36, DetailedAmmoBoxData(8, 50)), + InventoryItemData(ObjectClass.remote_electronics_kit, PlanetSideGUID(88), 39, DetailedREKData(CommonFieldData(PlanetSideEmpire.VS, false, false, true, None, false, Some(false), None, PlanetSideGUID(0)))) + )) val obj = DetailedPlayerData.apply(pos, app, char, inv, DrawnSlot.Pistol1) val msg = ObjectCreateDetailedMessage(0x79, PlanetSideGUID(75), obj) @@ -1358,14 +1441,18 @@ class DetailedCharacterDataTest extends Specification { 41, CharacterVoice.Voice1 ), - false, - false, - false, - None, - false, + CommonFieldData( + PlanetSideEmpire.VS, + false, + false, + false, + None, + false, + None, + None, + PlanetSideGUID(0) + ), ExoSuitType.Standard, - None, - 0, 0, 192L, 0, @@ -1393,7 +1480,7 @@ class DetailedCharacterDataTest extends Specification { None ) - val app : (Int)=>CharacterAppearanceData = CharacterAppearanceData( + val app : Int=>CharacterAppearanceData = CharacterAppearanceData( aa, ab, RibbonBars( MeritCommendation.None, @@ -1440,22 +1527,38 @@ class DetailedCharacterDataTest extends Specification { Nil, Nil, false, None ) - val char : (Option[Int])=>DetailedCharacterData = + val char : Option[Int]=>DetailedCharacterData = (pad_length : Option[Int]) => DetailedCharacterData(ba, bb(ba.bep, pad_length))(pad_length) - val inv = InventoryData( - InventoryItemData(ObjectClass.beamer, PlanetSideGUID(76), 0, DetailedWeaponData(4, 8, ObjectClass.energy_cell, PlanetSideGUID(77), 0, DetailedAmmoBoxData(8, 16))) :: - InventoryItemData(ObjectClass.suppressor, PlanetSideGUID(78), 2, DetailedWeaponData(4, 8, ObjectClass.bullet_9mm, PlanetSideGUID(79), 0, DetailedAmmoBoxData(8, 25))) :: - InventoryItemData(ObjectClass.forceblade, PlanetSideGUID(80), 4, DetailedWeaponData(4, 8, ObjectClass.melee_ammo, PlanetSideGUID(81), 0, DetailedAmmoBoxData(8, 1))) :: - InventoryItemData(ObjectClass.locker_container, PlanetSideGUID(82), 5, DetailedLockerContainerData(8)) :: - InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(83), 6, DetailedAmmoBoxData(8, 50)) :: - InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(84), 9, DetailedAmmoBoxData(8, 50)) :: - InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(85), 12, DetailedAmmoBoxData(8, 50)) :: - InventoryItemData(ObjectClass.bullet_9mm_AP, PlanetSideGUID(86), 33, DetailedAmmoBoxData(8, 50)) :: - InventoryItemData(ObjectClass.energy_cell, PlanetSideGUID(87), 36, DetailedAmmoBoxData(8, 50)) :: - InventoryItemData(ObjectClass.remote_electronics_kit, PlanetSideGUID(88), 39, DetailedREKData(8)) :: - Nil - ) + val inv = InventoryData(List( + InventoryItemData(ObjectClass.beamer, PlanetSideGUID(76), 0, + DetailedWeaponData( + CommonFieldData(PlanetSideEmpire.VS, false, false, true, None, false, None, None, PlanetSideGUID(0)), + 0, + List(InternalSlot(ObjectClass.energy_cell, PlanetSideGUID(77), 0, DetailedAmmoBoxData(8, 16))) + ) + ), + InventoryItemData(ObjectClass.suppressor, PlanetSideGUID(78), 2, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.VS, false, false, true, None, false, None, None, PlanetSideGUID(0)), + 0, + List(InternalSlot(ObjectClass.bullet_9mm, PlanetSideGUID(79), 0, DetailedAmmoBoxData(8, 25))) + ) + ), + InventoryItemData(ObjectClass.forceblade, PlanetSideGUID(80), 4, + DetailedWeaponData( + CommonFieldData(PlanetSideEmpire.VS, false, false, true, None, false, None, None, PlanetSideGUID(0)), + 0, + List(InternalSlot(ObjectClass.melee_ammo, PlanetSideGUID(81), 0, DetailedAmmoBoxData(8, 1))) + ) + ), + InventoryItemData(ObjectClass.locker_container, PlanetSideGUID(82), 5, DetailedLockerContainerData(8)), + InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(83), 6, DetailedAmmoBoxData(8, 50)), + InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(84), 9, DetailedAmmoBoxData(8, 50)), + InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(85), 12, DetailedAmmoBoxData(8, 50)), + InventoryItemData(ObjectClass.bullet_9mm_AP, PlanetSideGUID(86), 33, DetailedAmmoBoxData(8, 50)), + InventoryItemData(ObjectClass.energy_cell, PlanetSideGUID(87), 36, DetailedAmmoBoxData(8, 50)), + InventoryItemData(ObjectClass.remote_electronics_kit, PlanetSideGUID(88), 39, DetailedREKData(CommonFieldData(PlanetSideEmpire.VS, false, false, true, None, false, Some(false), None, PlanetSideGUID(0)))) + )) val obj = DetailedPlayerData.apply(app, char, inv, DrawnSlot.Pistol1) //it shouldn't be Pistol1 if he's seated but it's fine for the test @@ -1481,15 +1584,18 @@ class DetailedCharacterDataTest extends Specification { CharacterGender.Male, 57, CharacterVoice.Voice1 + ),CommonFieldData( + PlanetSideEmpire.TR, + false, + false, + true, + None, + false, + None, + None, + PlanetSideGUID(0) ), - false, - false, - true, - None, - false, ExoSuitType.MAX, - None, - 0, 1, 41605870L, 0, @@ -1517,7 +1623,7 @@ class DetailedCharacterDataTest extends Specification { None ) - val app : (Int)=>CharacterAppearanceData = CharacterAppearanceData( + val app : Int=>CharacterAppearanceData = CharacterAppearanceData( aa, ab, RibbonBars() ) @@ -1601,24 +1707,34 @@ class DetailedCharacterDataTest extends Specification { Nil, Nil, false, None ) - val char : (Option[Int])=>DetailedCharacterData = + val char : Option[Int]=>DetailedCharacterData = (pad_length : Option[Int]) => DetailedCharacterData(ba, bb(ba.bep, pad_length))(pad_length) val inv = InventoryData( List( InternalSlot(889, PlanetSideGUID(2), 0, - DetailedWeaponData(0,8,0, List( - InternalSlot(265, PlanetSideGUID(3), 0, DetailedAmmoBoxData(8,200)), - InternalSlot(265, PlanetSideGUID(4), 1, DetailedAmmoBoxData(8,200)), - InternalSlot(265, PlanetSideGUID(5), 2, DetailedAmmoBoxData(8,200)) - )) + DetailedWeaponData( + CommonFieldData(PlanetSideEmpire.TR, false, false, true, None, false, None, None, PlanetSideGUID(0)), + 0, + List( + InternalSlot(265, PlanetSideGUID(3), 0, DetailedAmmoBoxData(8,200)), + InternalSlot(265, PlanetSideGUID(4), 1, DetailedAmmoBoxData(8,200)), + InternalSlot(265, PlanetSideGUID(5), 2, DetailedAmmoBoxData(8,200)) + ) + ) ), InternalSlot(175, PlanetSideGUID(6), 4, - DetailedWeaponData(0,8,0, List( - InternalSlot(540, PlanetSideGUID(7), 0, DetailedAmmoBoxData(8,1)) - )) + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.TR, false, false, true, None, false, None, None, PlanetSideGUID(0)), + 0, + List( + InternalSlot(540, PlanetSideGUID(7), 0, DetailedAmmoBoxData(8,1)) + ) + ) ), - InternalSlot(456, PlanetSideGUID(8), 5, DetailedLockerContainerData(8, None)), + InternalSlot(456, PlanetSideGUID(8), 5, DetailedLockerContainerData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), + None + )), InternalSlot(265, PlanetSideGUID(9), 6, DetailedAmmoBoxData(8, 36)), InternalSlot(265, PlanetSideGUID(10), 10, DetailedAmmoBoxData(8, 100)), InternalSlot(265, PlanetSideGUID(11), 14, DetailedAmmoBoxData(8, 100)), @@ -1644,7 +1760,7 @@ class DetailedCharacterDataTest extends Specification { pkt mustEqual string_max } - "encode (character, br32)" in { + "encode (BR32)" in { val pos : PlacementData = PlacementData( Vector3(5500.0f, 3800.0f, 71.484375f), Vector3(0, 0, 90.0f), @@ -1658,14 +1774,18 @@ class DetailedCharacterDataTest extends Specification { 24, CharacterVoice.Voice4 ), - false, - false, - true, - None, - false, + CommonFieldData( + PlanetSideEmpire.NC, + false, + false, + true, + None, + false, + None, + None, + PlanetSideGUID(0) + ), ExoSuitType.Agile, - None, - 0, 0, 733931L, 0, @@ -1693,7 +1813,7 @@ class DetailedCharacterDataTest extends Specification { None ) - val app : (Int)=>CharacterAppearanceData = CharacterAppearanceData( + val app : Int=>CharacterAppearanceData = CharacterAppearanceData( aa, ab, RibbonBars( MeritCommendation.Loser4, @@ -2050,190 +2170,195 @@ class DetailedCharacterDataTest extends Specification { Nil, Nil, false, Some(Cosmetics(true, true, true, true, false)) ) - val char : (Option[Int])=>DetailedCharacterData = + val char : Option[Int]=>DetailedCharacterData = (pad_length : Option[Int]) => DetailedCharacterData(ba, bb(ba.bep, pad_length))(pad_length) val inv = InventoryData( List( InternalSlot(531, PlanetSideGUID(4202), 0, - DetailedWeaponData(2, 8, 0, List(InternalSlot(389, PlanetSideGUID(3942), 0,DetailedAmmoBoxData(8, 100)))) + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NC, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(389, PlanetSideGUID(3942), 0,DetailedAmmoBoxData(8, 100)))) ), InternalSlot(132, PlanetSideGUID(6924), 1, - DetailedWeaponData(2, 8, 0, List(InternalSlot(111, PlanetSideGUID(9157), 0, DetailedAmmoBoxData(8, 100)))) + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NC, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(111, PlanetSideGUID(9157), 0, DetailedAmmoBoxData(8, 100)))) ), InternalSlot(714, PlanetSideGUID(8498), 2, - DetailedWeaponData(2, 8, 0, List(InternalSlot(755, PlanetSideGUID(5356), 0, DetailedAmmoBoxData(8, 16)))) + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NC, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(755, PlanetSideGUID(5356), 0, DetailedAmmoBoxData(8, 16)))) ), InternalSlot(468, PlanetSideGUID(7198), 4, - DetailedWeaponData(2, 8, 0, List(InternalSlot(540, PlanetSideGUID(5009), 0, DetailedAmmoBoxData(8, 1)))) + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NC, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(5009), 0, DetailedAmmoBoxData(8, 1)))) ), InternalSlot(456, PlanetSideGUID(5374), 5, - DetailedLockerContainerData(8, Some(InventoryData(List( - InternalSlot(429, PlanetSideGUID(3021), 0, - DetailedWeaponData(6, 8, 0, List(InternalSlot(272, PlanetSideGUID(8729), 0, DetailedAmmoBoxData(8, 0)))) - ), - InternalSlot(838, PlanetSideGUID(8467), 9, - DetailedWeaponData(6, 8, 0, List(InternalSlot(839, PlanetSideGUID(8603), 0, DetailedAmmoBoxData(8, 5)))) - ), - InternalSlot(272, PlanetSideGUID(3266), 18, DetailedAmmoBoxData(8, 27)), - InternalSlot(577, PlanetSideGUID(2934), 22, - DetailedWeaponData(6, 8, 0, List(InternalSlot(111, PlanetSideGUID(4682), 0, DetailedAmmoBoxData(8, 100)))) - ), - InternalSlot(839, PlanetSideGUID(3271), 90, DetailedAmmoBoxData(8, 15)), - InternalSlot(839, PlanetSideGUID(7174), 94, DetailedAmmoBoxData(8, 6)), - InternalSlot(429, PlanetSideGUID(6084), 98, - DetailedWeaponData(6, 8, 0, List(InternalSlot(272, PlanetSideGUID(5928), 0, DetailedAmmoBoxData(8, 35)))) - ), - InternalSlot(462, PlanetSideGUID(5000), 108, - DetailedWeaponData(6, 8, 0, List(InternalSlot(463, PlanetSideGUID(6277), 0, DetailedAmmoBoxData(8, 150)))) - ), - InternalSlot(429, PlanetSideGUID(4341), 189, - DetailedWeaponData(6, 8, 0, List(InternalSlot(272, PlanetSideGUID(7043), 0, DetailedAmmoBoxData(8, 35)))) - ), - InternalSlot(556, PlanetSideGUID(4168), 198, - DetailedWeaponData(6, 8, 0, List(InternalSlot(28, PlanetSideGUID(8937), 0, DetailedAmmoBoxData(8, 100)))) - ), - InternalSlot(272, PlanetSideGUID(3173), 207, DetailedAmmoBoxData(8, 50)), - InternalSlot(462, PlanetSideGUID(3221), 210, - DetailedWeaponData(6, 8, 0, List(InternalSlot(463, PlanetSideGUID(4031), 0, DetailedAmmoBoxData(8, 150)))) - ), - InternalSlot(556, PlanetSideGUID(6853), 280, - DetailedWeaponData(6, 8, 0, List(InternalSlot(29, PlanetSideGUID(8524), 0, DetailedAmmoBoxData(8, 67)))) - ), - InternalSlot(556, PlanetSideGUID(4569), 290, - DetailedWeaponData(6, 8, 0, List(InternalSlot(28, PlanetSideGUID(5584), 0, DetailedAmmoBoxData(8, 100)))) - ), - InternalSlot(462, PlanetSideGUID(9294), 300, - DetailedWeaponData(6, 8, 0, List(InternalSlot(463, PlanetSideGUID(3118), 0, DetailedAmmoBoxData(8, 150)))) - ), - InternalSlot(272, PlanetSideGUID(4759), 387, DetailedAmmoBoxData(8, 50)), - InternalSlot(462, PlanetSideGUID(7377), 390, - DetailedWeaponData(6, 8, 0, List(InternalSlot(463, PlanetSideGUID(8155), 0, DetailedAmmoBoxData(8, 150)))) - ), - InternalSlot(843, PlanetSideGUID(6709), 480, DetailedAmmoBoxData(8, 1)), - InternalSlot(843, PlanetSideGUID(5276), 484, DetailedAmmoBoxData(8, 1)), - InternalSlot(843, PlanetSideGUID(7769), 488, DetailedAmmoBoxData(8, 1)), - InternalSlot(844, PlanetSideGUID(5334), 492, DetailedAmmoBoxData(8, 1)), - InternalSlot(844, PlanetSideGUID(6219), 496, DetailedAmmoBoxData(8, 1)), - InternalSlot(842, PlanetSideGUID(7279), 500, DetailedAmmoBoxData(8, 1)), - InternalSlot(842, PlanetSideGUID(5415), 504, DetailedAmmoBoxData(8, 1)), - InternalSlot(175, PlanetSideGUID(5741), 540, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(5183), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(324, PlanetSideGUID(6208), 541, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(5029), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(324, PlanetSideGUID(8589), 542, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(9217), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(175, PlanetSideGUID(8901), 543, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(7633), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(175, PlanetSideGUID(8419), 544, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(6546), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(175, PlanetSideGUID(4715), 545, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(8453), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(324, PlanetSideGUID(3577), 546, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(9202), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(324, PlanetSideGUID(6003), 547, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(3260), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(324, PlanetSideGUID(9140), 548, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(3815),0,DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(324, PlanetSideGUID(4913), 549, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(7222),0,DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(324, PlanetSideGUID(6954), 550, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(2953),0,DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(324, PlanetSideGUID(6405), 551, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(4676),0,DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(324, PlanetSideGUID(8915), 552, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(4018),0,DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(324, PlanetSideGUID(4993), 553, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(6775),0,DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(175, PlanetSideGUID(5053), 554, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(6418),0,DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(324, PlanetSideGUID(9244), 555, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(3327),0,DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(468, PlanetSideGUID(6292), 556, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540,PlanetSideGUID(6918),0,DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(842, PlanetSideGUID(5357), 558, DetailedAmmoBoxData(8, 1)), - InternalSlot(844, PlanetSideGUID(4435), 562, DetailedAmmoBoxData(8, 1)), - InternalSlot(843, PlanetSideGUID(7242), 566, DetailedAmmoBoxData(8, 1)), - InternalSlot(175, PlanetSideGUID(7330), 570, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(4786), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(468, PlanetSideGUID(7415), 571, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(6536), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(175, PlanetSideGUID(3949), 572, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(7526), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(175, PlanetSideGUID(3805), 573, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(7358), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(324, PlanetSideGUID(4493), 574, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(6852), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(324, PlanetSideGUID(5762), 575, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(3463), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(175, PlanetSideGUID(3315), 576, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(7619), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(324, PlanetSideGUID(6263), 577, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(5912), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(468, PlanetSideGUID(4028), 578, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(8021), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(175, PlanetSideGUID(2843), 579, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(7250), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(175, PlanetSideGUID(9143), 580, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(5195), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(468, PlanetSideGUID(5024), 581, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(4287), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(468, PlanetSideGUID(6582), 582, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(4915), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(468, PlanetSideGUID(6425), 583, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(8872), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(468, PlanetSideGUID(4431), 584, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(4191), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(175, PlanetSideGUID(8339), 585, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(7317), 0, DetailedAmmoBoxData(8, 1)))) - ), - InternalSlot(175, PlanetSideGUID(3277), 586, - DetailedWeaponData(6, 8, 0, List(InternalSlot(540, PlanetSideGUID(6469), 0, DetailedAmmoBoxData(8, 1)))) + DetailedLockerContainerData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), + Some(InventoryData(List( + InternalSlot(429, PlanetSideGUID(3021), 0, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(272, PlanetSideGUID(8729), 0, DetailedAmmoBoxData(8, 0)))) + ), + InternalSlot(838, PlanetSideGUID(8467), 9, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(839, PlanetSideGUID(8603), 0, DetailedAmmoBoxData(8, 5)))) + ), + InternalSlot(272, PlanetSideGUID(3266), 18, DetailedAmmoBoxData(8, 27)), + InternalSlot(577, PlanetSideGUID(2934), 22, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(111, PlanetSideGUID(4682), 0, DetailedAmmoBoxData(8, 100)))) + ), + InternalSlot(839, PlanetSideGUID(3271), 90, DetailedAmmoBoxData(8, 15)), + InternalSlot(839, PlanetSideGUID(7174), 94, DetailedAmmoBoxData(8, 6)), + InternalSlot(429, PlanetSideGUID(6084), 98, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(272, PlanetSideGUID(5928), 0, DetailedAmmoBoxData(8, 35)))) + ), + InternalSlot(462, PlanetSideGUID(5000), 108, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(463, PlanetSideGUID(6277), 0, DetailedAmmoBoxData(8, 150)))) + ), + InternalSlot(429, PlanetSideGUID(4341), 189, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(272, PlanetSideGUID(7043), 0, DetailedAmmoBoxData(8, 35)))) + ), + InternalSlot(556, PlanetSideGUID(4168), 198, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(28, PlanetSideGUID(8937), 0, DetailedAmmoBoxData(8, 100)))) + ), + InternalSlot(272, PlanetSideGUID(3173), 207, DetailedAmmoBoxData(8, 50)), + InternalSlot(462, PlanetSideGUID(3221), 210, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(463, PlanetSideGUID(4031), 0, DetailedAmmoBoxData(8, 150)))) + ), + InternalSlot(556, PlanetSideGUID(6853), 280, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(29, PlanetSideGUID(8524), 0, DetailedAmmoBoxData(8, 67)))) + ), + InternalSlot(556, PlanetSideGUID(4569), 290, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(28, PlanetSideGUID(5584), 0, DetailedAmmoBoxData(8, 100)))) + ), + InternalSlot(462, PlanetSideGUID(9294), 300, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(463, PlanetSideGUID(3118), 0, DetailedAmmoBoxData(8, 150)))) + ), + InternalSlot(272, PlanetSideGUID(4759), 387, DetailedAmmoBoxData(8, 50)), + InternalSlot(462, PlanetSideGUID(7377), 390, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(463, PlanetSideGUID(8155), 0, DetailedAmmoBoxData(8, 150)))) + ), + InternalSlot(843, PlanetSideGUID(6709), 480, DetailedAmmoBoxData(8, 1)), + InternalSlot(843, PlanetSideGUID(5276), 484, DetailedAmmoBoxData(8, 1)), + InternalSlot(843, PlanetSideGUID(7769), 488, DetailedAmmoBoxData(8, 1)), + InternalSlot(844, PlanetSideGUID(5334), 492, DetailedAmmoBoxData(8, 1)), + InternalSlot(844, PlanetSideGUID(6219), 496, DetailedAmmoBoxData(8, 1)), + InternalSlot(842, PlanetSideGUID(7279), 500, DetailedAmmoBoxData(8, 1)), + InternalSlot(842, PlanetSideGUID(5415), 504, DetailedAmmoBoxData(8, 1)), + InternalSlot(175, PlanetSideGUID(5741), 540, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(5183), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(324, PlanetSideGUID(6208), 541, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(5029), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(324, PlanetSideGUID(8589), 542, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(9217), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(175, PlanetSideGUID(8901), 543, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(7633), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(175, PlanetSideGUID(8419), 544, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(6546), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(175, PlanetSideGUID(4715), 545, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(8453), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(324, PlanetSideGUID(3577), 546, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(9202), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(324, PlanetSideGUID(6003), 547, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(3260), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(324, PlanetSideGUID(9140), 548, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540,PlanetSideGUID(3815),0,DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(324, PlanetSideGUID(4913), 549, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540,PlanetSideGUID(7222),0,DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(324, PlanetSideGUID(6954), 550, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540,PlanetSideGUID(2953),0,DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(324, PlanetSideGUID(6405), 551, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540,PlanetSideGUID(4676),0,DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(324, PlanetSideGUID(8915), 552, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540,PlanetSideGUID(4018),0,DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(324, PlanetSideGUID(4993), 553, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540,PlanetSideGUID(6775),0,DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(175, PlanetSideGUID(5053), 554, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540,PlanetSideGUID(6418),0,DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(324, PlanetSideGUID(9244), 555, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540,PlanetSideGUID(3327),0,DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(468, PlanetSideGUID(6292), 556, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540,PlanetSideGUID(6918),0,DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(842, PlanetSideGUID(5357), 558, DetailedAmmoBoxData(8, 1)), + InternalSlot(844, PlanetSideGUID(4435), 562, DetailedAmmoBoxData(8, 1)), + InternalSlot(843, PlanetSideGUID(7242), 566, DetailedAmmoBoxData(8, 1)), + InternalSlot(175, PlanetSideGUID(7330), 570, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(4786), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(468, PlanetSideGUID(7415), 571, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(6536), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(175, PlanetSideGUID(3949), 572, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(7526), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(175, PlanetSideGUID(3805), 573, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(7358), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(324, PlanetSideGUID(4493), 574, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(6852), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(324, PlanetSideGUID(5762), 575, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(3463), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(175, PlanetSideGUID(3315), 576, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(7619), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(324, PlanetSideGUID(6263), 577, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(5912), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(468, PlanetSideGUID(4028), 578, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(8021), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(175, PlanetSideGUID(2843), 579, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(7250), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(175, PlanetSideGUID(9143), 580, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(5195), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(468, PlanetSideGUID(5024), 581, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(4287), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(468, PlanetSideGUID(6582), 582, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(4915), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(468, PlanetSideGUID(6425), 583, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(8872), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(468, PlanetSideGUID(4431), 584, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(4191), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(175, PlanetSideGUID(8339), 585, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(7317), 0, DetailedAmmoBoxData(8, 1)))) + ), + InternalSlot(175, PlanetSideGUID(3277), 586, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(6469), 0, DetailedAmmoBoxData(8, 1)))) + ) ) - )))) + ))) ), - InternalSlot(213, PlanetSideGUID(6877), 6, DetailedCommandDetonaterData(4, 8)), + InternalSlot(213, PlanetSideGUID(6877), 6, DetailedCommandDetonaterData(CommonFieldData(PlanetSideEmpire.NC, false, false, true, None, false, None, None, PlanetSideGUID(0)))), InternalSlot(755, PlanetSideGUID(6227), 9, DetailedAmmoBoxData(8, 16)), - InternalSlot(728, PlanetSideGUID(7181), 12, DetailedREKData(4, 16)), + InternalSlot(728, PlanetSideGUID(7181), 12, DetailedREKData(CommonFieldData(PlanetSideEmpire.NC, false, false, true, None, false, Some(false), None, PlanetSideGUID(0)), 16)), InternalSlot(536, PlanetSideGUID(4077), 33, DetailedAmmoBoxData(8, 1)), InternalSlot(680, PlanetSideGUID(4377), 37, - DetailedWeaponData(2, 8, 0, List(InternalSlot(681, PlanetSideGUID(8905), 0, DetailedAmmoBoxData(8, 3)))) + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NC, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(681, PlanetSideGUID(8905), 0, DetailedAmmoBoxData(8, 3)))) ), - InternalSlot(32, PlanetSideGUID(5523), 39, DetailedACEData(4)), + InternalSlot(32, PlanetSideGUID(5523), 39, DetailedConstructionToolData( + CommonFieldData(PlanetSideEmpire.NC, false, false, true, None, false, None, None, PlanetSideGUID(0)) + )), InternalSlot(673, PlanetSideGUID(3661), 60, - DetailedWeaponData(2, 8, 0, List(InternalSlot(674, PlanetSideGUID(8542), 0, DetailedAmmoBoxData(8, 3)))) + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NC, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(674, PlanetSideGUID(8542), 0, DetailedAmmoBoxData(8, 3)))) ) ) ) @@ -2258,14 +2383,18 @@ class DetailedCharacterDataTest extends Specification { 20, CharacterVoice.Voice3 ), - false, - false, - false, - None, - false, + CommonFieldData( + PlanetSideEmpire.NC, + false, + false, + false, + None, + false, + None, + None, + PlanetSideGUID(0) + ), ExoSuitType.Standard, - None, - 0, 0, 1176612L, 15, @@ -2293,7 +2422,7 @@ class DetailedCharacterDataTest extends Specification { None ) - val app : (Int)=>CharacterAppearanceData = CharacterAppearanceData( + val app : Int=>CharacterAppearanceData = CharacterAppearanceData( aa, ab, RibbonBars( MeritCommendation.DefenseNC5, @@ -2645,98 +2774,101 @@ class DetailedCharacterDataTest extends Specification { false, Some(Cosmetics(true, false, true, true, true)) ) - val char : (Option[Int])=>DetailedCharacterData = + val char : Option[Int]=>DetailedCharacterData = (pad_length : Option[Int]) => DetailedCharacterData(ba, bb(ba.bep, pad_length))(pad_length) val inv : InventoryData = InventoryData(List( InternalSlot(411, PlanetSideGUID(10022), 0, - DetailedWeaponData(2, 8, 0, List(InternalSlot(755, PlanetSideGUID(10023), 0, DetailedAmmoBoxData(8, 8)))) + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NC, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(755, PlanetSideGUID(10023), 0, DetailedAmmoBoxData(8, 8)))) ), InternalSlot(845, PlanetSideGUID(5671), 2, - DetailedWeaponData(2, 8, 0, List(InternalSlot(28, PlanetSideGUID(10019), 0, DetailedAmmoBoxData(8, 25)))) + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NC, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(28, PlanetSideGUID(10019), 0, DetailedAmmoBoxData(8, 25)))) ), InternalSlot(468, PlanetSideGUID(3754), 4, - DetailedWeaponData(2, 8, 0, List(InternalSlot(540, PlanetSideGUID(6693), 0, DetailedAmmoBoxData(8, 1)))) + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NC, false, false, true, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(540, PlanetSideGUID(6693), 0, DetailedAmmoBoxData(8, 1)))) ), InternalSlot(456, PlanetSideGUID(8199), 5, - DetailedLockerContainerData(0, Some(InventoryData(List( - InternalSlot(233, PlanetSideGUID(6315), 0, - DetailedWeaponData(6, 0, 0, List(InternalSlot(28, PlanetSideGUID(6795), 0, DetailedAmmoBoxData(0, 50)))) - ), - InternalSlot(233, PlanetSideGUID(4302), 6, - DetailedWeaponData(6, 0, 0, List(InternalSlot(28, PlanetSideGUID(5511), 0, DetailedAmmoBoxData(0, 50)))) - ), - InternalSlot(233, PlanetSideGUID(6342), 12, - DetailedWeaponData(6, 0, 0, List(InternalSlot(28, PlanetSideGUID(7788), 0, DetailedAmmoBoxData(0, 50)))) - ), - InternalSlot(233, PlanetSideGUID(7392), 18, - DetailedWeaponData(6, 0, 0, List(InternalSlot(28, PlanetSideGUID(8335), 0, DetailedAmmoBoxData(0, 50)))) - ), - InternalSlot(233, PlanetSideGUID(4432), 24, - DetailedWeaponData(6, 0, 0, List(InternalSlot(28, PlanetSideGUID(7020), 0, DetailedAmmoBoxData(0,50)))) - ), - InternalSlot(716, PlanetSideGUID(4219), 90, - DetailedWeaponData(6, 0, 0, List(InternalSlot(50, PlanetSideGUID(9275), 0, DetailedAmmoBoxData(0, 25)))) - ), - InternalSlot(716, PlanetSideGUID(3869), 96, - DetailedWeaponData(6, 0, 0, List(InternalSlot(50, PlanetSideGUID(6099), 0, DetailedAmmoBoxData(0, 25)))) - ), - InternalSlot(716, PlanetSideGUID(8954), 102, - DetailedWeaponData(6, 0, 0, List(InternalSlot(50, PlanetSideGUID(5972), 0, DetailedAmmoBoxData(0, 25)))) - ), - InternalSlot(233, PlanetSideGUID(7476), 108, - DetailedWeaponData(6, 0, 0, List(InternalSlot(28, PlanetSideGUID(5704), 0, DetailedAmmoBoxData(0, 50)))) - ), - InternalSlot(272, PlanetSideGUID(8800), 114, DetailedAmmoBoxData(0, 50)), - InternalSlot(272, PlanetSideGUID(8649), 177, DetailedAmmoBoxData(0, 50)), - InternalSlot(716, PlanetSideGUID(7580), 180, - DetailedWeaponData(6, 0, 0, List(InternalSlot(50, PlanetSideGUID(6734), 0, DetailedAmmoBoxData(0, 25)))) - ), - InternalSlot(716, PlanetSideGUID(6464), 186, - DetailedWeaponData(6, 0, 0, List(InternalSlot(50, PlanetSideGUID(4738), 0, DetailedAmmoBoxData(0, 25)))) - ), - InternalSlot(716, PlanetSideGUID(5408), 192, - DetailedWeaponData(6, 0, 0, List(InternalSlot(50, PlanetSideGUID(3579), 0, DetailedAmmoBoxData(0, 25)))) - ), - InternalSlot(556, PlanetSideGUID(8957), 198, - DetailedWeaponData(6, 0, 0, List(InternalSlot(28, PlanetSideGUID(8223), 0, DetailedAmmoBoxData(0, 100)))) - ), - InternalSlot(272, PlanetSideGUID(3928), 267, DetailedAmmoBoxData(0, 50)), - InternalSlot(577, PlanetSideGUID(3403), 279, - DetailedWeaponData(6, 0, 0, List(InternalSlot(111, PlanetSideGUID(4352), 0, DetailedAmmoBoxData(0, 100)))) - ), - InternalSlot(577, PlanetSideGUID(8454), 285, - DetailedWeaponData(6, 0, 0, List(InternalSlot(111, PlanetSideGUID(8724), 0, DetailedAmmoBoxData(0,100)))) - ), - InternalSlot(272, PlanetSideGUID(3397), 357, DetailedAmmoBoxData(0, 50)), - InternalSlot(429, PlanetSideGUID(6695), 378, - DetailedWeaponData(6, 0, 0, List(InternalSlot(272, PlanetSideGUID(6842), 0, DetailedAmmoBoxData(0, 35)))) - ), - InternalSlot(462, PlanetSideGUID(8304), 420, - DetailedWeaponData(6, 0, 0, List(InternalSlot(463, PlanetSideGUID(7089), 0, DetailedAmmoBoxData(0, 150)))) - ), - InternalSlot(462, PlanetSideGUID(3346), 429, - DetailedWeaponData(6, 0, 0, List(InternalSlot(463, PlanetSideGUID(7557), 0, DetailedAmmoBoxData(0, 150)))) - ), - InternalSlot(272, PlanetSideGUID(7515), 447, DetailedAmmoBoxData(0, 50)), - InternalSlot(462, PlanetSideGUID(4622), 510, - DetailedWeaponData(6, 0, 0, List(InternalSlot(463, PlanetSideGUID(6996), 0, DetailedAmmoBoxData(0, 150)))) - ), - InternalSlot(462, PlanetSideGUID(6586), 519, - DetailedWeaponData(6, 0, 0, List(InternalSlot(463, PlanetSideGUID(6870), 0, DetailedAmmoBoxData(0, 150)))) - ), - InternalSlot(556, PlanetSideGUID(4806), 528, - DetailedWeaponData(6, 0, 0, List(InternalSlot(28, PlanetSideGUID(8798), 0, DetailedAmmoBoxData(0, 100)))) - ), - InternalSlot(272, PlanetSideGUID(8429), 537, DetailedAmmoBoxData(0, 50)) - )))) + DetailedLockerContainerData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)), + Some(InventoryData(List( + InternalSlot(233, PlanetSideGUID(6315), 0, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(28, PlanetSideGUID(6795), 0, DetailedAmmoBoxData(0, 50)))) + ), + InternalSlot(233, PlanetSideGUID(4302), 6, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(28, PlanetSideGUID(5511), 0, DetailedAmmoBoxData(0, 50)))) + ), + InternalSlot(233, PlanetSideGUID(6342), 12, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(28, PlanetSideGUID(7788), 0, DetailedAmmoBoxData(0, 50)))) + ), + InternalSlot(233, PlanetSideGUID(7392), 18, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(28, PlanetSideGUID(8335), 0, DetailedAmmoBoxData(0, 50)))) + ), + InternalSlot(233, PlanetSideGUID(4432), 24, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(28, PlanetSideGUID(7020), 0, DetailedAmmoBoxData(0,50)))) + ), + InternalSlot(716, PlanetSideGUID(4219), 90, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(50, PlanetSideGUID(9275), 0, DetailedAmmoBoxData(0, 25)))) + ), + InternalSlot(716, PlanetSideGUID(3869), 96, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(50, PlanetSideGUID(6099), 0, DetailedAmmoBoxData(0, 25)))) + ), + InternalSlot(716, PlanetSideGUID(8954), 102, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(50, PlanetSideGUID(5972), 0, DetailedAmmoBoxData(0, 25)))) + ), + InternalSlot(233, PlanetSideGUID(7476), 108, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(28, PlanetSideGUID(5704), 0, DetailedAmmoBoxData(0, 50)))) + ), + InternalSlot(272, PlanetSideGUID(8800), 114, DetailedAmmoBoxData(0, 50)), + InternalSlot(272, PlanetSideGUID(8649), 177, DetailedAmmoBoxData(0, 50)), + InternalSlot(716, PlanetSideGUID(7580), 180, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(50, PlanetSideGUID(6734), 0, DetailedAmmoBoxData(0, 25)))) + ), + InternalSlot(716, PlanetSideGUID(6464), 186, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(50, PlanetSideGUID(4738), 0, DetailedAmmoBoxData(0, 25)))) + ), + InternalSlot(716, PlanetSideGUID(5408), 192, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(50, PlanetSideGUID(3579), 0, DetailedAmmoBoxData(0, 25)))) + ), + InternalSlot(556, PlanetSideGUID(8957), 198, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(28, PlanetSideGUID(8223), 0, DetailedAmmoBoxData(0, 100)))) + ), + InternalSlot(272, PlanetSideGUID(3928), 267, DetailedAmmoBoxData(0, 50)), + InternalSlot(577, PlanetSideGUID(3403), 279, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(111, PlanetSideGUID(4352), 0, DetailedAmmoBoxData(0, 100)))) + ), + InternalSlot(577, PlanetSideGUID(8454), 285, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(111, PlanetSideGUID(8724), 0, DetailedAmmoBoxData(0,100)))) + ), + InternalSlot(272, PlanetSideGUID(3397), 357, DetailedAmmoBoxData(0, 50)), + InternalSlot(429, PlanetSideGUID(6695), 378, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(272, PlanetSideGUID(6842), 0, DetailedAmmoBoxData(0, 35)))) + ), + InternalSlot(462, PlanetSideGUID(8304), 420, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(463, PlanetSideGUID(7089), 0, DetailedAmmoBoxData(0, 150)))) + ), + InternalSlot(462, PlanetSideGUID(3346), 429, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(463, PlanetSideGUID(7557), 0, DetailedAmmoBoxData(0, 150)))) + ), + InternalSlot(272, PlanetSideGUID(7515), 447, DetailedAmmoBoxData(0, 50)), + InternalSlot(462, PlanetSideGUID(4622), 510, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(463, PlanetSideGUID(6996), 0, DetailedAmmoBoxData(0, 150)))) + ), + InternalSlot(462, PlanetSideGUID(6586), 519, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(463, PlanetSideGUID(6870), 0, DetailedAmmoBoxData(0, 150)))) + ), + InternalSlot(556, PlanetSideGUID(4806), 528, + DetailedWeaponData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)), 0, List(InternalSlot(28, PlanetSideGUID(8798), 0, DetailedAmmoBoxData(0, 100)))) + ), + InternalSlot(272, PlanetSideGUID(8429), 537, DetailedAmmoBoxData(0, 50)) + )) + )) ), InternalSlot(28, PlanetSideGUID(10018), 6, DetailedAmmoBoxData(8, 50)), InternalSlot(28, PlanetSideGUID(5612), 9, DetailedAmmoBoxData(8, 50)), InternalSlot(28, PlanetSideGUID(5128), 12, DetailedAmmoBoxData(8, 50)), InternalSlot(29, PlanetSideGUID(8363), 33, DetailedAmmoBoxData(8, 50)), InternalSlot(755, PlanetSideGUID(4090), 36, DetailedAmmoBoxData(8, 16)), - InternalSlot(728, PlanetSideGUID(10075), 39, DetailedREKData(4, 24)) + InternalSlot(728, PlanetSideGUID(10075), 39, DetailedREKData(CommonFieldData(PlanetSideEmpire.NC, false, false, true, None, false, Some(false), None, PlanetSideGUID(0)), 24)) )) val obj = DetailedPlayerData.apply(pos, app, char, inv, DrawnSlot.None) diff --git a/common/src/test/scala/game/objectcreatedetailed/DetailedCommandDetonaterDataTest.scala b/common/src/test/scala/game/objectcreatedetailed/DetailedCommandDetonaterDataTest.scala index b1cebb95..f2abe55e 100644 --- a/common/src/test/scala/game/objectcreatedetailed/DetailedCommandDetonaterDataTest.scala +++ b/common/src/test/scala/game/objectcreatedetailed/DetailedCommandDetonaterDataTest.scala @@ -5,6 +5,7 @@ import org.specs2.mutable._ import net.psforever.packet._ import net.psforever.packet.game.{ObjectCreateDetailedMessage, _} import net.psforever.packet.game.objectcreate._ +import net.psforever.types.PlanetSideEmpire import scodec.bits._ class DetailedCommandDetonaterDataTest extends Specification { @@ -20,15 +21,29 @@ class DetailedCommandDetonaterDataTest extends Specification { parent.isDefined mustEqual true parent.get.guid mustEqual PlanetSideGUID(3530) parent.get.slot mustEqual 0 - data.isDefined mustEqual true - data.get.isInstanceOf[DetailedCommandDetonaterData] mustEqual true + data match { + case DetailedCommandDetonaterData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid)) => + faction mustEqual PlanetSideEmpire.VS + bops mustEqual false + alternate mustEqual false + v1 mustEqual false + v2.isEmpty mustEqual true + v3 mustEqual false + v4.isEmpty mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + + data.isInstanceOf[DetailedCommandDetonaterData] mustEqual true case _ => ko } } "encode" in { - val obj = DetailedCommandDetonaterData() + val obj = DetailedCommandDetonaterData(CommonFieldData(PlanetSideEmpire.VS, false, false, false, None, false, None, None, PlanetSideGUID(0))) val msg = ObjectCreateDetailedMessage(ObjectClass.command_detonater, PlanetSideGUID(8308), ObjectCreateMessageParent(PlanetSideGUID(3530), 0), obj) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector pkt mustEqual string_detonater diff --git a/common/src/test/scala/game/objectcreatedetailed/DetailedConstructionToolDataTest.scala b/common/src/test/scala/game/objectcreatedetailed/DetailedConstructionToolDataTest.scala new file mode 100644 index 00000000..13ebb06f --- /dev/null +++ b/common/src/test/scala/game/objectcreatedetailed/DetailedConstructionToolDataTest.scala @@ -0,0 +1,172 @@ +// Copyright (c) 2019 PSForever +package game.objectcreatedetailed + +import net.psforever.packet._ +import net.psforever.packet.game._ +import net.psforever.packet.game.objectcreate._ +import net.psforever.types.PlanetSideEmpire +import org.specs2.mutable._ +import scodec.bits._ + +class DetailedConstructionToolDataTest extends Specification { + val string_ace = hex"18 87000000 1006 100 C70B 80 8800000200008" + val string_boomer_trigger = hex"18 87000000 6304CA8760B 80 C800000200008" + val string_telepad = hex"18 97000000 4f00 f3a e301 80 4a680400000200008" + val string_telepad_short = hex"18 87000000 2a00 f3a 5d01 89 8000000200008" + + "ACE (detailed)" should { + "decode" in { + PacketCoding.DecodePacket(string_ace).require match { + case ObjectCreateDetailedMessage(len, cls, guid, parent, data) => + len mustEqual 135 + cls mustEqual ObjectClass.ace + guid mustEqual PlanetSideGUID(3015) + parent.isDefined mustEqual true + parent.get.guid mustEqual PlanetSideGUID(3104) + parent.get.slot mustEqual 0 + data match { + case DetailedConstructionToolData(cdata) => + cdata.faction mustEqual PlanetSideEmpire.VS + cdata.bops mustEqual false + cdata.alternate mustEqual false + cdata.v1 mustEqual true + cdata.v2.isEmpty mustEqual true + cdata.v3 mustEqual false + cdata.v4.isEmpty mustEqual true + cdata.v5.isEmpty mustEqual true + cdata.guid mustEqual PlanetSideGUID(0) + case _ => + ko + } + case _ => + ko + } + } + + "encode" in { + val obj = DetailedConstructionToolData( + CommonFieldData(PlanetSideEmpire.VS, false, false, true, None, false, None, None, PlanetSideGUID(0)) + ) + val msg = ObjectCreateDetailedMessage(ObjectClass.ace, PlanetSideGUID(3015), ObjectCreateMessageParent(PlanetSideGUID(3104), 0), obj) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_ace + } + } + + "Boomer Trigger (detailed)" should { + "decode" in { + PacketCoding.DecodePacket(string_boomer_trigger).require match { + case ObjectCreateDetailedMessage(len, cls, guid, parent, data) => + len mustEqual 135 + cls mustEqual ObjectClass.boomer_trigger + guid mustEqual PlanetSideGUID(2934) + parent.isDefined mustEqual true + parent.get.guid mustEqual PlanetSideGUID(2502) + parent.get.slot mustEqual 0 + data match { + case DetailedConstructionToolData(cdata) => + cdata.faction mustEqual PlanetSideEmpire.NEUTRAL + cdata.bops mustEqual false + cdata.alternate mustEqual false + cdata.v1 mustEqual true + cdata.v2.isEmpty mustEqual true + cdata.v3 mustEqual false + cdata.v4.isEmpty mustEqual true + cdata.v5.isEmpty mustEqual true + cdata.guid mustEqual PlanetSideGUID(0) + case _ => + ko + } + case _ => + ko + } + } + + "encode" in { + val obj = DetailedConstructionToolData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)) + ) + val msg = ObjectCreateDetailedMessage(ObjectClass.boomer_trigger, PlanetSideGUID(2934), ObjectCreateMessageParent(PlanetSideGUID(2502), 0), obj) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_boomer_trigger + } + } + + "Telepad (detailed)" should { + "decode" in { + PacketCoding.DecodePacket(string_telepad).require match { + case ObjectCreateDetailedMessage(len, cls, guid, parent, data) => + len mustEqual 151 + cls mustEqual ObjectClass.router_telepad + guid mustEqual PlanetSideGUID(483) + parent.isDefined mustEqual true + parent.get.guid mustEqual PlanetSideGUID(414) + parent.get.slot mustEqual 0 + data match { + case DetailedConstructionToolData(cdata) => + cdata.faction mustEqual PlanetSideEmpire.NC + cdata.bops mustEqual false + cdata.alternate mustEqual false + cdata.v1 mustEqual true + cdata.v2.isEmpty mustEqual true + cdata.v3 mustEqual false + cdata.v4.isEmpty mustEqual true + cdata.v5.contains(564) mustEqual true + cdata.guid mustEqual PlanetSideGUID(0) + case _ => + ko + } + case _ => + ko + } + } + + "decode (short)" in { + PacketCoding.DecodePacket(string_telepad_short).require match { + case ObjectCreateDetailedMessage(len, cls, guid, parent, data) => + len mustEqual 135 + cls mustEqual ObjectClass.router_telepad + guid mustEqual PlanetSideGUID(349) + parent.isDefined mustEqual true + parent.get.guid mustEqual PlanetSideGUID(340) + parent.get.slot mustEqual 9 + data match { + case DetailedConstructionToolData(cdata) => + cdata.faction mustEqual PlanetSideEmpire.VS + cdata.bops mustEqual false + cdata.alternate mustEqual false + cdata.v1 mustEqual false + cdata.v2.isEmpty mustEqual true + cdata.v3 mustEqual false + cdata.v4.isEmpty mustEqual true + cdata.v5.isEmpty mustEqual true + cdata.guid mustEqual PlanetSideGUID(0) + case _ => + ko + } + case _ => + ko + } + } + + "encode" in { + val obj = DetailedConstructionToolData( + CommonFieldData(PlanetSideEmpire.NC, false, false, true, None, false, None, Some(564), PlanetSideGUID(0)) + ) + val msg = ObjectCreateDetailedMessage(ObjectClass.router_telepad, PlanetSideGUID(483), ObjectCreateMessageParent(PlanetSideGUID(414), 0), obj) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_telepad + } + + "encode (short)" in { + val obj = DetailedConstructionToolData(CommonFieldData(PlanetSideEmpire.VS)) + val msg = ObjectCreateDetailedMessage(ObjectClass.router_telepad, PlanetSideGUID(349), ObjectCreateMessageParent(PlanetSideGUID(340), 9), obj) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_telepad_short + } + } +} diff --git a/common/src/test/scala/game/objectcreatedetailed/DetailedREKDataTest.scala b/common/src/test/scala/game/objectcreatedetailed/DetailedREKDataTest.scala index 5b1ead2d..1ee0b18b 100644 --- a/common/src/test/scala/game/objectcreatedetailed/DetailedREKDataTest.scala +++ b/common/src/test/scala/game/objectcreatedetailed/DetailedREKDataTest.scala @@ -5,6 +5,7 @@ import org.specs2.mutable._ import net.psforever.packet._ import net.psforever.packet.game.{ObjectCreateDetailedMessage, _} import net.psforever.packet.game.objectcreate._ +import net.psforever.types.PlanetSideEmpire import scodec.bits._ class DetailedREKDataTest extends Specification { @@ -20,16 +21,28 @@ class DetailedREKDataTest extends Specification { parent.isDefined mustEqual true parent.get.guid mustEqual PlanetSideGUID(75) parent.get.slot mustEqual 1 - data.isDefined mustEqual true - data.get.asInstanceOf[DetailedREKData].unk1 mustEqual 4 - data.get.asInstanceOf[DetailedREKData].unk2 mustEqual 0 + data match { + case DetailedREKData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid), unk) => + faction mustEqual PlanetSideEmpire.NC + bops mustEqual false + alternate mustEqual false + v1 mustEqual true + v2.isEmpty mustEqual true + v3 mustEqual false + v4.contains(false) mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + unk mustEqual 0 + case _ => + ko + } case _ => ko } } "encode" in { - val obj = DetailedREKData(4) + val obj = DetailedREKData(CommonFieldData(PlanetSideEmpire.NC, false, false, true, None, false, Some(false), None, PlanetSideGUID(0))) val msg = ObjectCreateDetailedMessage(ObjectClass.remote_electronics_kit, PlanetSideGUID(1439), ObjectCreateMessageParent(PlanetSideGUID(75), 1), obj) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector diff --git a/common/src/test/scala/game/objectcreatedetailed/DetailedTelepadDataTest.scala b/common/src/test/scala/game/objectcreatedetailed/DetailedTelepadDataTest.scala deleted file mode 100644 index 5145b00e..00000000 --- a/common/src/test/scala/game/objectcreatedetailed/DetailedTelepadDataTest.scala +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2017 PSForever -package game.objectcreatedetailed - -import net.psforever.packet._ -import net.psforever.packet.game._ -import net.psforever.packet.game.objectcreate._ -import org.specs2.mutable._ -import scodec.bits._ - -class DetailedTelepadDataTest extends Specification { - val string = hex"18 97000000 4f00 f3a e301 80 4a680400000200008" - val string_short = hex"18 87000000 2a00 f3a 5d01 89 8000000200008" - //TODO validate the unknown fields before router_guid for testing - - "DetailedTelepadData" should { - "decode" in { - PacketCoding.DecodePacket(string).require match { - case ObjectCreateDetailedMessage(len, cls, guid, parent, data) => - len mustEqual 151 - cls mustEqual ObjectClass.router_telepad - guid mustEqual PlanetSideGUID(483) - parent.isDefined mustEqual true - parent.get.guid mustEqual PlanetSideGUID(414) - parent.get.slot mustEqual 0 - data.isDefined mustEqual true - data.get.isInstanceOf[DetailedTelepadData] mustEqual true - data.get.asInstanceOf[DetailedTelepadData].router_guid mustEqual Some(PlanetSideGUID(564)) - case _ => - ko - } - } - - "decode (short)" in { - PacketCoding.DecodePacket(string_short).require match { - case ObjectCreateDetailedMessage(len, cls, guid, parent, data) => - len mustEqual 135 - cls mustEqual ObjectClass.router_telepad - guid mustEqual PlanetSideGUID(349) - parent.isDefined mustEqual true - parent.get.guid mustEqual PlanetSideGUID(340) - parent.get.slot mustEqual 9 - data.isDefined mustEqual true - data.get.isInstanceOf[DetailedTelepadData] mustEqual true - data.get.asInstanceOf[DetailedTelepadData].router_guid mustEqual None - case _ => - ko - } - } - - "encode" in { - val obj = DetailedTelepadData(18, PlanetSideGUID(564)) - val msg = ObjectCreateDetailedMessage(ObjectClass.router_telepad, PlanetSideGUID(483), ObjectCreateMessageParent(PlanetSideGUID(414), 0), obj) - val pkt = PacketCoding.EncodePacket(msg).require.toByteVector - - pkt mustEqual string - } - - "encode (short)" in { - val obj = DetailedTelepadData(32) - val msg = ObjectCreateDetailedMessage(ObjectClass.router_telepad, PlanetSideGUID(349), ObjectCreateMessageParent(PlanetSideGUID(340), 9), obj) - val pkt = PacketCoding.EncodePacket(msg).require.toByteVector - - pkt mustEqual string_short - } - } -} diff --git a/common/src/test/scala/game/objectcreatedetailed/DetailedWeaponDataTest.scala b/common/src/test/scala/game/objectcreatedetailed/DetailedWeaponDataTest.scala index 05cb8fd5..9ad972ed 100644 --- a/common/src/test/scala/game/objectcreatedetailed/DetailedWeaponDataTest.scala +++ b/common/src/test/scala/game/objectcreatedetailed/DetailedWeaponDataTest.scala @@ -5,6 +5,7 @@ import org.specs2.mutable._ import net.psforever.packet._ import net.psforever.packet.game.{ObjectCreateDetailedMessage, _} import net.psforever.packet.game.objectcreate._ +import net.psforever.types.PlanetSideEmpire import scodec.bits._ class DetailedWeaponDataTest extends Specification { @@ -21,15 +22,33 @@ class DetailedWeaponDataTest extends Specification { parent.isDefined mustEqual true parent.get.guid mustEqual PlanetSideGUID(75) parent.get.slot mustEqual 2 - data.isDefined mustEqual true - val obj_wep = data.get.asInstanceOf[DetailedWeaponData] - obj_wep.unk1 mustEqual 2 - obj_wep.unk2 mustEqual 8 - val obj_ammo = obj_wep.ammo - obj_ammo.head.objectClass mustEqual 28 - obj_ammo.head.guid mustEqual PlanetSideGUID(1286) - obj_ammo.head.parentSlot mustEqual 0 - obj_ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 30 + data match { + case DetailedWeaponData(cdata, fmode, ammo, _) => + cdata match { + case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid) => + faction mustEqual PlanetSideEmpire.NC + bops mustEqual false + alternate mustEqual false + v1 mustEqual true + v2.isEmpty mustEqual true + v3 mustEqual false + v4.isEmpty mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + + fmode mustEqual 0 + + ammo.size mustEqual 1 + ammo.head.objectClass mustEqual 28 + ammo.head.guid mustEqual PlanetSideGUID(1286) + ammo.head.parentSlot mustEqual 0 + ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 30 + case _ => + ko + } case _ => ko } @@ -44,27 +63,48 @@ class DetailedWeaponDataTest extends Specification { parent.isDefined mustEqual true parent.get.guid mustEqual PlanetSideGUID(75) parent.get.slot mustEqual 2 - data.isDefined mustEqual true - val obj_wep = data.get.asInstanceOf[DetailedWeaponData] - obj_wep.unk1 mustEqual 0 - obj_wep.unk2 mustEqual 8 - val obj_ammo = obj_wep.ammo - obj_ammo.size mustEqual 2 - obj_ammo.head.objectClass mustEqual ObjectClass.bullet_9mm - obj_ammo.head.guid mustEqual PlanetSideGUID(1693) - obj_ammo.head.parentSlot mustEqual 0 - obj_ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 30 - obj_ammo(1).objectClass mustEqual ObjectClass.jammer_cartridge - obj_ammo(1).guid mustEqual PlanetSideGUID(1564) - obj_ammo(1).parentSlot mustEqual 1 - obj_ammo(1).obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 1 + data match { + case DetailedWeaponData(cdata, fmode, ammo, _) => + cdata match { + case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid) => + faction mustEqual PlanetSideEmpire.TR + bops mustEqual false + alternate mustEqual false + v1 mustEqual true + v2.isEmpty mustEqual true + v3 mustEqual false + v4.isEmpty mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + + fmode mustEqual 0 + + ammo.size mustEqual 2 + ammo.head.objectClass mustEqual ObjectClass.bullet_9mm + ammo.head.guid mustEqual PlanetSideGUID(1693) + ammo.head.parentSlot mustEqual 0 + ammo.head.obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 30 + ammo(1).objectClass mustEqual ObjectClass.jammer_cartridge + ammo(1).guid mustEqual PlanetSideGUID(1564) + ammo(1).parentSlot mustEqual 1 + ammo(1).obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 1 + case _ => + ko + } case _ => ko } } "encode (gauss)" in { - val obj = DetailedWeaponData(2, 8, ObjectClass.bullet_9mm, PlanetSideGUID(1286), 0, DetailedAmmoBoxData(8, 30)) + val obj = DetailedWeaponData( + CommonFieldData(PlanetSideEmpire.NC, false, false, true, None, false, None, None, PlanetSideGUID(0)), + 0, + List(InternalSlot(ObjectClass.bullet_9mm, PlanetSideGUID(1286), 0, DetailedAmmoBoxData(8, 30))) + ) val msg = ObjectCreateDetailedMessage(ObjectClass.gauss, PlanetSideGUID(1465), ObjectCreateMessageParent(PlanetSideGUID(75), 2), obj) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector @@ -72,11 +112,24 @@ class DetailedWeaponDataTest extends Specification { } "encode (punisher)" in { - val obj = DetailedWeaponData(0, 8, 0, - DetailedAmmoBoxData(ObjectClass.bullet_9mm, PlanetSideGUID(1693), 0, DetailedAmmoBoxData(8, 30)) :: - DetailedAmmoBoxData(ObjectClass.jammer_cartridge, PlanetSideGUID(1564), 1, DetailedAmmoBoxData(8, 1)) :: - Nil - )(2) + val obj = DetailedWeaponData( + CommonFieldData( + PlanetSideEmpire.TR, + bops = false, + alternate = false, + true, + None, + false, + None, + None, + PlanetSideGUID(0) + ), + 0, + List( + DetailedAmmoBoxData(ObjectClass.bullet_9mm, PlanetSideGUID(1693), 0, DetailedAmmoBoxData(8, 30)), + DetailedAmmoBoxData(ObjectClass.jammer_cartridge, PlanetSideGUID(1564), 1, DetailedAmmoBoxData(8, 1)) + ) + ) val msg = ObjectCreateDetailedMessage(ObjectClass.punisher, PlanetSideGUID(1703), ObjectCreateMessageParent(PlanetSideGUID(75), 2), obj) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector diff --git a/common/src/test/scala/game/objectcreatevehicle/DestroyedVehiclesTest.scala b/common/src/test/scala/game/objectcreatevehicle/DestroyedVehiclesTest.scala index 84b243c7..cc7a0055 100644 --- a/common/src/test/scala/game/objectcreatevehicle/DestroyedVehiclesTest.scala +++ b/common/src/test/scala/game/objectcreatevehicle/DestroyedVehiclesTest.scala @@ -2,8 +2,8 @@ package game.objectcreatevehicle import net.psforever.packet._ -import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} import net.psforever.packet.game.objectcreate._ +import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} import org.specs2.mutable._ import scodec.bits._ @@ -18,9 +18,8 @@ class DestroyedVehiclesTest extends Specification { cls mustEqual ObjectClass.ams_destroyed guid mustEqual PlanetSideGUID(4157) parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[DestroyedVehicleData] mustEqual true - val dams = data.get.asInstanceOf[DestroyedVehicleData] + data.isInstanceOf[DestroyedVehicleData] mustEqual true + val dams = data.asInstanceOf[DestroyedVehicleData] dams.pos.coord.x mustEqual 3674.0f dams.pos.coord.y mustEqual 2726.789f dams.pos.coord.z mustEqual 91.15625f diff --git a/common/src/test/scala/game/objectcreatevehicle/MountedVehiclesTest.scala b/common/src/test/scala/game/objectcreatevehicle/MountedVehiclesTest.scala index cbeccc0c..5b73667f 100644 --- a/common/src/test/scala/game/objectcreatevehicle/MountedVehiclesTest.scala +++ b/common/src/test/scala/game/objectcreatevehicle/MountedVehiclesTest.scala @@ -2,8 +2,8 @@ package game.objectcreatevehicle import net.psforever.packet._ -import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} import net.psforever.packet.game.objectcreate._ +import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} import net.psforever.types._ import org.specs2.mutable._ import scodec.bits._ @@ -22,28 +22,28 @@ class MountedVehiclesTest extends Specification { len mustEqual 1991 cls mustEqual ObjectClass.mosquito guid mustEqual PlanetSideGUID(4308) - parent mustEqual None + parent.isEmpty mustEqual true data match { - case Some(vdata : VehicleData) => + case vdata : VehicleData => vdata.pos.coord mustEqual Vector3(4571.6875f, 5602.1875f, 93) vdata.pos.orient mustEqual Vector3(11.25f, 2.8125f, 92.8125f) - vdata.pos.vel mustEqual Some(Vector3(31.71875f, 8.875f, -0.03125f)) - vdata.faction mustEqual PlanetSideEmpire.TR - vdata.bops mustEqual false - vdata.destroyed mustEqual false - vdata.jammered mustEqual false - vdata.owner_guid mustEqual PlanetSideGUID(3776) + vdata.pos.vel.contains(Vector3(31.71875f, 8.875f, -0.03125f)) mustEqual true + vdata.data.faction mustEqual PlanetSideEmpire.TR + vdata.data.bops mustEqual false + vdata.data.alternate mustEqual false + vdata.data.v1 mustEqual false + vdata.data.v3 mustEqual false + vdata.data.v5.isEmpty mustEqual true + vdata.data.guid mustEqual PlanetSideGUID(3776) vdata.health mustEqual 255 vdata.no_mount_points mustEqual false vdata.driveState mustEqual DriveState.Mobile vdata.cloak mustEqual false - vdata.unk1 mustEqual 0 - vdata.unk2 mustEqual false vdata.unk3 mustEqual false vdata.unk4 mustEqual false vdata.unk5 mustEqual false vdata.unk6 mustEqual false - vdata.vehicle_format_data mustEqual Some(VariantVehicleData(7)) + vdata.vehicle_format_data.contains(VariantVehicleData(7)) mustEqual true vdata.inventory match { case Some(InventoryData(list)) => list.head.objectClass mustEqual ObjectClass.avatar @@ -54,13 +54,13 @@ class MountedVehiclesTest extends Specification { app match { case CharacterAppearanceData(a, b, ribbons) => a.app mustEqual BasicCharacterData("ScrawnyRonnie", PlanetSideEmpire.TR, CharacterGender.Male, 5, CharacterVoice.Voice5) - a.black_ops mustEqual false - a.jammered mustEqual false + a.data.bops mustEqual false + a.data.v1 mustEqual false + a.data.v2.isEmpty mustEqual true + a.data.v3 mustEqual false + a.data.v4.isEmpty mustEqual true + a.data.v5.isEmpty mustEqual true a.exosuit mustEqual ExoSuitType.Agile - a.unk1 mustEqual false - a.unk2 mustEqual None - a.unk3 mustEqual None - a.unk4 mustEqual 0 a.unk5 mustEqual 0 a.unk6 mustEqual 30777081L a.unk7 mustEqual 1 @@ -77,7 +77,7 @@ class MountedVehiclesTest extends Specification { b.grenade_state mustEqual GrenadeState.None b.is_cloaking mustEqual false b.charging_pose mustEqual false - b.on_zipline mustEqual None + b.on_zipline.isEmpty mustEqual true b.unk0 mustEqual 316554L b.unk1 mustEqual false b.unk2 mustEqual false @@ -99,7 +99,7 @@ class MountedVehiclesTest extends Specification { unk mustEqual 7 cr mustEqual 5 implants mustEqual Nil - cosmetics mustEqual Some(Cosmetics(true, true, true, true, false)) + cosmetics.contains(Cosmetics(true, true, true, true, false)) mustEqual true case _ => ko } @@ -139,14 +139,18 @@ class MountedVehiclesTest extends Specification { 5, CharacterVoice.Voice5 ), - false, - false, - false, - None, - false, + CommonFieldData( + PlanetSideEmpire.TR, + false, + false, + false, + None, + false, + None, + None, + PlanetSideGUID(0) + ), ExoSuitType.Agile, - None, - 0, 0, 30777081L, 1, @@ -174,7 +178,7 @@ class MountedVehiclesTest extends Specification { None ) - val app : (Int)=>CharacterAppearanceData = CharacterAppearanceData( + val app : Int=>CharacterAppearanceData = CharacterAppearanceData( a, b, RibbonBars( MeritCommendation.MarkovVeteran, @@ -194,16 +198,16 @@ class MountedVehiclesTest extends Specification { val inv : InventoryData = InventoryData( List( InternalSlot(ObjectClass.medicalapplicator, PlanetSideGUID(4201), 0, - WeaponData(0, 0, 0, List(InternalSlot(ObjectClass.health_canister, PlanetSideGUID(3472), 0, AmmoBoxData(0)))) + WeaponData(CommonFieldData(PlanetSideEmpire.TR), 0, List(InternalSlot(ObjectClass.health_canister, PlanetSideGUID(3472), 0, CommonFieldData()(false)))) ), InternalSlot(ObjectClass.bank, PlanetSideGUID(2952), 1, - WeaponData(0, 0, 0, List(InternalSlot(ObjectClass.armor_canister, PlanetSideGUID(3758), 0, AmmoBoxData(0)))) + WeaponData(CommonFieldData(PlanetSideEmpire.TR), 0, List(InternalSlot(ObjectClass.armor_canister, PlanetSideGUID(3758), 0, CommonFieldData()(false)))) ), InternalSlot(ObjectClass.mini_chaingun, PlanetSideGUID(2929), 2, - WeaponData(0, 0, 0, List(InternalSlot(ObjectClass.bullet_9mm, PlanetSideGUID(3292), 0, AmmoBoxData(0)))) + WeaponData(CommonFieldData(PlanetSideEmpire.TR), 0, List(InternalSlot(ObjectClass.bullet_9mm, PlanetSideGUID(3292), 0, CommonFieldData()(false)))) ), InternalSlot(ObjectClass.chainblade, PlanetSideGUID(3222), 4, - WeaponData(0, 0, 0, List(InternalSlot(ObjectClass.melee_ammo, PlanetSideGUID(3100), 0, AmmoBoxData(0)))) + WeaponData(CommonFieldData(PlanetSideEmpire.TR), 0, List(InternalSlot(ObjectClass.melee_ammo, PlanetSideGUID(3100), 0, CommonFieldData()(false)))) ) ) ) @@ -214,11 +218,7 @@ class MountedVehiclesTest extends Specification { Vector3(11.25f, 2.8125f, 92.8125f), Some(Vector3(31.71875f, 8.875f, -0.03125f)) ), - PlanetSideEmpire.TR, - false, false, - 0, - false, false, - PlanetSideGUID(3776), + CommonFieldData(PlanetSideEmpire.TR, false, false, false, None, false, Some(false), None, PlanetSideGUID(3776)), false, 255, false, false, @@ -230,7 +230,7 @@ class MountedVehiclesTest extends Specification { List( InternalSlot(ObjectClass.avatar, PlanetSideGUID(3776), 0, player), InternalSlot(ObjectClass.rotarychaingun_mosquito, PlanetSideGUID(3602), 1, - WeaponData(6, 0, 0, List(InternalSlot(ObjectClass.bullet_12mm, PlanetSideGUID(3538), 0, AmmoBoxData(0)))) + WeaponData(CommonFieldData(), 0, List(InternalSlot(ObjectClass.bullet_12mm, PlanetSideGUID(3538), 0, CommonFieldData()(false)))) ) ) ) diff --git a/common/src/test/scala/game/objectcreatevehicle/NonstandardVehiclesTest.scala b/common/src/test/scala/game/objectcreatevehicle/NonstandardVehiclesTest.scala index aec38af8..3f31ebf0 100644 --- a/common/src/test/scala/game/objectcreatevehicle/NonstandardVehiclesTest.scala +++ b/common/src/test/scala/game/objectcreatevehicle/NonstandardVehiclesTest.scala @@ -2,8 +2,8 @@ package game.objectcreatevehicle import net.psforever.packet._ -import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} import net.psforever.packet.game.objectcreate._ +import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} import net.psforever.types._ import org.specs2.mutable._ import scodec.bits._ @@ -21,19 +21,25 @@ class NonstandardVehiclesTest extends Specification { cls mustEqual ObjectClass.droppod guid mustEqual PlanetSideGUID(3595) parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[DroppodData] mustEqual true - val droppod = data.get.asInstanceOf[DroppodData] - droppod.basic.pos.coord.x mustEqual 5108.0f - droppod.basic.pos.coord.y mustEqual 6164.0f - droppod.basic.pos.coord.z mustEqual 1023.9844f - droppod.basic.pos.orient.x mustEqual 0f - droppod.basic.pos.orient.y mustEqual 0f - droppod.basic.pos.orient.z mustEqual 90.0f - droppod.basic.unk mustEqual 2 - droppod.basic.player_guid mustEqual PlanetSideGUID(0) - droppod.burn mustEqual false - droppod.health mustEqual 255 + data match { + case DroppodData(basic, burn, health) => + basic.pos.coord mustEqual Vector3(5108.0f, 6164.0f, 1023.9844f) + basic.pos.orient mustEqual Vector3.z(90.0f) + + basic.data.faction mustEqual PlanetSideEmpire.VS + basic.data.bops mustEqual false + basic.data.alternate mustEqual false + basic.data.v1 mustEqual true + basic.data.v2.isDefined mustEqual false + basic.data.v3 mustEqual false + basic.data.v5.isDefined mustEqual false + basic.data.guid mustEqual PlanetSideGUID(0) + + burn mustEqual false + health mustEqual 255 + case _ => + ko + } case _ => ko } @@ -48,10 +54,9 @@ class NonstandardVehiclesTest extends Specification { parent.isDefined mustEqual true parent.get.guid mustEqual PlanetSideGUID(786) parent.get.slot mustEqual 3 - data.isDefined mustEqual true - data.get.isInstanceOf[OrbitalShuttleData] mustEqual true - data.get.asInstanceOf[OrbitalShuttleData].faction mustEqual PlanetSideEmpire.VS - data.get.asInstanceOf[OrbitalShuttleData].pos.isDefined mustEqual false + data.isInstanceOf[OrbitalShuttleData] mustEqual true + data.asInstanceOf[OrbitalShuttleData].faction mustEqual PlanetSideEmpire.VS + data.asInstanceOf[OrbitalShuttleData].pos.isDefined mustEqual false case _ => ko } @@ -64,9 +69,8 @@ class NonstandardVehiclesTest extends Specification { cls mustEqual ObjectClass.orbital_shuttle guid mustEqual PlanetSideGUID(1127) parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[OrbitalShuttleData] mustEqual true - val shuttle = data.get.asInstanceOf[OrbitalShuttleData] + data.isInstanceOf[OrbitalShuttleData] mustEqual true + val shuttle = data.asInstanceOf[OrbitalShuttleData] shuttle.faction mustEqual PlanetSideEmpire.VS shuttle.pos.isDefined mustEqual true shuttle.pos.get.coord.x mustEqual 5610.0156f @@ -82,10 +86,9 @@ class NonstandardVehiclesTest extends Specification { "encode (droppod)" in { val obj = DroppodData( - CommonFieldData( + CommonFieldDataWithPlacement( PlacementData(5108.0f, 6164.0f, 1023.9844f, 0f, 0f, 90.0f), - PlanetSideEmpire.VS, - 2 + CommonFieldData(PlanetSideEmpire.VS, 2) ) ) val msg = ObjectCreateMessage(ObjectClass.droppod, PlanetSideGUID(3595), obj) diff --git a/common/src/test/scala/game/objectcreatevehicle/NormalVehiclesTest.scala b/common/src/test/scala/game/objectcreatevehicle/NormalVehiclesTest.scala index 5d537227..5d5dcc4c 100644 --- a/common/src/test/scala/game/objectcreatevehicle/NormalVehiclesTest.scala +++ b/common/src/test/scala/game/objectcreatevehicle/NormalVehiclesTest.scala @@ -2,8 +2,8 @@ package game.objectcreatevehicle import net.psforever.packet._ -import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} import net.psforever.packet.game.objectcreate._ +import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} import net.psforever.types._ import org.specs2.mutable._ import scodec.bits._ @@ -21,15 +21,14 @@ class NormalVehiclesTest extends Specification { cls mustEqual ObjectClass.fury guid mustEqual PlanetSideGUID(413) parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[VehicleData] mustEqual true - val fury = data.get.asInstanceOf[VehicleData] + data.isInstanceOf[VehicleData] mustEqual true + val fury = data.asInstanceOf[VehicleData] fury.pos.coord mustEqual Vector3(6531.961f, 1872.1406f,24.734375f) fury.pos.orient mustEqual Vector3(0, 0, 357.1875f) - fury.pos.vel mustEqual None - fury.faction mustEqual PlanetSideEmpire.VS - fury.unk1 mustEqual 2 - fury.owner_guid mustEqual PlanetSideGUID(0) + fury.pos.vel.isEmpty mustEqual true + fury.data.faction mustEqual PlanetSideEmpire.VS + fury.data.v1 mustEqual true + fury.data.guid mustEqual PlanetSideGUID(0) fury.health mustEqual 255 // fury.inventory.isDefined mustEqual true @@ -39,17 +38,40 @@ class NormalVehiclesTest extends Specification { mounting.guid mustEqual PlanetSideGUID(400) mounting.parentSlot mustEqual 1 mounting.obj.isInstanceOf[WeaponData] mustEqual true - val weapon = mounting.obj.asInstanceOf[WeaponData] - weapon.unk1 mustEqual 0x6 - weapon.unk2 mustEqual 0x8 - weapon.fire_mode mustEqual 0 - weapon.ammo.size mustEqual 1 - val ammo = weapon.ammo.head - ammo.objectClass mustEqual ObjectClass.hellfire_ammo - ammo.guid mustEqual PlanetSideGUID(432) - ammo.parentSlot mustEqual 0 - ammo.obj.isInstanceOf[AmmoBoxData] mustEqual true - ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0x8 + mounting.obj match { + case WeaponData(CommonFieldData(wfaction, wbops, walternate, wv1, wv2, wv3, wv4, wv5, wfguid), fmode, ammo, _) => + wfaction mustEqual PlanetSideEmpire.NEUTRAL + wbops mustEqual false + walternate mustEqual false + wv1 mustEqual true + wv2.isEmpty mustEqual true + wv3 mustEqual false + wv4.isEmpty mustEqual true + wv5.isEmpty mustEqual true + wfguid mustEqual PlanetSideGUID(0) + + fmode mustEqual 0 + + ammo.head.objectClass mustEqual ObjectClass.hellfire_ammo + ammo.head.guid mustEqual PlanetSideGUID(432) + ammo.head.parentSlot mustEqual 0 + ammo.head.obj match { + case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid) => + faction mustEqual PlanetSideEmpire.NEUTRAL + bops mustEqual false + alternate mustEqual false + v1 mustEqual true + v2.isEmpty mustEqual true + v3 mustEqual false + v4.contains(false) mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + case _ => + ko + } case _ => ko } @@ -62,15 +84,14 @@ class NormalVehiclesTest extends Specification { cls mustEqual ObjectClass.lightning guid mustEqual PlanetSideGUID(90) parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[VehicleData] mustEqual true - val lightning = data.get.asInstanceOf[VehicleData] + data.isInstanceOf[VehicleData] mustEqual true + val lightning = data.asInstanceOf[VehicleData] lightning.pos.coord mustEqual Vector3(3674.8438f, 2726.789f, 91.15625f) lightning.pos.orient mustEqual Vector3(0, 0, 90) - lightning.pos.vel mustEqual None - lightning.faction mustEqual PlanetSideEmpire.VS - lightning.unk1 mustEqual 2 - lightning.owner_guid mustEqual PlanetSideGUID(0) + lightning.pos.vel.isEmpty mustEqual true + lightning.data.faction mustEqual PlanetSideEmpire.VS + lightning.data.v1 mustEqual true + lightning.data.guid mustEqual PlanetSideGUID(0) lightning.health mustEqual 255 lightning.inventory.isDefined mustEqual true @@ -79,26 +100,59 @@ class NormalVehiclesTest extends Specification { mounting.objectClass mustEqual ObjectClass.lightning_weapon_system mounting.guid mustEqual PlanetSideGUID(91) mounting.parentSlot mustEqual 1 - mounting.obj.isInstanceOf[WeaponData] mustEqual true - val weapon = mounting.obj.asInstanceOf[WeaponData] - weapon.unk1 mustEqual 0x4 - weapon.unk2 mustEqual 0x8 - weapon.fire_mode mustEqual 0 - weapon.ammo.size mustEqual 2 - //0 - var ammo = weapon.ammo.head - ammo.objectClass mustEqual ObjectClass.bullet_75mm - ammo.guid mustEqual PlanetSideGUID(92) - ammo.parentSlot mustEqual 0 - ammo.obj.isInstanceOf[AmmoBoxData] mustEqual true - ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0x0 - //1 - ammo = weapon.ammo(1) - ammo.objectClass mustEqual ObjectClass.bullet_25mm - ammo.guid mustEqual PlanetSideGUID(93) - ammo.parentSlot mustEqual 1 - ammo.obj.isInstanceOf[AmmoBoxData] mustEqual true - ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0x0 + mounting.obj match { + case WeaponData(CommonFieldData(wfaction, wbops, walternate, wv1, wv2, wv3, wv4, wv5, wfguid), fmode, ammo, _) => + wfaction mustEqual PlanetSideEmpire.VS + wbops mustEqual false + walternate mustEqual false + wv1 mustEqual true + wv2.isEmpty mustEqual true + wv3 mustEqual false + wv4.isEmpty mustEqual true + wv5.isEmpty mustEqual true + wfguid mustEqual PlanetSideGUID(0) + + fmode mustEqual 0 + + //0 + ammo.head.objectClass mustEqual ObjectClass.bullet_75mm + ammo.head.guid mustEqual PlanetSideGUID(92) + ammo.head.parentSlot mustEqual 0 + ammo.head.obj match { + case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid) => + faction mustEqual PlanetSideEmpire.NEUTRAL + bops mustEqual false + alternate mustEqual false + v1 mustEqual false + v2.isEmpty mustEqual true + v3 mustEqual false + v4.contains(false) mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + //1 + ammo(1).objectClass mustEqual ObjectClass.bullet_25mm + ammo(1).guid mustEqual PlanetSideGUID(93) + ammo(1).parentSlot mustEqual 1 + ammo(1).obj match { + case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid) => + faction mustEqual PlanetSideEmpire.NEUTRAL + bops mustEqual false + alternate mustEqual false + v1 mustEqual false + v2.isEmpty mustEqual true + v3 mustEqual false + v4.contains(false) mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + case _ => + ko + } case _ => ko } @@ -111,62 +165,104 @@ class NormalVehiclesTest extends Specification { cls mustEqual ObjectClass.mediumtransport guid mustEqual PlanetSideGUID(387) parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[VehicleData] mustEqual true - val deliverer = data.get.asInstanceOf[VehicleData] - deliverer.pos.coord mustEqual Vector3(6531.961f, 1872.1406f, 24.734375f) - deliverer.pos.orient mustEqual Vector3(0, 0, 357.1875f) - deliverer.pos.vel mustEqual None - deliverer.faction mustEqual PlanetSideEmpire.NC - deliverer.owner_guid mustEqual PlanetSideGUID(0) - deliverer.health mustEqual 255 - deliverer.driveState mustEqual DriveState.State7 - deliverer.jammered mustEqual false - deliverer.destroyed mustEqual false - deliverer.cloak mustEqual false - deliverer.unk1 mustEqual 2 - deliverer.unk2 mustEqual false - deliverer.unk3 mustEqual false - deliverer.unk4 mustEqual false - deliverer.unk5 mustEqual true - deliverer.unk6 mustEqual false - deliverer.vehicle_format_data mustEqual None - deliverer.inventory.isDefined mustEqual true - deliverer.inventory.get.contents.size mustEqual 2 - //0 - var mounting = deliverer.inventory.get.contents.head - mounting.objectClass mustEqual ObjectClass.mediumtransport_weapon_systemA - mounting.guid mustEqual PlanetSideGUID(383) - mounting.parentSlot mustEqual 5 - mounting.obj.isInstanceOf[WeaponData] mustEqual true - var weapon = mounting.obj.asInstanceOf[WeaponData] - weapon.unk1 mustEqual 0x6 - weapon.unk2 mustEqual 0x8 - weapon.fire_mode mustEqual 0 - weapon.ammo.size mustEqual 1 - var ammo = weapon.ammo.head - ammo.objectClass mustEqual ObjectClass.bullet_20mm - ammo.guid mustEqual PlanetSideGUID(420) - ammo.parentSlot mustEqual 0 - ammo.obj.isInstanceOf[AmmoBoxData] mustEqual true - ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0x8 - //1 - mounting = deliverer.inventory.get.contents(1) - mounting.objectClass mustEqual ObjectClass.mediumtransport_weapon_systemB - mounting.guid mustEqual PlanetSideGUID(556) - mounting.parentSlot mustEqual 6 - mounting.obj.isInstanceOf[WeaponData] mustEqual true - weapon = mounting.obj.asInstanceOf[WeaponData] - weapon.unk1 mustEqual 0x6 - weapon.unk2 mustEqual 0x8 - weapon.fire_mode mustEqual 0 - weapon.ammo.size mustEqual 1 - ammo = weapon.ammo.head - ammo.objectClass mustEqual ObjectClass.bullet_20mm - ammo.guid mustEqual PlanetSideGUID(575) - ammo.parentSlot mustEqual 0 - ammo.obj.isInstanceOf[AmmoBoxData] mustEqual true - ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0x8 + data match { + case VehicleData(pos, vdata, unk3, health, unk4, _, driveState, unk5, unk6, _, format, Some(InventoryData(inv))) => + pos.coord mustEqual Vector3(6531.961f, 1872.1406f, 24.734375f) + pos.orient mustEqual Vector3.z(357.1875f) + + vdata.faction mustEqual PlanetSideEmpire.NC + vdata.alternate mustEqual false + vdata.v1 mustEqual true + vdata.v3 mustEqual false + vdata.v5.isEmpty mustEqual true + vdata.guid mustEqual PlanetSideGUID(0) + + health mustEqual 255 + driveState mustEqual DriveState.State7 + unk3 mustEqual false + unk4 mustEqual false + unk5 mustEqual true + unk6 mustEqual false + format.isEmpty mustEqual true + //0 + inv.head.objectClass mustEqual ObjectClass.mediumtransport_weapon_systemA + inv.head.guid mustEqual PlanetSideGUID(383) + inv.head.parentSlot mustEqual 5 + inv.head.obj match { + case WeaponData(CommonFieldData(wfaction, wbops, walternate, wv1, wv2, wv3, wv4, wv5, wfguid), fmode, List(ammo), _) => + wfaction mustEqual PlanetSideEmpire.NEUTRAL + wbops mustEqual false + walternate mustEqual false + wv1 mustEqual true + wv2.isEmpty mustEqual true + wv3 mustEqual false + wv4.isEmpty mustEqual true + wv5.isEmpty mustEqual true + wfguid mustEqual PlanetSideGUID(0) + + fmode mustEqual 0 + + ammo.objectClass mustEqual ObjectClass.bullet_20mm + ammo.guid mustEqual PlanetSideGUID(420) + ammo.parentSlot mustEqual 0 + ammo.obj match { + case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid) => + faction mustEqual PlanetSideEmpire.NEUTRAL + bops mustEqual false + alternate mustEqual false + v1 mustEqual true + v2.isEmpty mustEqual true + v3 mustEqual false + v4.contains(false) mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + case _ => + ko + } + //1 + inv(1).objectClass mustEqual ObjectClass.mediumtransport_weapon_systemB + inv(1).guid mustEqual PlanetSideGUID(556) + inv(1).parentSlot mustEqual 6 + inv(1).obj match { + case WeaponData(CommonFieldData(wfaction, wbops, walternate, wv1, wv2, wv3, wv4, wv5, wfguid), fmode, List(ammo), _) => + wfaction mustEqual PlanetSideEmpire.NEUTRAL + wbops mustEqual false + walternate mustEqual false + wv1 mustEqual true + wv2.isEmpty mustEqual true + wv3 mustEqual false + wv4.isEmpty mustEqual true + wv5.isEmpty mustEqual true + wfguid mustEqual PlanetSideGUID(0) + + fmode mustEqual 0 + + ammo.objectClass mustEqual ObjectClass.bullet_20mm + ammo.guid mustEqual PlanetSideGUID(575) + ammo.parentSlot mustEqual 0 + ammo.obj match { + case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid) => + faction mustEqual PlanetSideEmpire.NEUTRAL + bops mustEqual false + alternate mustEqual false + v1 mustEqual true + v2.isEmpty mustEqual true + v3 mustEqual false + v4.contains(false) mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + case _ => + ko + } + case _ => + ko + } case _ => ko } @@ -175,22 +271,26 @@ class NormalVehiclesTest extends Specification { "encode (fury)" in { val obj = VehicleData( PlacementData(6531.961f, 1872.1406f, 24.734375f, 0f, 0f, 357.1875f), - PlanetSideEmpire.VS, - false, false, - 2, - false, false, - PlanetSideGUID(0), + CommonFieldData(PlanetSideEmpire.VS, false, false, true, None, false, Some(false), None, PlanetSideGUID(0)), false, 255, false, false, DriveState.Mobile, false, false, false, None, - Some(InventoryData( + Some(InventoryData(List( InventoryItemData(ObjectClass.fury_weapon_systema, PlanetSideGUID(400), 1, - WeaponData(0x6, 0x8, 0, ObjectClass.hellfire_ammo, PlanetSideGUID(432), 0, AmmoBoxData(0x8)) - ) :: Nil - )) + WeaponData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, 2), + 0, + List( + InternalSlot(ObjectClass.hellfire_ammo, PlanetSideGUID(432), 0, + CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false) + ) + ) + ) + ) + ))) )(VehicleFormat.Normal) val msg = ObjectCreateMessage(ObjectClass.fury, PlanetSideGUID(413), obj) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector @@ -201,22 +301,25 @@ class NormalVehiclesTest extends Specification { "encode (lightning)" in { val obj = VehicleData( PlacementData(3674.8438f, 2726.789f, 91.15625f, 0f, 0f, 90.0f), - PlanetSideEmpire.VS, - false, false, - 2, - false, false, - PlanetSideGUID(0), + CommonFieldData(PlanetSideEmpire.VS, false, false, true, None, false, Some(false), None, PlanetSideGUID(0)), false, 255, false, false, DriveState.Mobile, false, false, false, None, - Some(InventoryData( + Some(InventoryData(List( InventoryItemData(ObjectClass.lightning_weapon_system, PlanetSideGUID(91), 1, - WeaponData(4, 8, 0, ObjectClass.bullet_75mm, PlanetSideGUID(92), 0, AmmoBoxData(), ObjectClass.bullet_25mm, PlanetSideGUID(93), 1, AmmoBoxData()) - ) :: Nil - )) + WeaponData( + CommonFieldData(PlanetSideEmpire.VS, 2), + 0, + List( + InternalSlot(ObjectClass.bullet_75mm, PlanetSideGUID(92), 0, CommonFieldData()(false)), + InternalSlot(ObjectClass.bullet_25mm, PlanetSideGUID(93), 1, CommonFieldData()(false)) + ) + ) + ) + ))) )(VehicleFormat.Normal) val msg = ObjectCreateMessage(ObjectClass.lightning, PlanetSideGUID(90), obj) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector @@ -227,25 +330,37 @@ class NormalVehiclesTest extends Specification { "encode (medium transport)" in { val obj = VehicleData( PlacementData(6531.961f, 1872.1406f, 24.734375f, 0f, 0f, 357.1875f), - PlanetSideEmpire.NC, - false, false, - 2, - false, false, - PlanetSideGUID(0), + CommonFieldData(PlanetSideEmpire.NC, false, false, true, None, false, Some(false), None, PlanetSideGUID(0)), false, 255, false, false, DriveState.State7, true, false, false, None, - Some(InventoryData( + Some(InventoryData(List( InventoryItemData(ObjectClass.mediumtransport_weapon_systemA, PlanetSideGUID(383), 5, - WeaponData(6, 8, ObjectClass.bullet_20mm, PlanetSideGUID(420), 0, AmmoBoxData(8)) - ) :: - InventoryItemData(ObjectClass.mediumtransport_weapon_systemB, PlanetSideGUID(556), 6, - WeaponData(6, 8, ObjectClass.bullet_20mm, PlanetSideGUID(575), 0, AmmoBoxData(8)) - ) :: Nil - )) + WeaponData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, 2), + 0, + List( + InternalSlot(ObjectClass.bullet_20mm, PlanetSideGUID(420), 0, + CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false) + ) + ) + ) + ), + InventoryItemData(ObjectClass.mediumtransport_weapon_systemB, PlanetSideGUID(556), 6, + WeaponData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, 2), + 0, + List( + InternalSlot(ObjectClass.bullet_20mm, PlanetSideGUID(575), 0, + CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false) + ) + ) + ) + ) + ))) )(VehicleFormat.Normal) val msg = ObjectCreateMessage(ObjectClass.mediumtransport, PlanetSideGUID(387), obj) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector diff --git a/common/src/test/scala/game/objectcreatevehicle/UtilityVehiclesTest.scala b/common/src/test/scala/game/objectcreatevehicle/UtilityVehiclesTest.scala index 0c081a16..a7e2e093 100644 --- a/common/src/test/scala/game/objectcreatevehicle/UtilityVehiclesTest.scala +++ b/common/src/test/scala/game/objectcreatevehicle/UtilityVehiclesTest.scala @@ -2,8 +2,8 @@ package game.objectcreatevehicle import net.psforever.packet._ -import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} import net.psforever.packet.game.objectcreate._ +import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} import net.psforever.types._ import org.specs2.mutable._ import scodec.bits._ @@ -22,20 +22,19 @@ class UtilityVehiclesTest extends Specification { cls mustEqual ObjectClass.ant guid mustEqual PlanetSideGUID(380) parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[VehicleData] mustEqual true - val ant = data.get.asInstanceOf[VehicleData] + data.isInstanceOf[VehicleData] mustEqual true + val ant = data.asInstanceOf[VehicleData] ant.pos.coord mustEqual Vector3(3674.8438f, 2726.789f, 91.15625f) ant.pos.orient mustEqual Vector3(0, 0, 90) - ant.faction mustEqual PlanetSideEmpire.VS - ant.owner_guid mustEqual PlanetSideGUID(0) + ant.data.faction mustEqual PlanetSideEmpire.VS + ant.data.alternate mustEqual false + ant.data.v1 mustEqual true + ant.data.v3 mustEqual false + ant.data.v5.isEmpty mustEqual true + ant.data.guid mustEqual PlanetSideGUID(0) ant.driveState mustEqual DriveState.Mobile ant.health mustEqual 255 - ant.jammered mustEqual false - ant.destroyed mustEqual false ant.cloak mustEqual false - ant.unk1 mustEqual 2 - ant.unk2 mustEqual false ant.unk3 mustEqual false ant.unk4 mustEqual false ant.unk5 mustEqual false @@ -52,22 +51,21 @@ class UtilityVehiclesTest extends Specification { cls mustEqual ObjectClass.ams guid mustEqual PlanetSideGUID(4157) parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[VehicleData] mustEqual true - val ams = data.get.asInstanceOf[VehicleData] + data.isInstanceOf[VehicleData] mustEqual true + val ams = data.asInstanceOf[VehicleData] ams.pos.coord mustEqual Vector3(3674, 2726.789f, 91.15625f) ams.pos.orient mustEqual Vector3(0, 0, 90) ams.pos.vel mustEqual None - ams.faction mustEqual PlanetSideEmpire.VS - ams.owner_guid mustEqual PlanetSideGUID(2885) + ams.data.faction mustEqual PlanetSideEmpire.VS + ams.data.alternate mustEqual false + ams.data.v1 mustEqual false + ams.data.v3 mustEqual false + ams.data.v5.isEmpty mustEqual true + ams.data.guid mustEqual PlanetSideGUID(2885) ams.driveState mustEqual DriveState.Deployed ams.vehicle_format_data mustEqual Some(UtilityVehicleData(60)) ams.health mustEqual 236 - ams.jammered mustEqual false - ams.destroyed mustEqual false ams.cloak mustEqual true - ams.unk1 mustEqual 0 - ams.unk2 mustEqual false ams.unk3 mustEqual false ams.unk4 mustEqual false ams.unk5 mustEqual false @@ -78,19 +76,19 @@ class UtilityVehiclesTest extends Specification { inv.head.objectClass mustEqual ObjectClass.matrix_terminalc inv.head.guid mustEqual PlanetSideGUID(3663) inv.head.parentSlot mustEqual 1 - inv.head.obj.isInstanceOf[CommonTerminalData] mustEqual true + inv.head.obj.isInstanceOf[CommonFieldData] mustEqual true inv(1).objectClass mustEqual ObjectClass.ams_respawn_tube inv(1).guid mustEqual PlanetSideGUID(3638) inv(1).parentSlot mustEqual 2 - inv(1).obj.isInstanceOf[CommonTerminalData] mustEqual true + inv(1).obj.isInstanceOf[CommonFieldData] mustEqual true inv(2).objectClass mustEqual ObjectClass.order_terminala inv(2).guid mustEqual PlanetSideGUID(3827) inv(2).parentSlot mustEqual 3 - inv(2).obj.isInstanceOf[CommonTerminalData] mustEqual true + inv(2).obj.isInstanceOf[CommonFieldData] mustEqual true inv(3).objectClass mustEqual ObjectClass.order_terminalb inv(3).guid mustEqual PlanetSideGUID(3556) inv(3).parentSlot mustEqual 4 - inv(3).obj.isInstanceOf[CommonTerminalData] mustEqual true + inv(3).obj.isInstanceOf[CommonFieldData] mustEqual true case _ => ko } @@ -99,11 +97,7 @@ class UtilityVehiclesTest extends Specification { "encode (ant)" in { val obj = VehicleData( PlacementData(3674.8438f, 2726.789f, 91.15625f, 0f, 0f, 90.0f), - PlanetSideEmpire.VS, - false, false, - 2, - false, false, - PlanetSideGUID(0), + CommonFieldData(PlanetSideEmpire.VS, false, false, true, None, false, Some(false), None, PlanetSideGUID(0)), false, 255, false, false, @@ -121,11 +115,7 @@ class UtilityVehiclesTest extends Specification { "encode (ams)" in { val obj = VehicleData( PlacementData(3674.0f, 2726.789f, 91.15625f, 0f, 0f, 90.0f), - PlanetSideEmpire.VS, - false, false, - 0, - false, false, - PlanetSideGUID(2885), + CommonFieldData(PlanetSideEmpire.VS, false, false, false, None, false, Some(false), None, PlanetSideGUID(2885)), false, 236, false, false, @@ -133,10 +123,10 @@ class UtilityVehiclesTest extends Specification { false, true, true, Some(UtilityVehicleData(60)), //what does this mean? Some(InventoryData(List( - InternalSlot(ObjectClass.matrix_terminalc, PlanetSideGUID(3663), 1, CommonTerminalData(PlanetSideEmpire.VS)), - InternalSlot(ObjectClass.ams_respawn_tube, PlanetSideGUID(3638), 2, CommonTerminalData(PlanetSideEmpire.VS)), - InternalSlot(ObjectClass.order_terminala, PlanetSideGUID(3827), 3, CommonTerminalData(PlanetSideEmpire.VS)), - InternalSlot(ObjectClass.order_terminalb, PlanetSideGUID(3556), 4, CommonTerminalData(PlanetSideEmpire.VS)) + InternalSlot(ObjectClass.matrix_terminalc, PlanetSideGUID(3663), 1, CommonFieldData(PlanetSideEmpire.VS)(false)), + InternalSlot(ObjectClass.ams_respawn_tube, PlanetSideGUID(3638), 2, CommonFieldData(PlanetSideEmpire.VS)(false)), + InternalSlot(ObjectClass.order_terminala, PlanetSideGUID(3827), 3, CommonFieldData(PlanetSideEmpire.VS)(false)), + InternalSlot(ObjectClass.order_terminalb, PlanetSideGUID(3556), 4, CommonFieldData(PlanetSideEmpire.VS)(false)) ))) )(VehicleFormat.Utility) val msg = ObjectCreateMessage(ObjectClass.ams, PlanetSideGUID(4157), obj) diff --git a/common/src/test/scala/game/objectcreatevehicle/VariantVehiclesTest.scala b/common/src/test/scala/game/objectcreatevehicle/VariantVehiclesTest.scala index 5924cda1..672945b8 100644 --- a/common/src/test/scala/game/objectcreatevehicle/VariantVehiclesTest.scala +++ b/common/src/test/scala/game/objectcreatevehicle/VariantVehiclesTest.scala @@ -19,17 +19,16 @@ class VariantVehiclesTest extends Specification { cls mustEqual ObjectClass.switchblade guid mustEqual PlanetSideGUID(418) parent.isDefined mustEqual false - data.isDefined mustEqual true - data.get.isInstanceOf[VehicleData] mustEqual true - val switchblade = data.get.asInstanceOf[VehicleData] + data.isInstanceOf[VehicleData] mustEqual true + val switchblade = data.asInstanceOf[VehicleData] switchblade.pos.coord.x mustEqual 6531.961f switchblade.pos.coord.y mustEqual 1872.1406f switchblade.pos.coord.z mustEqual 24.734375f switchblade.pos.orient.x mustEqual 0f switchblade.pos.orient.y mustEqual 0f switchblade.pos.orient.z mustEqual 357.1875f - switchblade.faction mustEqual PlanetSideEmpire.VS - switchblade.unk1 mustEqual 2 + switchblade.data.faction mustEqual PlanetSideEmpire.VS + switchblade.data.v1 mustEqual true switchblade.health mustEqual 255 switchblade.driveState mustEqual DriveState.Mobile switchblade.inventory.isDefined mustEqual true @@ -39,21 +38,59 @@ class VariantVehiclesTest extends Specification { weapon.objectClass mustEqual ObjectClass.scythe weapon.guid mustEqual PlanetSideGUID(355) weapon.parentSlot mustEqual 1 - weapon.obj.asInstanceOf[WeaponData].unk1 mustEqual 0x6 - weapon.obj.asInstanceOf[WeaponData].unk2 mustEqual 0x8 - weapon.obj.asInstanceOf[WeaponData].ammo.size mustEqual 2 - //ammo-0 - var ammo = weapon.obj.asInstanceOf[WeaponData].ammo.head - ammo.objectClass mustEqual ObjectClass.ancient_ammo_vehicle - ammo.guid mustEqual PlanetSideGUID(366) - ammo.parentSlot mustEqual 0 - ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0x8 - //ammo-1 - ammo = weapon.obj.asInstanceOf[WeaponData].ammo(1) - ammo.objectClass mustEqual ObjectClass.ancient_ammo_vehicle - ammo.guid mustEqual PlanetSideGUID(385) - ammo.parentSlot mustEqual 1 - ammo.obj.asInstanceOf[AmmoBoxData].unk mustEqual 0x8 + weapon.obj match { + case WeaponData(CommonFieldData(wfaction, wbops, walternate, wv1, wv2, wv3, wv4, wv5, wfguid), fmode, ammo, _) => + wfaction mustEqual PlanetSideEmpire.NEUTRAL + wbops mustEqual false + walternate mustEqual false + wv1 mustEqual true + wv2.isEmpty mustEqual true + wv3 mustEqual false + wv4.isEmpty mustEqual true + wv5.isEmpty mustEqual true + wfguid mustEqual PlanetSideGUID(0) + + fmode mustEqual 0 + + //ammo-0 + ammo.head.objectClass mustEqual ObjectClass.ancient_ammo_vehicle + ammo.head.guid mustEqual PlanetSideGUID(366) + ammo.head.parentSlot mustEqual 0 + ammo.head.obj match { + case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid) => + faction mustEqual PlanetSideEmpire.NEUTRAL + bops mustEqual false + alternate mustEqual false + v1 mustEqual true + v2.isEmpty mustEqual true + v3 mustEqual false + v4.contains(false) mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + //ammo-1 + ammo(1).objectClass mustEqual ObjectClass.ancient_ammo_vehicle + ammo(1).guid mustEqual PlanetSideGUID(385) + ammo(1).parentSlot mustEqual 1 + ammo(1).obj match { + case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid) => + faction mustEqual PlanetSideEmpire.NEUTRAL + bops mustEqual false + alternate mustEqual false + v1 mustEqual true + v2.isEmpty mustEqual true + v3 mustEqual false + v4.contains(false) mustEqual true + v5.isEmpty mustEqual true + fguid mustEqual PlanetSideGUID(0) + case _ => + ko + } + case _ => + ko + } case _ => ko } @@ -62,22 +99,25 @@ class VariantVehiclesTest extends Specification { "encode (switchblade)" in { val obj = VehicleData( PlacementData(6531.961f, 1872.1406f, 24.734375f, 0f, 0f, 357.1875f), - PlanetSideEmpire.VS, - false, false, - 2, - false, false, - PlanetSideGUID(0), + CommonFieldData(PlanetSideEmpire.VS, false, false, true, None, false, Some(false), None, PlanetSideGUID(0)), false, 255, false, false, DriveState.Mobile, false, false, false, Some(VariantVehicleData(0)), - Some(InventoryData( + Some(InventoryData(List( InventoryItemData(ObjectClass.scythe, PlanetSideGUID(355), 1, - WeaponData(0x6, 0x8, 0, ObjectClass.ancient_ammo_vehicle, PlanetSideGUID(366), 0, AmmoBoxData(0x8), ObjectClass.ancient_ammo_vehicle, PlanetSideGUID(385), 1, AmmoBoxData(0x8)) - ) :: Nil - )) + WeaponData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), + 0, + List( + InternalSlot(ObjectClass.ancient_ammo_vehicle, PlanetSideGUID(366), 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)), + InternalSlot(ObjectClass.ancient_ammo_vehicle, PlanetSideGUID(385), 1, CommonFieldData(PlanetSideEmpire.NEUTRAL, 2)(false)) + ) + ) + ) + ))) )(VehicleFormat.Variant) val msg = ObjectCreateMessage(ObjectClass.switchblade, PlanetSideGUID(418), obj) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector diff --git a/common/src/test/scala/objects/ContainerTest.scala b/common/src/test/scala/objects/ContainerTest.scala index a34e6693..9d398cee 100644 --- a/common/src/test/scala/objects/ContainerTest.scala +++ b/common/src/test/scala/objects/ContainerTest.scala @@ -1,9 +1,9 @@ // Copyright (c) 2017 PSForever package objects -import net.psforever.objects.equipment.EquipmentSize +import net.psforever.objects.equipment.{EquipmentSize, EquipmentSlot} import net.psforever.objects.inventory.{Container, GridInventory, InventoryEquipmentSlot} -import net.psforever.objects.{EquipmentSlot, GlobalDefinitions, OffhandEquipmentSlot, Tool} +import net.psforever.objects.{GlobalDefinitions, OffhandEquipmentSlot, Tool} import net.psforever.packet.game.PlanetSideGUID import org.specs2.mutable._ diff --git a/common/src/test/scala/objects/ConverterTest.scala b/common/src/test/scala/objects/ConverterTest.scala index 4b4d8c1d..1febaac1 100644 --- a/common/src/test/scala/objects/ConverterTest.scala +++ b/common/src/test/scala/objects/ConverterTest.scala @@ -25,13 +25,36 @@ class ConverterTest extends Specification { val obj = AmmoBox(bullet_9mm) obj.Definition.Packet.DetailedConstructorData(obj) match { case Success(pkt) => - pkt mustEqual DetailedAmmoBoxData(8, 50) + pkt mustEqual DetailedAmmoBoxData( + CommonFieldData( + PlanetSideEmpire.NEUTRAL, + bops = false, + alternate = false, + true, + None, + false, + None, + None, + PlanetSideGUID(0) + ), + obj.Capacity + ) case _ => ko } obj.Definition.Packet.ConstructorData(obj) match { case Success(pkt) => - pkt mustEqual AmmoBoxData() + pkt mustEqual CommonFieldData( + PlanetSideEmpire.NEUTRAL, + bops = false, + alternate = false, + false, + None, + false, + Some(false), + None, + PlanetSideGUID(0) + ) case _ => ko } @@ -45,13 +68,23 @@ class ConverterTest extends Specification { obj.Definition.Packet.DetailedConstructorData(obj) match { case Success(pkt) => - pkt mustEqual DetailedWeaponData(4,8, Ammo.shotgun_shell.id, PlanetSideGUID(90), 0, DetailedAmmoBoxData(8, 12)) + pkt mustEqual DetailedWeaponData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), + 0, + List(InternalSlot(Ammo.shotgun_shell.id, PlanetSideGUID(90), 0, DetailedAmmoBoxData(8, 12))) + ) case _ => ko } obj.Definition.Packet.ConstructorData(obj) match { case Success(pkt) => - pkt mustEqual WeaponData(4,8, 0, Ammo.shotgun_shell.id, PlanetSideGUID(90), 0, AmmoBoxData()) + pkt mustEqual WeaponData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), + 0, + List(InternalSlot(Ammo.shotgun_shell.id, PlanetSideGUID(90), 0, + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, Some(false), None, PlanetSideGUID(0))) + ) + ) case _ => ko } @@ -64,7 +97,9 @@ class ConverterTest extends Specification { obj.Definition.Packet.DetailedConstructorData(obj) match { case Success(pkt) => - pkt mustEqual DetailedWeaponData(4,8, 0, + pkt mustEqual DetailedWeaponData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), + 0, List( InternalSlot(Ammo.bullet_9mm.id, PlanetSideGUID(90), 0, DetailedAmmoBoxData(8, 30)), InternalSlot(Ammo.rocket.id, PlanetSideGUID(91), 1, DetailedAmmoBoxData(8, 1)) @@ -75,10 +110,22 @@ class ConverterTest extends Specification { } obj.Definition.Packet.ConstructorData(obj) match { case Success(pkt) => - pkt mustEqual WeaponData(4,8, 0, + pkt mustEqual WeaponData( + CommonFieldData( + PlanetSideEmpire.NEUTRAL, //TODO need faction affinity + bops = false, + alternate = false, + true, + None, + false, + None, + None, + PlanetSideGUID(0) + ), + 0, List( - InternalSlot(Ammo.bullet_9mm.id, PlanetSideGUID(90), 0, AmmoBoxData()), - InternalSlot(Ammo.rocket.id, PlanetSideGUID(91), 1, AmmoBoxData()) + InternalSlot(Ammo.bullet_9mm.id, PlanetSideGUID(90), 0, CommonFieldData()(false)), + InternalSlot(Ammo.rocket.id, PlanetSideGUID(91), 1, CommonFieldData()(false)) ) ) case _ => @@ -100,7 +147,7 @@ class ConverterTest extends Specification { } obj.Definition.Packet.ConstructorData(obj) match { case Success(pkt) => - pkt mustEqual AmmoBoxData() + pkt mustEqual CommonFieldData()(false) case _ => ko } @@ -112,14 +159,28 @@ class ConverterTest extends Specification { obj.GUID = PlanetSideGUID(90) obj.Definition.Packet.DetailedConstructorData(obj) match { case Success(pkt) => - pkt mustEqual DetailedACEData(0) + pkt mustEqual DetailedConstructionToolData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)) + ) case _ => ko } obj.Definition.Packet.ConstructorData(obj) match { case Success(pkt) => - pkt mustEqual ACEData(0,0) + pkt mustEqual HandheldData( + CommonFieldData( + PlanetSideEmpire.NEUTRAL, + false, + false, + true, + None, + false, + None, + None, + PlanetSideGUID(0) + ) + ) case _ => ko } @@ -135,13 +196,37 @@ class ConverterTest extends Specification { obj.GUID = PlanetSideGUID(90) obj.Definition.Packet.DetailedConstructorData(obj) match { case Success(pkt) => - pkt mustEqual DetailedREKData(8) + pkt mustEqual DetailedREKData( + CommonFieldData( + PlanetSideEmpire.NEUTRAL, //TODO faction affinity + false, + false, + true, + None, + false, + Some(false), + None, + PlanetSideGUID(0) + ) + ) case _ => ko } obj.Definition.Packet.ConstructorData(obj) match { case Success(pkt) => - pkt mustEqual REKData(8,0) + pkt mustEqual REKData( + CommonFieldData( + PlanetSideEmpire.NEUTRAL, + false, + false, + true, + None, + false, + Some(false), + None, + PlanetSideGUID(0) + ) + ) case _ => ko } @@ -154,13 +239,17 @@ class ConverterTest extends Specification { obj.GUID = PlanetSideGUID(90) obj.Definition.Packet.DetailedConstructorData(obj) match { case Success(pkt) => - pkt mustEqual DetailedBoomerTriggerData() + pkt mustEqual DetailedConstructionToolData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)) + ) case _ => ko } obj.Definition.Packet.ConstructorData(obj) match { case Success(pkt) => - pkt mustEqual BoomerTriggerData() + pkt mustEqual HandheldData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0)) + ) case _ => ko } @@ -173,14 +262,28 @@ class ConverterTest extends Specification { obj.Router = PlanetSideGUID(1001) obj.Definition.Packet.ConstructorData(obj) match { case Success(pkt) => - pkt mustEqual TelepadData(0, PlanetSideGUID(1001)) + pkt mustEqual HandheldData( + CommonFieldData( + PlanetSideEmpire.NEUTRAL, + false, + false, + false, + None, + false, + None, + Some(1001), + PlanetSideGUID(0) + ) + ) case _ => ko } obj.Definition.Packet.DetailedConstructorData(obj) match { case Success(pkt) => - pkt mustEqual DetailedTelepadData(0, PlanetSideGUID(1001)) + pkt mustEqual DetailedConstructionToolData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, Some(1001), PlanetSideGUID(0)) + ) case _ => ko } @@ -204,12 +307,19 @@ class ConverterTest extends Specification { obj.Definition.Packet.ConstructorData(obj) match { case Success(pkt) => - pkt mustEqual SmallDeployableData( + pkt mustEqual CommonFieldDataWithPlacement( PlacementData(Vector3.Zero, Vector3.Zero), - PlanetSideEmpire.TR, - 0, - false, - false + CommonFieldData( + PlanetSideEmpire.TR, + false, + false, + false, + None, + false, + Some(false), + None, + PlanetSideGUID(0) + ) ) case _ => ko @@ -229,17 +339,20 @@ class ConverterTest extends Specification { obj.Definition.Packet.ConstructorData(obj) match { case Success(pkt) => pkt mustEqual SmallTurretData( - SmallDeployableData( + CommonFieldDataWithPlacement( PlacementData(Vector3.Zero, Vector3.Zero), - PlanetSideEmpire.TR, - 0, - false, - false + CommonFieldData(PlanetSideEmpire.TR, false, false, false, None, false, Some(true), None, PlanetSideGUID(0)) ), 255, InventoryData( List(InternalSlot(ObjectClass.spitfire_weapon, PlanetSideGUID(91), 1, - WeaponData(4, 8, ObjectClass.spitfire_ammo, PlanetSideGUID(92), 0, AmmoBoxData())) + WeaponData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), + 0, + List(InternalSlot(Ammo.spitfire_ammo.id, PlanetSideGUID(92), 0, + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, Some(false), None, PlanetSideGUID(0))) + )) + ) ) ) ) @@ -261,17 +374,20 @@ class ConverterTest extends Specification { obj.Definition.Packet.ConstructorData(obj) match { case Success(pkt) => pkt mustEqual OneMannedFieldTurretData( - SmallDeployableData( + CommonFieldDataWithPlacement( PlacementData(Vector3.Zero, Vector3.Zero), - PlanetSideEmpire.TR, - 0, - false, - false + CommonFieldData(PlanetSideEmpire.TR, false, false, true, None, false, Some(false), None, PlanetSideGUID(0)) ), 255, InventoryData( List(InternalSlot(ObjectClass.energy_gun_tr, PlanetSideGUID(91), 1, - WeaponData(4, 8, ObjectClass.energy_gun_ammo, PlanetSideGUID(92), 0, AmmoBoxData())) + WeaponData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), + 0, + List(InternalSlot(Ammo.energy_gun_ammo.id, PlanetSideGUID(92), 0, + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, Some(false), None, PlanetSideGUID(0))) + )) + ) ) ) ) @@ -291,12 +407,19 @@ class ConverterTest extends Specification { obj.Definition.Packet.ConstructorData(obj) match { case Success(pkt) => pkt mustEqual TRAPData( - SmallDeployableData( + CommonFieldDataWithPlacement( PlacementData(Vector3.Zero, Vector3.Zero), - PlanetSideEmpire.TR, - 0, - false, - false + CommonFieldData( + PlanetSideEmpire.TR, + bops = false, + alternate = false, + true, + None, + false, + Some(true), + None, + PlanetSideGUID(0) + ) ), 255 ) @@ -316,7 +439,7 @@ class ConverterTest extends Specification { obj.Definition.Packet.ConstructorData(obj) match { case Success(pkt) => pkt mustEqual AegisShieldGeneratorData( - CommonFieldData( + CommonFieldDataWithPlacement( PlacementData(Vector3.Zero, Vector3.Zero), PlanetSideEmpire.TR, 0 @@ -339,15 +462,23 @@ class ConverterTest extends Specification { obj.Health = 1 obj.Definition.Packet.ConstructorData(obj) match { case Success(pkt) => - pkt mustEqual TelepadDeployableData( + pkt mustEqual DroppedItemData( PlacementData(Vector3.Zero, Vector3.Zero), - PlanetSideEmpire.TR, - bops = false, - destroyed = false, - unk1 = 2, unk2 = true, - router_guid = PlanetSideGUID(1001), - owner_guid = PlanetSideGUID(5001), - unk3 = 87, unk4 = 12 + TelepadDeployableData( + CommonFieldData( + PlanetSideEmpire.TR, + bops = false, + alternate = false, + true, + None, + false, + None, + Some(1001), + PlanetSideGUID(5001) + ), + unk1 = 87, + unk2 = 12 + ) ) case _ => ko @@ -363,15 +494,23 @@ class ConverterTest extends Specification { obj.Health = 0 obj.Definition.Packet.ConstructorData(obj) match { case Success(pkt) => - pkt mustEqual TelepadDeployableData( + pkt mustEqual DroppedItemData( PlacementData(Vector3.Zero, Vector3.Zero), - PlanetSideEmpire.TR, - bops = false, - destroyed = true, - unk1 = 2, unk2 = true, - router_guid = PlanetSideGUID(1001), - owner_guid = PlanetSideGUID(0), - unk3 = 0, unk4 = 6 + TelepadDeployableData( + CommonFieldData( + PlanetSideEmpire.TR, + bops = false, + alternate = true, + true, + None, + false, + None, + Some(1001), + PlanetSideGUID(0) + ), + unk1 = 0, + unk2 = 6 + ) ) case _ => ko @@ -496,13 +635,13 @@ class ConverterTest extends Specification { val obj = LockerContainer() obj.Definition.Packet.DetailedConstructorData(obj) match { case Success(pkt) => - pkt mustEqual DetailedLockerContainerData(8, None) + pkt mustEqual DetailedLockerContainerData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), None) case _ => ko } obj.Definition.Packet.ConstructorData(obj) match { case Success(pkt) => - pkt mustEqual LockerContainerData(InventoryData(List.empty)) + pkt mustEqual LockerContainerData(None) case _ => ko } @@ -517,13 +656,13 @@ class ConverterTest extends Specification { obj.Definition.Packet.DetailedConstructorData(obj) match { case Success(pkt) => - pkt mustEqual DetailedLockerContainerData(8, InternalSlot(remote_electronics_kit.ObjectId, PlanetSideGUID(1), 0, DetailedREKData(8)) :: Nil) + pkt mustEqual DetailedLockerContainerData(8, InternalSlot(remote_electronics_kit.ObjectId, PlanetSideGUID(1), 0, DetailedREKData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, Some(false), None, PlanetSideGUID(0)))) :: Nil) case _ => ko } obj.Definition.Packet.ConstructorData(obj) match { case Success(pkt) => - pkt mustEqual LockerContainerData(InventoryData(InternalSlot(remote_electronics_kit.ObjectId, PlanetSideGUID(1), 0, REKData(8,0)) :: Nil)) + pkt mustEqual LockerContainerData(InventoryData(InternalSlot(remote_electronics_kit.ObjectId, PlanetSideGUID(1), 0, REKData(CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, Some(false), None, PlanetSideGUID(0)))) :: Nil)) case _ => ko } @@ -543,7 +682,7 @@ class ConverterTest extends Specification { obj.Definition.Packet.ConstructorData(obj) match { case Success(pkt) => - pkt mustEqual CommonTerminalData(PlanetSideEmpire.NEUTRAL) + pkt mustEqual CommonFieldData(PlanetSideEmpire.NEUTRAL)(false) case _ => ko } @@ -563,7 +702,7 @@ class ConverterTest extends Specification { obj.Definition.Packet.ConstructorData(obj) match { case Success(pkt) => - pkt mustEqual CommonTerminalData(PlanetSideEmpire.NEUTRAL) + pkt mustEqual CommonFieldData(PlanetSideEmpire.NEUTRAL)(false) case _ => ko } diff --git a/common/src/test/scala/objects/EquipmentSlotTest.scala b/common/src/test/scala/objects/EquipmentSlotTest.scala index 2741225a..08af787d 100644 --- a/common/src/test/scala/objects/EquipmentSlotTest.scala +++ b/common/src/test/scala/objects/EquipmentSlotTest.scala @@ -1,8 +1,8 @@ // Copyright (c) 2017 PSForever package objects -import net.psforever.objects.{EquipmentSlot, OffhandEquipmentSlot, Tool} -import net.psforever.objects.equipment.EquipmentSize +import net.psforever.objects.{OffhandEquipmentSlot, Tool} +import net.psforever.objects.equipment.{EquipmentSize, EquipmentSlot} import net.psforever.objects.GlobalDefinitions.{beamer, repeater, suppressor} import org.specs2.mutable._ diff --git a/common/src/test/scala/objects/ExoSuitTest.scala b/common/src/test/scala/objects/ExoSuitTest.scala index ba9a9123..c7db0ac8 100644 --- a/common/src/test/scala/objects/ExoSuitTest.scala +++ b/common/src/test/scala/objects/ExoSuitTest.scala @@ -1,7 +1,7 @@ // Copyright (c) 2017 PSForever package objects -import net.psforever.objects._ +import net.psforever.objects.definition.{ExoSuitDefinition, SpecialExoSuitDefinition} import net.psforever.objects.equipment._ import net.psforever.objects.inventory.InventoryTile import net.psforever.types.ExoSuitType diff --git a/common/src/test/scala/objects/PlayerTest.scala b/common/src/test/scala/objects/PlayerTest.scala index 4e4d367a..c1471800 100644 --- a/common/src/test/scala/objects/PlayerTest.scala +++ b/common/src/test/scala/objects/PlayerTest.scala @@ -3,9 +3,10 @@ package objects import net.psforever.objects.GlobalDefinitions._ import net.psforever.objects._ -import net.psforever.objects.definition.{ImplantDefinition, SimpleItemDefinition} +import net.psforever.objects.definition.{ImplantDefinition, SimpleItemDefinition, SpecialExoSuitDefinition} import net.psforever.objects.equipment.EquipmentSize import net.psforever.packet.game.PlanetSideGUID +import net.psforever.packet.game.objectcreate.{Cosmetics, PersonalStyle} import net.psforever.types._ import org.specs2.mutable._ @@ -521,6 +522,115 @@ class PlayerTest extends Specification { obj.UsingSpecial != test mustEqual true } + "start with a nonexistent cosmetic state" in { + TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5).PersonalStyleFeatures.isEmpty mustEqual true + } + + "will not gain cosmetic state if player does not have a certain amount of BEP" in { + val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5) + val obj = Player(avatar) + obj.PersonalStyleFeatures.isEmpty mustEqual true + val (a1, b1) = obj.AddToPersonalStyle(PersonalStyle.Beret) + a1.isEmpty mustEqual true + b1.isEmpty mustEqual true + obj.PersonalStyleFeatures.isEmpty mustEqual true + + avatar.BEP = 2286231 //BR24 + val (a2, b2) = obj.AddToPersonalStyle(PersonalStyle.Beret) + a2.isEmpty mustEqual true + b2 match { + case Some(c : Cosmetics) => + c.Styles mustEqual Set(PersonalStyle.Beret) + case _ => + ko + } + obj.PersonalStyleFeatures.isEmpty mustEqual false + } + + "will lose cosmetic state" in { + val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5) + val obj = Player(avatar) + avatar.BEP = 2286231 //BR24 + obj.AddToPersonalStyle(PersonalStyle.Beret) + obj.PersonalStyleFeatures.contains(Cosmetics(Set(PersonalStyle.Beret))) mustEqual true + val (a2, b2) = obj.RemoveFromPersonalStyle(PersonalStyle.Beret) + a2 match { + case Some(c : Cosmetics) => + c.Styles mustEqual Set(PersonalStyle.Beret) + case _ => + ko + } + b2 match { + case Some(c : Cosmetics) => + c.Styles mustEqual Set.empty + case _ => + ko + } + } + + "will not lose cosmetic state if the player doesn't have any cosmetic state to begin with" in { + val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5) + val obj = Player(avatar) + obj.PersonalStyleFeatures.isEmpty mustEqual true + val (a1, b1) = obj.RemoveFromPersonalStyle(PersonalStyle.Beret) + a1.isEmpty mustEqual true + b1.isEmpty mustEqual true + } + + "toggle helmet" in { + val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5) + val obj = Player(avatar) + avatar.BEP = 2286231 + obj.PersonalStyleFeatures.isEmpty mustEqual true + obj.ToggleHelmet + obj.PersonalStyleFeatures.contains(Cosmetics(Set(PersonalStyle.NoHelmet))) mustEqual true + obj.ToggleHelmet + obj.PersonalStyleFeatures.contains(Cosmetics()) mustEqual true + obj.ToggleHelmet + obj.PersonalStyleFeatures.contains(Cosmetics(Set(PersonalStyle.NoHelmet))) mustEqual true + } + + "toggle suglasses" in { + val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5) + val obj = Player(avatar) + avatar.BEP = 2286231 + obj.PersonalStyleFeatures.isEmpty mustEqual true + obj.ToggleShades + obj.PersonalStyleFeatures.contains(Cosmetics(Set(PersonalStyle.Sunglasses))) mustEqual true + obj.ToggleShades + obj.PersonalStyleFeatures.contains(Cosmetics()) mustEqual true + obj.ToggleShades + obj.PersonalStyleFeatures.contains(Cosmetics(Set(PersonalStyle.Sunglasses))) mustEqual true + } + + "toggle earpiece" in { + val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5) + val obj = Player(avatar) + avatar.BEP = 2286231 + obj.PersonalStyleFeatures.isEmpty mustEqual true + obj.ToggleEarpiece + obj.PersonalStyleFeatures.contains(Cosmetics(Set(PersonalStyle.Earpiece))) mustEqual true + obj.ToggleEarpiece + obj.PersonalStyleFeatures.contains(Cosmetics()) mustEqual true + obj.ToggleEarpiece + obj.PersonalStyleFeatures.contains(Cosmetics(Set(PersonalStyle.Earpiece))) mustEqual true + } + + "toggle between brimmed cap and beret" in { + val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5) + val obj = Player(avatar) + avatar.BEP = 2286231 + obj.PersonalStyleFeatures.isEmpty mustEqual true + obj.ToggleHat + obj.PersonalStyleFeatures.contains(Cosmetics(Set(PersonalStyle.BrimmedCap))) mustEqual true + obj.ToggleHat + obj.PersonalStyleFeatures.contains(Cosmetics(Set(PersonalStyle.Beret))) mustEqual true + obj.ToggleHat + obj.PersonalStyleFeatures.contains(Cosmetics()) mustEqual true + obj.ToggleHat + obj.PersonalStyleFeatures.contains(Cosmetics(Set(PersonalStyle.BrimmedCap))) mustEqual true + } + "toString" in { val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5) obj.toString mustEqual "TR Chord 0/100 0/50" diff --git a/common/src/test/scala/objects/UtilityTest.scala b/common/src/test/scala/objects/UtilityTest.scala index 13920cb5..df70ca36 100644 --- a/common/src/test/scala/objects/UtilityTest.scala +++ b/common/src/test/scala/objects/UtilityTest.scala @@ -63,7 +63,7 @@ class UtilityTest extends Specification { obj().Owner = veh //hack obj().GUID = PlanetSideGUID(1) - val msg = obj().asInstanceOf[Terminal].Buy( + val msg = obj().asInstanceOf[Terminal].Request( Player(Avatar("TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)), ItemTransactionMessage(PlanetSideGUID(853), TransactionType.Buy, 0, "router_telepad", 0, PlanetSideGUID(0)) ) diff --git a/common/src/test/scala/objects/terminal/AirVehicleTerminalTest.scala b/common/src/test/scala/objects/terminal/AirVehicleTerminalTest.scala deleted file mode 100644 index 8ea5ae6a..00000000 --- a/common/src/test/scala/objects/terminal/AirVehicleTerminalTest.scala +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2017 PSForever -package objects.terminal - -import akka.actor.ActorRef -import net.psforever.objects.serverobject.structures.{Building, StructureType} -import net.psforever.objects.{Avatar, GlobalDefinitions, Player} -import net.psforever.objects.serverobject.terminals.Terminal -import net.psforever.objects.zones.Zone -import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID} -import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire, TransactionType} -import org.specs2.mutable.Specification - -class AirVehicleTerminalTest extends Specification { - "Air_Vehicle_Terminal" should { - val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) - val terminal = Terminal(GlobalDefinitions.air_vehicle_terminal) - terminal.Owner = new Building(0, Zone.Nowhere, StructureType.Building) - terminal.Owner.Faction = PlanetSideEmpire.TR - - "construct" in { - val terminal = Terminal(GlobalDefinitions.air_vehicle_terminal) - terminal.Actor mustEqual ActorRef.noSender - } - - "player can buy a reaver ('lightgunship')" in { - val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "lightgunship", 0, PlanetSideGUID(0)) - - val reply = terminal.Request(player, msg) - reply.isInstanceOf[Terminal.BuyVehicle] mustEqual true - val reply2 = reply.asInstanceOf[Terminal.BuyVehicle] - reply2.vehicle.Definition mustEqual GlobalDefinitions.lightgunship - reply2.weapons mustEqual Nil - reply2.inventory.length mustEqual 6 - reply2.inventory.head.obj.Definition mustEqual GlobalDefinitions.reaver_rocket - reply2.inventory(1).obj.Definition mustEqual GlobalDefinitions.reaver_rocket - reply2.inventory(2).obj.Definition mustEqual GlobalDefinitions.reaver_rocket - reply2.inventory(3).obj.Definition mustEqual GlobalDefinitions.reaver_rocket - reply2.inventory(4).obj.Definition mustEqual GlobalDefinitions.bullet_20mm - reply2.inventory(5).obj.Definition mustEqual GlobalDefinitions.bullet_20mm - } - - "player can not buy a fake vehicle ('reaver')" in { - val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "reaver", 0, PlanetSideGUID(0)) - - terminal.Request(player, msg) mustEqual Terminal.NoDeal() - } - } -} diff --git a/common/src/test/scala/objects/terminal/CertTerminalTest.scala b/common/src/test/scala/objects/terminal/CertTerminalTest.scala deleted file mode 100644 index 5676d327..00000000 --- a/common/src/test/scala/objects/terminal/CertTerminalTest.scala +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2017 PSForever -package objects.terminal - -import akka.actor.ActorRef -import net.psforever.objects.serverobject.structures.{Building, StructureType} -import net.psforever.objects.serverobject.terminals.Terminal -import net.psforever.objects.zones.Zone -import net.psforever.objects.{Avatar, GlobalDefinitions, Player} -import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID} -import net.psforever.types._ -import org.specs2.mutable.Specification - -class CertTerminalTest extends Specification { - "Cert_Terminal" should { - val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) - val terminal = Terminal(GlobalDefinitions.cert_terminal) - terminal.Owner = new Building(0, Zone.Nowhere, StructureType.Building) - terminal.Owner.Faction = PlanetSideEmpire.TR - - "construct" in { - val terminal = Terminal(GlobalDefinitions.cert_terminal) - terminal.Actor mustEqual ActorRef.noSender - } - - "player can learn a certification ('medium_assault')" in { - val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Learn, 0, "medium_assault", 0, PlanetSideGUID(0)) - terminal.Request(player, msg) mustEqual Terminal.LearnCertification(CertificationType.MediumAssault) - } - - "player can not learn a fake certification ('juggling')" in { - val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Learn, 0, "juggling", 0, PlanetSideGUID(0)) - - terminal.Request(player, msg) mustEqual Terminal.NoDeal() - } - - "player can forget a certification ('medium_assault')" in { - val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Sell, 0, "medium_assault", 0, PlanetSideGUID(0)) - - terminal.Request(player, msg) mustEqual Terminal.SellCertification(CertificationType.MediumAssault) - } - - "player can not forget a fake certification ('juggling')" in { - val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Sell, 0, "juggling", 0, PlanetSideGUID(0)) - - terminal.Request(player, msg) mustEqual Terminal.NoDeal() - } - } -} diff --git a/common/src/test/scala/objects/terminal/DropshipVehicleTerminalTest.scala b/common/src/test/scala/objects/terminal/DropshipVehicleTerminalTest.scala deleted file mode 100644 index 3ad3df33..00000000 --- a/common/src/test/scala/objects/terminal/DropshipVehicleTerminalTest.scala +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2017 PSForever -package objects.terminal - -import akka.actor.ActorRef -import net.psforever.objects.serverobject.structures.{Building, StructureType} -import net.psforever.objects.{Avatar, GlobalDefinitions, Player} -import net.psforever.objects.serverobject.terminals.Terminal -import net.psforever.objects.zones.Zone -import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID} -import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire, TransactionType} -import org.specs2.mutable.Specification - -class DropshipVehicleTerminalTest extends Specification { - "Dropship_Vehicle_Terminal" should { - val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) - val terminal = Terminal(GlobalDefinitions.dropship_vehicle_terminal) - terminal.Owner = new Building(0, Zone.Nowhere, StructureType.Building) - terminal.Owner.Faction = PlanetSideEmpire.TR - - "construct" in { - val terminal = Terminal(GlobalDefinitions.dropship_vehicle_terminal) - terminal.Actor mustEqual ActorRef.noSender - } - - "player can buy a galaxy ('dropship')" in { - val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "dropship", 0, PlanetSideGUID(0)) - - val reply = terminal.Request(player, msg) - reply.isInstanceOf[Terminal.BuyVehicle] mustEqual true - val reply2 = reply.asInstanceOf[Terminal.BuyVehicle] - reply2.vehicle.Definition mustEqual GlobalDefinitions.dropship - reply2.weapons mustEqual Nil - reply2.inventory.length mustEqual 12 - reply2.inventory.head.obj.Definition mustEqual GlobalDefinitions.bullet_20mm - reply2.inventory(1).obj.Definition mustEqual GlobalDefinitions.bullet_20mm - reply2.inventory(2).obj.Definition mustEqual GlobalDefinitions.bullet_20mm - reply2.inventory(3).obj.Definition mustEqual GlobalDefinitions.bullet_20mm - reply2.inventory(4).obj.Definition mustEqual GlobalDefinitions.bullet_20mm - reply2.inventory(5).obj.Definition mustEqual GlobalDefinitions.bullet_20mm - reply2.inventory(6).obj.Definition mustEqual GlobalDefinitions.bullet_20mm - reply2.inventory(7).obj.Definition mustEqual GlobalDefinitions.bullet_20mm - reply2.inventory(8).obj.Definition mustEqual GlobalDefinitions.bullet_20mm - reply2.inventory(9).obj.Definition mustEqual GlobalDefinitions.bullet_20mm - reply2.inventory(10).obj.Definition mustEqual GlobalDefinitions.bullet_20mm - reply2.inventory(11).obj.Definition mustEqual GlobalDefinitions.bullet_20mm - } - - "player can not buy a fake vehicle ('galaxy')" in { - val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "galaxy", 0, PlanetSideGUID(0)) - - terminal.Request(player, msg) mustEqual Terminal.NoDeal() - } - } -} diff --git a/common/src/test/scala/objects/terminal/GroundVehicleTerminalTest.scala b/common/src/test/scala/objects/terminal/GroundVehicleTerminalTest.scala deleted file mode 100644 index 680d4752..00000000 --- a/common/src/test/scala/objects/terminal/GroundVehicleTerminalTest.scala +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2017 PSForever -package objects.terminal - -import akka.actor.ActorRef -import net.psforever.objects.serverobject.structures.{Building, StructureType} -import net.psforever.objects.{Avatar, GlobalDefinitions, Player} -import net.psforever.objects.serverobject.terminals.Terminal -import net.psforever.objects.zones.Zone -import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID} -import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire, TransactionType} -import org.specs2.mutable.Specification - -class GroundVehicleTerminalTest extends Specification { - "Ground_Vehicle_Terminal" should { - val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) - val terminal = Terminal(GlobalDefinitions.ground_vehicle_terminal) - terminal.Owner = new Building(0, Zone.Nowhere, StructureType.Building) - terminal.Owner.Faction = PlanetSideEmpire.TR - - "construct" in { - val terminal = Terminal(GlobalDefinitions.ground_vehicle_terminal) - terminal.Actor mustEqual ActorRef.noSender - } - - "player can buy a harasser ('two_man_assault_buggy')" in { - val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "two_man_assault_buggy", 0, PlanetSideGUID(0)) - - val reply = terminal.Request(player, msg) - reply.isInstanceOf[Terminal.BuyVehicle] mustEqual true - val reply2 = reply.asInstanceOf[Terminal.BuyVehicle] - reply2.vehicle.Definition mustEqual GlobalDefinitions.two_man_assault_buggy - reply2.weapons mustEqual Nil - reply2.inventory.length mustEqual 6 - reply2.inventory.head.obj.Definition mustEqual GlobalDefinitions.bullet_12mm - reply2.inventory(1).obj.Definition mustEqual GlobalDefinitions.bullet_12mm - reply2.inventory(2).obj.Definition mustEqual GlobalDefinitions.bullet_12mm - reply2.inventory(3).obj.Definition mustEqual GlobalDefinitions.bullet_12mm - reply2.inventory(4).obj.Definition mustEqual GlobalDefinitions.bullet_12mm - reply2.inventory(5).obj.Definition mustEqual GlobalDefinitions.bullet_12mm - } - - "player can not buy a fake vehicle ('harasser')" in { - val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "harasser", 0, PlanetSideGUID(0)) - - terminal.Request(player, msg) mustEqual Terminal.NoDeal() - } - } -} diff --git a/common/src/test/scala/objects/terminal/ImplantTerminalInterfaceTest.scala b/common/src/test/scala/objects/terminal/ImplantTerminalInterfaceTest.scala deleted file mode 100644 index 461fef8f..00000000 --- a/common/src/test/scala/objects/terminal/ImplantTerminalInterfaceTest.scala +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2017 PSForever -package objects.terminal - -import akka.actor.ActorRef -import net.psforever.objects.serverobject.structures.{Building, StructureType} -import net.psforever.objects.{Avatar, GlobalDefinitions, Player} -import net.psforever.objects.serverobject.terminals.Terminal -import net.psforever.objects.zones.Zone -import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID} -import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire, TransactionType} -import org.specs2.mutable.Specification - -class ImplantTerminalInterfaceTest extends Specification { - "Implant_Terminal_Interface" should { - val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) - val terminal = Terminal(GlobalDefinitions.implant_terminal_interface) - terminal.Owner = new Building(0, Zone.Nowhere, StructureType.Building) - terminal.Owner.Faction = PlanetSideEmpire.TR - - "construct" in { - val terminal = Terminal(GlobalDefinitions.implant_terminal_interface) - terminal.Actor mustEqual ActorRef.noSender - } - - "player can learn an implant ('darklight_vision')" in { - val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "darklight_vision", 0, PlanetSideGUID(0)) - - val reply = terminal.Request(player, msg) - reply.isInstanceOf[Terminal.LearnImplant] mustEqual true - val reply2 = reply.asInstanceOf[Terminal.LearnImplant] - reply2.implant mustEqual GlobalDefinitions.darklight_vision - } - - "player can not learn a fake implant ('aimbot')" in { - val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "aimbot", 0, PlanetSideGUID(0)) - - terminal.Request(player, msg) mustEqual Terminal.NoDeal() - } - - "player can surrender an implant ('darklight_vision')" in { - val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Sell, 0, "darklight_vision", 0, PlanetSideGUID(0)) - - val reply = terminal.Request(player, msg) - reply.isInstanceOf[Terminal.SellImplant] mustEqual true - val reply2 = reply.asInstanceOf[Terminal.SellImplant] - reply2.implant mustEqual GlobalDefinitions.darklight_vision - } - - "player can not surrender a fake implant ('aimbot')" in { - val terminal = Terminal(GlobalDefinitions.implant_terminal_interface) - val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Sell, 0, "aimbot", 0, PlanetSideGUID(0)) - - terminal.Request(player, msg) mustEqual Terminal.NoDeal() - } - } -} diff --git a/common/src/test/scala/objects/terminal/ImplantTerminalMechTest.scala b/common/src/test/scala/objects/terminal/ImplantTerminalMechTest.scala index 68e04221..6c324950 100644 --- a/common/src/test/scala/objects/terminal/ImplantTerminalMechTest.scala +++ b/common/src/test/scala/objects/terminal/ImplantTerminalMechTest.scala @@ -28,7 +28,7 @@ class ImplantTerminalMechTest extends Specification { } } - "VehicleSpawnPad" should { + "Implant_Terminal_Mech" should { "construct" in { val obj = ImplantTerminalMech(GlobalDefinitions.implant_terminal_mech) obj.Actor mustEqual ActorRef.noSender diff --git a/common/src/test/scala/objects/terminal/MatrixTerminalTest.scala b/common/src/test/scala/objects/terminal/MatrixTerminalTest.scala index 15c3e7e4..b8091205 100644 --- a/common/src/test/scala/objects/terminal/MatrixTerminalTest.scala +++ b/common/src/test/scala/objects/terminal/MatrixTerminalTest.scala @@ -1,7 +1,6 @@ // Copyright (c) 2017 PSForever package objects.terminal -import akka.actor.ActorRef import net.psforever.objects.serverobject.terminals.{MatrixTerminalDefinition, Terminal} import net.psforever.objects.{Avatar, GlobalDefinitions, Player, Vehicle} import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID} @@ -10,59 +9,22 @@ import org.specs2.mutable.Specification class MatrixTerminalTest extends Specification { "MatrixTerminal" should { - "define (a)" in { + "define" in { val a = new MatrixTerminalDefinition(517) a.ObjectId mustEqual 517 - a.Name mustEqual "matrix_terminala" } - "define (b)" in { - val b = new MatrixTerminalDefinition(518) - b.ObjectId mustEqual 518 - b.Name mustEqual "matrix_terminalb" + "creation" in { + Terminal(new MatrixTerminalDefinition(518)) + ok } - "define (c)" in { - val b = new MatrixTerminalDefinition(519) - b.ObjectId mustEqual 519 - b.Name mustEqual "matrix_terminalc" - } - - "define (d)" in { - val b = new MatrixTerminalDefinition(812) - b.ObjectId mustEqual 812 - b.Name mustEqual "spawn_terminal" - } - - "define (invalid)" in { - var id : Int = (math.random * Int.MaxValue).toInt - if(id == 517) { - id += 3 - } - else if(id == 518) { - id += 2 - } - else if(id == 519 | id == 812) { - id += 1 - } - - new MatrixTerminalDefinition(id) must throwA[IllegalArgumentException] - } - } - - "Matrix_Terminal" should { - val terminal = Terminal(GlobalDefinitions.matrix_terminalc) - terminal.Owner = Vehicle(GlobalDefinitions.quadstealth) - terminal.Owner.Faction = PlanetSideEmpire.TR - - "construct" in { - terminal.Actor mustEqual ActorRef.noSender - } - - "player can not buy (anything)" in { + "invalid message" in { val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "lite_armor", 0, PlanetSideGUID(0)) - + val terminal = Terminal(new MatrixTerminalDefinition(519)) + terminal.Owner = Vehicle(GlobalDefinitions.quadstealth) + terminal.Owner.Faction = PlanetSideEmpire.TR terminal.Request(player, msg) mustEqual Terminal.NoDeal() } } diff --git a/common/src/test/scala/objects/terminal/OrderTerminalABTest.scala b/common/src/test/scala/objects/terminal/OrderTerminalABTest.scala deleted file mode 100644 index fcdaa498..00000000 --- a/common/src/test/scala/objects/terminal/OrderTerminalABTest.scala +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2017 PSForever -package objects.terminal - -import akka.actor.ActorRef -import net.psforever.objects.serverobject.structures.{Building, StructureType} -import net.psforever.objects.serverobject.terminals.{OrderTerminalABDefinition, Terminal} -import net.psforever.objects.zones.Zone -import net.psforever.objects.{Avatar, GlobalDefinitions, Player} -import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID} -import net.psforever.types._ -import org.specs2.mutable.Specification - -class OrderTerminalABTest extends Specification { - "OrderTerminalAB" should { - "define (a)" in { - val a = new OrderTerminalABDefinition(613) - a.ObjectId mustEqual 613 - a.Name mustEqual "order_terminala" - } - - "define (b)" in { - val b = new OrderTerminalABDefinition(614) - b.ObjectId mustEqual 614 - b.Name mustEqual "order_terminalb" - } - - "define (invalid)" in { - var id : Int = (math.random * Int.MaxValue).toInt - if(id == 613) { - id += 2 - } - else if(id == 614) { - id += 1 - } - - new OrderTerminalABDefinition(id) must throwA[IllegalArgumentException] - } - } - - "Order_Terminal" should { - val terminal = Terminal(GlobalDefinitions.order_terminala) - terminal.Owner = new Building(0, Zone.Nowhere, StructureType.Building) - terminal.Owner.Faction = PlanetSideEmpire.TR - - "construct" in { - terminal.Actor mustEqual ActorRef.noSender - } - - "player can buy different armor ('lite_armor')" in { - val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) - val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "lite_armor", 0, PlanetSideGUID(0)) - - terminal.Request(player, msg) mustEqual Terminal.BuyExosuit(ExoSuitType.Agile) - } - - "player can buy max armor ('trhev_antiaircraft')" in { - val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) - val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "trhev_antiaircraft", 0, PlanetSideGUID(0)) - - terminal.Request(player, msg) mustEqual Terminal.NoDeal() - } - //TODO loudout tests - - "player can not load max loadout" in { - val avatar = Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute) - val player = Player(avatar) - avatar.SaveLoadout(player, "test1", 0) - player.ExoSuit = ExoSuitType.MAX - avatar.SaveLoadout(player, "test2", 1) - - val msg1 = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Loadout, 4, "", 0, PlanetSideGUID(0)) - terminal.Request(player, msg1) mustEqual Terminal.InfantryLoadout(ExoSuitType.Standard, 0, Nil, Nil) - - val msg2 = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Loadout, 4, "", 1, PlanetSideGUID(0)) - terminal.Request(player, msg2) mustEqual Terminal.NoDeal() - } - } -} diff --git a/common/src/test/scala/objects/terminal/OrderTerminalTest.scala b/common/src/test/scala/objects/terminal/OrderTerminalTest.scala index ccdc7531..472825a6 100644 --- a/common/src/test/scala/objects/terminal/OrderTerminalTest.scala +++ b/common/src/test/scala/objects/terminal/OrderTerminalTest.scala @@ -1,92 +1,95 @@ // Copyright (c) 2017 PSForever package objects.terminal -import akka.actor.ActorRef import net.psforever.objects.serverobject.structures.{Building, StructureType} import net.psforever.objects.serverobject.terminals.Terminal import net.psforever.objects.zones.Zone -import net.psforever.objects.{AmmoBox, Avatar, GlobalDefinitions, Player, Tool} +import net.psforever.objects._ import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID} import net.psforever.types._ import org.specs2.mutable.Specification class OrderTerminalTest extends Specification { - "Order_Terminal" should { - val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) - val terminal = Terminal(GlobalDefinitions.order_terminal) - terminal.Owner = new Building(0, Zone.Nowhere, StructureType.Building) - terminal.Owner.Faction = PlanetSideEmpire.TR + val avatar = Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute) + val player = Player(avatar) - "construct" in { - val terminal = Terminal(GlobalDefinitions.order_terminal) - terminal.Actor mustEqual ActorRef.noSender + val building = new Building(0, Zone.Nowhere, StructureType.Building) + building.Faction = PlanetSideEmpire.TR + val infantryTerminal = Terminal(GlobalDefinitions.order_terminal) + infantryTerminal.Owner = building + + "General terminal behavior" should { + "player can not buy equipment from the wrong page ('9mmbullet_AP', page 10)" in { + val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "9mmbullet_AP", 0, PlanetSideGUID(0)) + + infantryTerminal.Request(player, msg) mustEqual Terminal.NoDeal() } + } + "Infantry Order Terminal" should { "player can buy a box of ammunition ('9mmbullet_AP')" in { val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "9mmbullet_AP", 0, PlanetSideGUID(0)) - val reply = terminal.Request(player, msg) + val reply = infantryTerminal.Request(player, msg) reply.isInstanceOf[Terminal.BuyEquipment] mustEqual true val reply2 = reply.asInstanceOf[Terminal.BuyEquipment] reply2.item.isInstanceOf[AmmoBox] mustEqual true reply2.item.asInstanceOf[AmmoBox].Definition mustEqual GlobalDefinitions.bullet_9mm_AP - reply2.item.asInstanceOf[AmmoBox].Capacity mustEqual 50 } "player can buy a weapon ('suppressor')" in { val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "suppressor", 0, PlanetSideGUID(0)) - val reply = terminal.Request(player, msg) + val reply = infantryTerminal.Request(player, msg) reply.isInstanceOf[Terminal.BuyEquipment] mustEqual true val reply2 = reply.asInstanceOf[Terminal.BuyEquipment] reply2.item.isInstanceOf[Tool] mustEqual true reply2.item.asInstanceOf[Tool].Definition mustEqual GlobalDefinitions.suppressor } - "player can buy a box of vehicle ammunition ('105mmbullet')" in { - val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 3, "105mmbullet", 0, PlanetSideGUID(0)) - val reply = terminal.Request(player, msg) + "player can buy different armor ('lite_armor')" in { + val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "lite_armor", 0, PlanetSideGUID(0)) + + infantryTerminal.Request(player, msg) mustEqual Terminal.BuyExosuit(ExoSuitType.Agile) + } + + "player can buy a box of ammunition belonging to a special armor type ('dualcycler_ammo')" in { + val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "dualcycler_ammo", 0, PlanetSideGUID(0)) + val reply = infantryTerminal.Request(player, msg) reply.isInstanceOf[Terminal.BuyEquipment] mustEqual true val reply2 = reply.asInstanceOf[Terminal.BuyEquipment] reply2.item.isInstanceOf[AmmoBox] mustEqual true - reply2.item.asInstanceOf[AmmoBox].Definition mustEqual GlobalDefinitions.bullet_105mm - reply2.item.asInstanceOf[AmmoBox].Capacity mustEqual 100 + reply2.item.asInstanceOf[AmmoBox].Definition mustEqual GlobalDefinitions.dualcycler_ammo } "player can buy a support tool ('bank')" in { val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 2, "bank", 0, PlanetSideGUID(0)) - val reply = terminal.Request(player, msg) + val reply = infantryTerminal.Request(player, msg) reply.isInstanceOf[Terminal.BuyEquipment] mustEqual true val reply2 = reply.asInstanceOf[Terminal.BuyEquipment] reply2.item.isInstanceOf[Tool] mustEqual true reply2.item.asInstanceOf[Tool].Definition mustEqual GlobalDefinitions.bank } - "player can buy different armor ('lite_armor')" in { - val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "lite_armor", 0, PlanetSideGUID(0)) - - terminal.Request(player, msg) mustEqual Terminal.BuyExosuit(ExoSuitType.Agile) + "player can buy a box of vehicle ammunition ('105mmbullet')" in { + val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 3, "105mmbullet", 0, PlanetSideGUID(0)) + val reply = infantryTerminal.Request(player, msg) + reply.isInstanceOf[Terminal.BuyEquipment] mustEqual true + val reply2 = reply.asInstanceOf[Terminal.BuyEquipment] + reply2.item.isInstanceOf[AmmoBox] mustEqual true + reply2.item.asInstanceOf[AmmoBox].Definition mustEqual GlobalDefinitions.bullet_105mm } "player can not buy fake equipment ('sabot')" in { val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "sabot", 0, PlanetSideGUID(0)) - - terminal.Request(player, msg) mustEqual Terminal.NoDeal() - } - - "player can not buy equipment from the wrong page ('9mmbullet_AP', page 1)" in { - val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "9mmbullet_AP", 0, PlanetSideGUID(0)) - - terminal.Request(player, msg) mustEqual Terminal.NoDeal() + infantryTerminal.Request(player, msg) mustEqual Terminal.NoDeal() } "player can retrieve an infantry loadout" in { - val avatar = Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute) - val player2 = Player(avatar) - player2.ExoSuit = ExoSuitType.Agile - player2.Slot(0).Equipment = Tool(GlobalDefinitions.beamer) - player2.Slot(6).Equipment = Tool(GlobalDefinitions.beamer) - avatar.SaveLoadout(player2, "test", 0) + player.ExoSuit = ExoSuitType.Agile + player.Slot(0).Equipment = Tool(GlobalDefinitions.beamer) + player.Slot(6).Equipment = Tool(GlobalDefinitions.beamer) + avatar.SaveLoadout(player, "test", 0) - val msg = terminal.Request(player2, ItemTransactionMessage(PlanetSideGUID(10), TransactionType.Loadout, 4, "", 0, PlanetSideGUID(0))) + val msg = infantryTerminal.Request(player, ItemTransactionMessage(PlanetSideGUID(10), TransactionType.Loadout, 4, "", 0, PlanetSideGUID(0))) msg.isInstanceOf[Terminal.InfantryLoadout] mustEqual true val loadout = msg.asInstanceOf[Terminal.InfantryLoadout] loadout.exosuit mustEqual ExoSuitType.Agile @@ -98,28 +101,120 @@ class OrderTerminalTest extends Specification { loadout.inventory.head.start mustEqual 6 } - "player can not retrieve an infantry loadout from the wrong page" in { - val avatar = Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute) - val player2 = Player(avatar) - player2.ExoSuit = ExoSuitType.Agile - player2.Slot(0).Equipment = Tool(GlobalDefinitions.beamer) - player2.Slot(6).Equipment = Tool(GlobalDefinitions.beamer) - avatar.SaveLoadout(player2, "test", 0) - - val msg = terminal.Request(player2, ItemTransactionMessage(PlanetSideGUID(10), TransactionType.Loadout, 3, "", 0, PlanetSideGUID(0))) //page 3 - msg.isInstanceOf[Terminal.NoDeal] mustEqual true - } - "player can not retrieve an infantry loadout from the wrong line" in { - val avatar = Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute) - val player2 = Player(avatar) - player2.ExoSuit = ExoSuitType.Agile - player2.Slot(0).Equipment = Tool(GlobalDefinitions.beamer) - player2.Slot(6).Equipment = Tool(GlobalDefinitions.beamer) - avatar.SaveLoadout(player2, "test", 0) - - val msg = terminal.Request(player2, ItemTransactionMessage(PlanetSideGUID(10), TransactionType.Loadout, 4, "", 1, PlanetSideGUID(0))) + val msg = infantryTerminal.Request(player, ItemTransactionMessage(PlanetSideGUID(10), TransactionType.Loadout, 4, "", 1, PlanetSideGUID(0))) msg.isInstanceOf[Terminal.NoDeal] mustEqual true } } + + "Vehicle Terminal" should { + val terminal = Terminal(GlobalDefinitions.ground_vehicle_terminal) + terminal.Owner = building + + "player can spawn a vehicle and its default trunk contents" in { + val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 46769, "quadassault", 0, PlanetSideGUID(0)) + terminal.Request(player, msg) match { + case Terminal.BuyVehicle(vehicle, weapons, trunk) => + vehicle.Definition mustEqual GlobalDefinitions.quadassault + + weapons.size mustEqual 0 //note: vehicles never have custom weapons using the default loadout + + trunk.size mustEqual 4 + trunk.head.obj.Definition mustEqual GlobalDefinitions.bullet_12mm + trunk(1).obj.Definition mustEqual GlobalDefinitions.bullet_12mm + trunk(2).obj.Definition mustEqual GlobalDefinitions.bullet_12mm + trunk(3).obj.Definition mustEqual GlobalDefinitions.bullet_12mm + case _ => + ko + } + } + + "player can not spawn a fake vehicle ('harasser')" in { + val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 46769, "harasser", 0, PlanetSideGUID(0)) + terminal.Request(player, msg) mustEqual Terminal.NoDeal() + } + + "player can retrieve a vehicle loadout" in { + val fury = Vehicle(GlobalDefinitions.fury) + fury.Slot(30).Equipment = AmmoBox(GlobalDefinitions.hellfire_ammo) + avatar.SaveLoadout(fury, "test", 10) + + val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Loadout, 4, "test", 0, PlanetSideGUID(0)) + terminal.Request(player, msg) match { + case Terminal.VehicleLoadout(definition, weapons, trunk) => + definition mustEqual GlobalDefinitions.fury + + weapons.size mustEqual 1 + weapons.head.obj.Definition mustEqual GlobalDefinitions.fury_weapon_systema + + trunk.size mustEqual 1 + trunk.head.obj.Definition mustEqual GlobalDefinitions.hellfire_ammo + case _ => + ko + } + + ok + } + } + + "Certification Terminal" should { + val terminal = Terminal(GlobalDefinitions.cert_terminal) + terminal.Owner = building + + "player can learn a certification ('medium_assault')" in { + val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Learn, 0, "medium_assault", 0, PlanetSideGUID(0)) + terminal.Request(player, msg) mustEqual Terminal.LearnCertification(CertificationType.MediumAssault) + } + + "player can not learn a fake certification ('juggling')" in { + val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Learn, 0, "juggling", 0, PlanetSideGUID(0)) + terminal.Request(player, msg) mustEqual Terminal.NoDeal() + } + + "player can forget a certification ('medium_assault')" in { + val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Sell, 0, "medium_assault", 0, PlanetSideGUID(0)) + terminal.Request(player, msg) mustEqual Terminal.SellCertification(CertificationType.MediumAssault) + } + + "player can not forget a fake certification ('juggling')" in { + val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Sell, 0, "juggling", 0, PlanetSideGUID(0)) + terminal.Request(player, msg) mustEqual Terminal.NoDeal() + } + } + + "Implant_Terminal_Interface" should { + val terminal = Terminal(GlobalDefinitions.implant_terminal_interface) + terminal.Owner = building + + "player can learn an implant ('darklight_vision')" in { + val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "darklight_vision", 0, PlanetSideGUID(0)) + + val reply = terminal.Request(player, msg) + reply.isInstanceOf[Terminal.LearnImplant] mustEqual true + val reply2 = reply.asInstanceOf[Terminal.LearnImplant] + reply2.implant mustEqual GlobalDefinitions.darklight_vision + } + + "player can not learn a fake implant ('aimbot')" in { + val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "aimbot", 0, PlanetSideGUID(0)) + + terminal.Request(player, msg) mustEqual Terminal.NoDeal() + } + + "player can un-learn an implant ('darklight_vision')" in { + val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Sell, 0, "darklight_vision", 0, PlanetSideGUID(0)) + + val reply = terminal.Request(player, msg) + reply.isInstanceOf[Terminal.SellImplant] mustEqual true + val reply2 = reply.asInstanceOf[Terminal.SellImplant] + reply2.implant mustEqual GlobalDefinitions.darklight_vision + } + + "player can not un-learn a fake implant ('aimbot')" in { + val terminal = Terminal(GlobalDefinitions.implant_terminal_interface) + val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Sell, 0, "aimbot", 0, PlanetSideGUID(0)) + + terminal.Request(player, msg) mustEqual Terminal.NoDeal() + } + } } diff --git a/common/src/test/scala/objects/terminal/TerminalControlTest.scala b/common/src/test/scala/objects/terminal/TerminalControlTest.scala index ed5c0e1f..69e192bb 100644 --- a/common/src/test/scala/objects/terminal/TerminalControlTest.scala +++ b/common/src/test/scala/objects/terminal/TerminalControlTest.scala @@ -80,7 +80,7 @@ class CertTerminalControl3Test extends ActorTest { class VehicleTerminalControl1Test extends ActorTest { "TerminalControl can be used to buy a vehicle ('two_man_assault_buggy')" in { val (player, terminal) = TerminalControlTest.SetUpAgents(GlobalDefinitions.ground_vehicle_terminal, PlanetSideEmpire.TR) - val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "two_man_assault_buggy", 0, PlanetSideGUID(0)) + val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 46769, "two_man_assault_buggy", 0, PlanetSideGUID(0)) terminal.Actor ! Terminal.Request(player, msg) val reply = receiveOne(Duration.create(500, "ms")) diff --git a/common/src/test/scala/objects/terminal/VehicleTerminalCombinedTest.scala b/common/src/test/scala/objects/terminal/VehicleTerminalCombinedTest.scala deleted file mode 100644 index b6edd741..00000000 --- a/common/src/test/scala/objects/terminal/VehicleTerminalCombinedTest.scala +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2017 PSForever -package objects.terminal - -import akka.actor.ActorRef -import net.psforever.objects.serverobject.structures.{Building, StructureType} -import net.psforever.objects.{Avatar, GlobalDefinitions, Player} -import net.psforever.objects.serverobject.terminals.Terminal -import net.psforever.objects.zones.Zone -import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID} -import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire, TransactionType} -import org.specs2.mutable.Specification - -class VehicleTerminalCombinedTest extends Specification { - "Ground_Vehicle_Terminal" should { - val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) - val terminal = Terminal(GlobalDefinitions.vehicle_terminal_combined) - terminal.Owner = new Building(0, Zone.Nowhere, StructureType.Building) - terminal.Owner.Faction = PlanetSideEmpire.TR - - "construct" in { - val terminal = Terminal(GlobalDefinitions.vehicle_terminal_combined) - terminal.Actor mustEqual ActorRef.noSender - } - - "player can buy a ground vehicle, the harasser ('two_man_assault_buggy')" in { - val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "two_man_assault_buggy", 0, PlanetSideGUID(0)) - - val reply = terminal.Request(player, msg) - reply.isInstanceOf[Terminal.BuyVehicle] mustEqual true - val reply2 = reply.asInstanceOf[Terminal.BuyVehicle] - reply2.vehicle.Definition mustEqual GlobalDefinitions.two_man_assault_buggy - reply2.weapons mustEqual Nil - reply2.inventory.length mustEqual 6 - reply2.inventory.head.obj.Definition mustEqual GlobalDefinitions.bullet_12mm - reply2.inventory(1).obj.Definition mustEqual GlobalDefinitions.bullet_12mm - reply2.inventory(2).obj.Definition mustEqual GlobalDefinitions.bullet_12mm - reply2.inventory(3).obj.Definition mustEqual GlobalDefinitions.bullet_12mm - reply2.inventory(4).obj.Definition mustEqual GlobalDefinitions.bullet_12mm - reply2.inventory(5).obj.Definition mustEqual GlobalDefinitions.bullet_12mm - } - - "player can buy a flying vehicle, the reaver ('lightgunship')" in { - val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "lightgunship", 0, PlanetSideGUID(0)) - - val reply = terminal.Request(player, msg) - reply.isInstanceOf[Terminal.BuyVehicle] mustEqual true - val reply2 = reply.asInstanceOf[Terminal.BuyVehicle] - reply2.vehicle.Definition mustEqual GlobalDefinitions.lightgunship - reply2.weapons mustEqual Nil - reply2.inventory.length mustEqual 6 - reply2.inventory.head.obj.Definition mustEqual GlobalDefinitions.reaver_rocket - reply2.inventory(1).obj.Definition mustEqual GlobalDefinitions.reaver_rocket - reply2.inventory(2).obj.Definition mustEqual GlobalDefinitions.reaver_rocket - reply2.inventory(3).obj.Definition mustEqual GlobalDefinitions.reaver_rocket - reply2.inventory(4).obj.Definition mustEqual GlobalDefinitions.bullet_20mm - reply2.inventory(5).obj.Definition mustEqual GlobalDefinitions.bullet_20mm - } - - "player can not buy a fake vehicle ('harasser')" in { - val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "harasser", 0, PlanetSideGUID(0)) - - terminal.Request(player, msg) mustEqual Terminal.NoDeal() - } - } -} diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala index 39802b21..4fb1f631 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -17,7 +17,7 @@ import net.psforever.objects._ import net.psforever.objects.avatar.{Certification, DeployableToolbox} import net.psforever.objects.ballistics._ import net.psforever.objects.ce._ -import net.psforever.objects.definition.{ConstructionFireMode, DeployableDefinition, ObjectDefinition, ToolDefinition} +import net.psforever.objects.definition._ import net.psforever.objects.definition.converter.{CorpseConverter, DestroyedVehicleConverter} import net.psforever.objects.equipment.{CItem, _} import net.psforever.objects.loadouts._ @@ -543,7 +543,6 @@ class WorldSessionActor extends Actor with MDCContextAware { val factionOnContinentChannel = s"${continent.Id}/${player.Faction}" obj.Owner = None obj.OwnerName = None - obj.Faction = PlanetSideEmpire.NEUTRAL avatar.Deployables.Remove(obj) UpdateDeployableUIElements(avatar.Deployables.UpdateUIElement(obj.Definition.Item)) localService ! LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, continent)) @@ -1332,20 +1331,6 @@ class WorldSessionActor extends Actor with MDCContextAware { MountingAction(tplayer, obj, seat_num) sendResponse(PlanetsideAttributeMessage(obj.GUID, 0, 1000L)) //health of mech - case Mountable.CanMount(obj : PlanetSideGameObject with WeaponTurret, seat_num) => - obj.WeaponControlledFromSeat(seat_num) match { - case Some(weapon : Tool) => - //update mounted weapon belonging to seat - weapon.AmmoSlots.foreach(slot => { - //update the magazine(s) in the weapon, specifically - val magazine = slot.Box - sendResponse(InventoryStateMessage(magazine.GUID, weapon.GUID, magazine.Capacity.toLong)) - }) - case _ => ; //no weapons to update - } - sendResponse(PlanetsideAttributeMessage(obj.GUID, 0, obj.Health)) - MountingAction(tplayer, obj, seat_num) - case Mountable.CanMount(obj : Vehicle, seat_num) => val obj_guid : PlanetSideGUID = obj.GUID val player_guid : PlanetSideGUID = tplayer.GUID @@ -1384,15 +1369,26 @@ class WorldSessionActor extends Actor with MDCContextAware { AccessContents(obj) MountingAction(tplayer, obj, seat_num) + case Mountable.CanMount(obj : PlanetSideGameObject with WeaponTurret, seat_num) => + obj.WeaponControlledFromSeat(seat_num) match { + case Some(weapon : Tool) => + //update mounted weapon belonging to seat + weapon.AmmoSlots.foreach(slot => { + //update the magazine(s) in the weapon, specifically + val magazine = slot.Box + sendResponse(InventoryStateMessage(magazine.GUID, weapon.GUID, magazine.Capacity.toLong)) + }) + case _ => ; //no weapons to update + } + sendResponse(PlanetsideAttributeMessage(obj.GUID, 0, obj.Health)) + MountingAction(tplayer, obj, seat_num) + case Mountable.CanMount(obj : Mountable, _) => log.warn(s"MountVehicleMsg: $obj is some generic mountable object and nothing will happen") case Mountable.CanDismount(obj : ImplantTerminalMech, seat_num) => DismountAction(tplayer, obj, seat_num) - case Mountable.CanDismount(obj : PlanetSideGameObject with WeaponTurret, seat_num) => - DismountAction(tplayer, obj, seat_num) - case Mountable.CanDismount(obj : Vehicle, seat_num) => val player_guid : PlanetSideGUID = tplayer.GUID if(player_guid == player.GUID) { @@ -1405,6 +1401,9 @@ class WorldSessionActor extends Actor with MDCContextAware { vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.KickPassenger(player_guid, seat_num, true, obj.GUID)) } + case Mountable.CanDismount(obj : PlanetSideGameObject with WeaponTurret, seat_num) => + DismountAction(tplayer, obj, seat_num) + case Mountable.CanDismount(obj : Mountable, _) => log.warn(s"DismountVehicleMsg: $obj is some generic mountable object and nothing will happen") @@ -1562,6 +1561,7 @@ class WorldSessionActor extends Actor with MDCContextAware { case Terminal.BuyEquipment(item) => tplayer.Fit(item) match { case Some(index) => + item.Faction = tplayer.Faction sendResponse(ItemTransactionResultMessage(msg.terminal_guid, TransactionType.Buy, true)) taskResolver ! PutEquipmentInSlot(tplayer, item, index) case None => @@ -1633,10 +1633,12 @@ class WorldSessionActor extends Actor with MDCContextAware { else { afterHolsters }.foreach(entry => { + entry.obj.Faction = tplayer.Faction taskResolver ! PutEquipmentInSlot(tplayer, entry.obj, entry.start) }) //put items into inventory afterInventory.foreach(entry => { + entry.obj.Faction = tplayer.Faction taskResolver ! PutEquipmentInSlot(tplayer, entry.obj, entry.start) }) //drop stuff on ground @@ -1646,6 +1648,7 @@ class WorldSessionActor extends Actor with MDCContextAware { case Some(item) => List(InventoryItem(item, -1)) //add the item previously in free hand, if any case None => Nil }) ++ dropHolsters ++ dropInventory).foreach(entry => { + entry.obj.Faction = PlanetSideEmpire.NEUTRAL continent.Ground ! Zone.Ground.DropItem(entry.obj, pos, orient) }) lastTerminalOrderFulfillment = true @@ -1690,6 +1693,7 @@ class WorldSessionActor extends Actor with MDCContextAware { stow } }).foreach({ case InventoryItem(obj, index) => + obj.Faction = tplayer.Faction taskResolver ! stowEquipment(index, obj) }) case None => @@ -1826,8 +1830,9 @@ class WorldSessionActor extends Actor with MDCContextAware { case Terminal.BuyVehicle(vehicle, weapons, trunk) => continent.Map.TerminalToSpawnPad.get(msg.terminal_guid.guid) match { case Some(pad_guid) => + val toFaction = tplayer.Faction val pad = continent.GUID(pad_guid).get.asInstanceOf[VehicleSpawnPad] - vehicle.Faction = tplayer.Faction + vehicle.Faction = toFaction vehicle.Continent = continent.Id vehicle.Position = pad.Position vehicle.Orientation = pad.Orientation @@ -1837,6 +1842,7 @@ class WorldSessionActor extends Actor with MDCContextAware { val index = entry.start vWeapons.get(index) match { case Some(slot) => + entry.obj.Faction = toFaction slot.Equipment = None slot.Equipment = entry.obj case None => @@ -1847,6 +1853,7 @@ class WorldSessionActor extends Actor with MDCContextAware { val vTrunk = vehicle.Trunk vTrunk.Clear() trunk.foreach(entry => { + entry.obj.Faction = toFaction vTrunk += entry.start -> entry.obj }) taskResolver ! RegisterNewVehicle(vehicle, pad) @@ -2419,7 +2426,16 @@ class WorldSessionActor extends Actor with MDCContextAware { //TODO if Medkit does not have shortcut, add to a free slot or write over slot 64 sendResponse(CreateShortcutMessage(guid, 1, 0, true, Shortcut.MEDKIT)) sendResponse(ChangeShortcutBankMessage(guid, 0)) - //FavoritesMessage + //Favorites lists + val (inf, veh) = avatar.Loadouts.partition { case (index, _) => index < 10 } + inf.foreach { + case (index, loadout : InfantryLoadout) => + sendResponse(FavoritesMessage(LoadoutType.Infantry, guid, index, loadout.label, loadout.exosuit.id + loadout.subtype)) + } + veh.foreach { + case (index, loadout : VehicleLoadout) => + sendResponse(FavoritesMessage(LoadoutType.Vehicle, guid, index - 10, loadout.label)) + } sendResponse(SetChatFilterMessage(ChatChannel.Local, false, ChatChannel.values.toList)) //TODO will not always be "on" like this deadState = DeadState.Alive sendResponse(AvatarDeadStateMessage(DeadState.Alive, 0, 0, tplayer.Position, player.Faction, true)) @@ -2472,7 +2488,8 @@ class WorldSessionActor extends Actor with MDCContextAware { //TODO begin temp player character auto-loading; remove later import net.psforever.objects.GlobalDefinitions._ import net.psforever.types.CertificationType._ - val avatar = Avatar(s"TestCharacter$sessionId", PlanetSideEmpire.VS, CharacterGender.Female, 41, CharacterVoice.Voice1) + val faction = PlanetSideEmpire.VS + val avatar = Avatar(s"TestCharacter$sessionId", faction, CharacterGender.Female, 41, CharacterVoice.Voice1) avatar.Certifications += StandardAssault avatar.Certifications += MediumAssault avatar.Certifications += StandardExoSuit @@ -2529,6 +2546,7 @@ class WorldSessionActor extends Actor with MDCContextAware { player.Slot(36).Equipment = AmmoBox(GlobalDefinitions.StandardPistolAmmo(player.Faction)) player.Slot(39).Equipment = SimpleItem(remote_electronics_kit) player.Locker.Inventory += 0 -> SimpleItem(remote_electronics_kit) + player.Inventory.Items.foreach { _.obj.Faction = faction } //TODO end temp player character auto-loading self ! ListAccountCharacters import scala.concurrent.ExecutionContext.Implicits.global @@ -3761,7 +3779,7 @@ class WorldSessionActor extends Actor with MDCContextAware { log.error("UseItem: expected seated vehicle, but found none") } } - else if(tdef.isInstanceOf[TeleportPadTerminalDefinition]) { + else if(tdef == GlobalDefinitions.teleportpad_terminal) { //explicit request terminal.Actor ! Terminal.Request( player, @@ -5389,15 +5407,18 @@ class WorldSessionActor extends Actor with MDCContextAware { } source match { case obj : Vehicle => + item2.Faction = PlanetSideEmpire.NEUTRAL vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.StowEquipment(player_guid, source_guid, index, item2)) case obj : Player => + item2.Faction = obj.Faction if(source.VisibleSlots.contains(index)) { //item is put in hands avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.EquipmentInHand(player_guid, source_guid, index, item2)) } else if(obj.isBackpack) { //corpse being given item avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.StowEquipment(player_guid, source_guid, index, item2)) } - case _ => ; + case _ => + item2.Faction = PlanetSideEmpire.NEUTRAL } case None => //item2 does not fit; drop on ground @@ -5437,15 +5458,19 @@ class WorldSessionActor extends Actor with MDCContextAware { } destination match { case obj : Vehicle => + item.Faction = PlanetSideEmpire.NEUTRAL vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.StowEquipment(player_guid, destination_guid, dest, item)) case obj : Player => if(destination.VisibleSlots.contains(dest)) { //item is put in hands + item.Faction = obj.Faction avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.EquipmentInHand(player_guid, destination_guid, dest, item)) } else if(obj.isBackpack) { //corpse being given item + item.Faction = PlanetSideEmpire.NEUTRAL avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.StowEquipment(player_guid, destination_guid, dest, item)) } - case _ => ; + case _ => + item.Faction = PlanetSideEmpire.NEUTRAL } } @@ -5842,7 +5867,10 @@ class WorldSessionActor extends Actor with MDCContextAware { /** * For a given facility structure, configure a client by dispatching the appropriate packets. - * Pay special attention to the details of `BuildingInfoUpdateMessage` when preparing this packet. + * Pay special attention to the details of `BuildingInfoUpdateMessage` when preparing this packet.
+ *
+ * 24 Janurtay 2019:
+ * Manual `BIUM` construction to alleviate player login. * @see `BuildingInfoUpdateMessage` * @see `DensityLevelUpdateMessage` * @param continentNumber the zone id @@ -5850,7 +5878,31 @@ class WorldSessionActor extends Actor with MDCContextAware { * @param building the building object */ def initFacility(continentNumber : Int, buildingNumber : Int, building : Building) : Unit = { - building.Actor ! Building.SendMapUpdate(all_clients = false) + sendResponse( + BuildingInfoUpdateMessage( + continentNumber, + buildingNumber, + ntu_level = 8, + is_hacked = false, + empire_hack = PlanetSideEmpire.NEUTRAL, + hack_time_remaining = 0, + building.Faction, + unk1 = 0, //!! Field != 0 will cause malformed packet. See class def. + unk1x = None, + PlanetSideGeneratorState.Normal, + spawn_tubes_normal = true, + force_dome_active = false, + lattice_benefit = 0, + cavern_benefit = 0, //!! Field > 0 will cause malformed packet. See class def. + unk4 = Nil, + unk5 = 0, + unk6 = false, + unk7 = 8, //!! Field != 8 will cause malformed packet. See class def. + unk7x = None, + boost_spawn_pain = false, + boost_generator_pain = false + ) + ) sendResponse(DensityLevelUpdateMessage(continentNumber, buildingNumber, List(0,0, 0,0, 0,0, 0,0))) } @@ -6104,6 +6156,7 @@ class WorldSessionActor extends Actor with MDCContextAware { obj.Slot(33).Equipment = AmmoBox(bullet_9mm_AP) obj.Slot(36).Equipment = AmmoBox(StandardPistolAmmo(faction)) obj.Slot(39).Equipment = SimpleItem(remote_electronics_kit) + obj.Inventory.Items.foreach { _.obj.Faction = faction } obj } @@ -6599,7 +6652,7 @@ class WorldSessionActor extends Actor with MDCContextAware { //TODO charId should reflect the player more properly val killerCharId = math.abs(killer.Name.hashCode) var victimCharId = math.abs(victim.Name.hashCode) - if(killerCharId == victimCharId && killer.Name != victim.Name) { + if(killerCharId == victimCharId && !killer.Name.equals(victim.Name)) { //odds of hash collision in a populated zone should be close to odds of being struck by lightning victimCharId = Int.MaxValue - victimCharId + 1 } @@ -6719,11 +6772,11 @@ class WorldSessionActor extends Actor with MDCContextAware { * Ownership causes icon to be drawn in yellow to the player (as opposed to a white icon) * and that signifies a certain level of control over the deployable, at least the ability to quietly deconstruct it. * Under normal death/respawn cycles while the player is in a given zone, - * the map icons for owned deployables ramin manipulable to that given user. - * They do not havwe to be redrawn to stay accurate. + * the map icons for owned deployables remain manipulable by that given user. + * They do not have to be redrawn to stay accurate. * Upon leaving a zone, where the icons are erased, and returning back to the zone, where they are drawn again, * the deployables that a player owned should be restored in terms of their map icon visibility. - * TThis control can not be recovered, however, until they are updated with the player's globally unique identifier. + * This control can not be recovered, however, until they are updated with the player's globally unique identifier. * Since the player does not need to redraw his own deployable icons each time he respawns, * but will not possess a valid GUID for that zone until he spawns in it at least once, * this function swaps out with another after the first spawn in any given zone. @@ -7298,6 +7351,7 @@ class WorldSessionActor extends Actor with MDCContextAware { //TODO delay or reverse dropping item when player is falling down item.Position = pos item.Orientation = Vector3.z(orient.z) + item.Faction = PlanetSideEmpire.NEUTRAL //dropped items rotate towards the user's standing direction val exclusionId = player.Find(item) match { //if the item is in our hands ... @@ -7324,6 +7378,7 @@ class WorldSessionActor extends Actor with MDCContextAware { def PutItemInHand(item : Equipment) : Boolean = { player.Fit(item) match { case Some(slotNum) => + item.Faction = player.Faction val item_guid = item.GUID val player_guid = player.GUID player.Slot(slotNum).Equipment = item @@ -7509,7 +7564,7 @@ class WorldSessionActor extends Actor with MDCContextAware { } /** - * For a certain weapon that cna load ammunition, enforce that its magazine is empty. + * For a certain weapon that can load ammunition, enforce that its magazine is empty. * Punctuate that emptiness with a ceasation of weapons fire and a dry fire sound effect. * @param weapon_guid the weapon (GUID) * @param tool the weapon (object) @@ -7590,6 +7645,32 @@ class WorldSessionActor extends Actor with MDCContextAware { } } + def GetPlayerHackSpeed(obj: PlanetSideServerObject with Hackable): Float = { + val playerHackLevel = GetPlayerHackLevel() + val timeToHack = obj.HackDuration(playerHackLevel) + + if(timeToHack == 0) { + log.warn(s"Player ${player.GUID} tried to hack an object ${obj.GUID} - ${obj.Definition.Name} that they don't have the correct hacking level for") + 0f + } + + // 250 ms per tick on the hacking progress bar + val ticks = (timeToHack * 1000) / 250 + 100f / ticks + } + + def GetPlayerHackLevel(): Int = { + if(player.Certifications.contains(CertificationType.ExpertHacking) || player.Certifications.contains(CertificationType.ElectronicsExpert)) { + 3 + } else if(player.Certifications.contains(CertificationType.AdvancedHacking)) { + 2 + } else if (player.Certifications.contains(CertificationType.Hacking)) { + 1 + } else { + 0 + } + } + def failWithError(error : String) = { log.error(error) sendResponse(ConnectionClose()) @@ -7667,13 +7748,13 @@ class WorldSessionActor extends Actor with MDCContextAware { /** * `KeepAliveMessage` is a special `PlanetSideGamePacket` that is excluded from being bundled when it is sent to the network.
*
- * The risk of the server getting caught in a state where the packets dispatched to the client are alwaysd bundled is posible. + * The risk of the server getting caught in a state where the packets dispatched to the client are always bundled is posible. * Starting the bundling functionality but forgetting to transition into a state where it is deactivated can lead to this problem. * No packets except for `KeepAliveMessage` will ever be sent until the ever-accumulating packets overflow. * To avoid this state, whenever a `KeepAliveMessage` is sent, the packet collector empties its current contents to the network. - * @see `StartBundlingPackets`
- * `StopBundlingPackets`
- * `clientKeepAlive` + * @see `StartBundlingPackets` + * @see `StopBundlingPackets` + * @see `clientKeepAlive` * @param cont a `KeepAliveMessage` packet */ def sendResponse(cont : KeepAliveMessage) : Unit = { @@ -7704,32 +7785,6 @@ class WorldSessionActor extends Actor with MDCContextAware { log.trace("WORLD SEND RAW: " + pkt) sendResponse(RawPacket(pkt)) } - - def GetPlayerHackSpeed(obj: PlanetSideServerObject with Hackable): Float = { - val playerHackLevel = GetPlayerHackLevel() - val timeToHack = obj.HackDuration(playerHackLevel) - - if(timeToHack == 0) { - log.warn(s"Player ${player.GUID} tried to hack an object ${obj.GUID} - ${obj.Definition.Name} that they don't have the correct hacking level for") - 0f - } - - // 250 ms per tick on the hacking progress bar - val ticks = (timeToHack * 1000) / 250 - 100f / ticks - } - - def GetPlayerHackLevel(): Int = { - if(player.Certifications.contains(CertificationType.ExpertHacking) || player.Certifications.contains(CertificationType.ElectronicsExpert)) { - 3 - } else if(player.Certifications.contains(CertificationType.AdvancedHacking)) { - 2 - } else if (player.Certifications.contains(CertificationType.Hacking)) { - 1 - } else { - 0 - } - } } object WorldSessionActor { diff --git a/pslogin/src/test/scala/PacketCodingActorTest.scala b/pslogin/src/test/scala/PacketCodingActorTest.scala index 1628fe5b..5efe312b 100644 --- a/pslogin/src/test/scala/PacketCodingActorTest.scala +++ b/pslogin/src/test/scala/PacketCodingActorTest.scala @@ -554,14 +554,18 @@ class PacketCodingActorKTest extends ActorTest { 41, CharacterVoice.Voice1 ), - false, - false, - true, - None, - false, + CommonFieldData( + PlanetSideEmpire.VS, + false, + false, + true, + None, + false, + None, + None, + PlanetSideGUID(0) + ), ExoSuitType.Standard, - None, - 0, 0, 41605313L, 0,