mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-04-25 13:55:22 +00:00
ObjectCreateMessage Alterations, Class Object Adjustments (#243)
* power outage failure resulting in the destruction of the original ocm-fixes branch; the git branch refs were corrupted during commit, but the up-to-date changed files remained intact * eliminating the need for CommonFieldData2 and CommonFieldData2WithPlacement * in the middle of integrating CommonFieldData into DetailedLockerContainerData (but not standard LockerContainerData); added field for final boolean in WeaponData * adding faction affinity to Equipment (to match functionality; not becuase I know what ends ...) * in the middle of integrating CommonFieldData into DetailedCommandDetonaterData * applying faction affinity to objects at time of terminal production (but to what ends?); required BoomerTrigger and AmmoBox to always report as NEUTRAL internally * completed the transition from using the old class-based order terminal system to the page-based order terminal system; unused terminal classes have been eliminated * more closely aligned TelepadDeployableData and InternalTelepadDeployableData * modifying TelepadDeployableData make it generic and eliminate the need for InternalTelepadDeployableData after fixing a packet converter to utilize DroppedItemData * modified Terminal operation to branch further outwards from Terminal.Request to the TerminalDefinition's Request method; modified tests to reflect update * loosening up matrix terminal definition limitations * modified ProximityTerminal to support a custom defintition class * rendered the message passing system for Terminals general (Any) in the full scale so it can be specific in instance cases * refactored and moved both EquipmentSlot and ExoSuitDefinition * (re)load Favorites each time player (re)spawns
This commit is contained in:
parent
5fc9e191fe
commit
337cfbe5d2
174 changed files with 6281 additions and 5477 deletions
|
|
@ -3,6 +3,7 @@ package net.psforever.objects
|
||||||
|
|
||||||
import net.psforever.objects.definition.AmmoBoxDefinition
|
import net.psforever.objects.definition.AmmoBoxDefinition
|
||||||
import net.psforever.objects.equipment.{Ammo, Equipment}
|
import net.psforever.objects.equipment.{Ammo, Equipment}
|
||||||
|
import net.psforever.types.PlanetSideEmpire
|
||||||
|
|
||||||
class AmmoBox(private val ammoDef : AmmoBoxDefinition,
|
class AmmoBox(private val ammoDef : AmmoBoxDefinition,
|
||||||
cap : Option[Int] = None
|
cap : Option[Int] = None
|
||||||
|
|
@ -22,6 +23,8 @@ class AmmoBox(private val ammoDef : AmmoBoxDefinition,
|
||||||
|
|
||||||
def Definition : AmmoBoxDefinition = ammoDef
|
def Definition : AmmoBoxDefinition = ammoDef
|
||||||
|
|
||||||
|
override def Faction_=(fact : PlanetSideEmpire.Value) : PlanetSideEmpire.Value = Faction
|
||||||
|
|
||||||
override def toString : String = {
|
override def toString : String = {
|
||||||
AmmoBox.toString(this)
|
AmmoBox.toString(this)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,9 @@ package net.psforever.objects
|
||||||
|
|
||||||
import net.psforever.objects.avatar.DeployableToolbox
|
import net.psforever.objects.avatar.DeployableToolbox
|
||||||
import net.psforever.objects.definition.{AvatarDefinition, ImplantDefinition}
|
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.objects.loadouts.Loadout
|
||||||
|
import net.psforever.packet.game.objectcreate.Cosmetics
|
||||||
import net.psforever.types._
|
import net.psforever.types._
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
|
|
@ -15,6 +16,8 @@ class Avatar(val name : String, val faction : PlanetSideEmpire.Value, val sex :
|
||||||
private var bep : Long = 0
|
private var bep : Long = 0
|
||||||
/** Command Experience Points */
|
/** Command Experience Points */
|
||||||
private var cep : Long = 0
|
private var cep : Long = 0
|
||||||
|
/** Cosmetics **/
|
||||||
|
private var pStyle : Option[Cosmetics] = None
|
||||||
/** Certifications */
|
/** Certifications */
|
||||||
private val certs : mutable.Set[CertificationType.Value] = mutable.Set[CertificationType.Value]()
|
private val certs : mutable.Set[CertificationType.Value] = mutable.Set[CertificationType.Value]()
|
||||||
/** Implants<br>
|
/** Implants<br>
|
||||||
|
|
@ -56,6 +59,13 @@ class Avatar(val name : String, val faction : PlanetSideEmpire.Value, val sex :
|
||||||
CEP
|
CEP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def PersonalStyleFeatures : Option[Cosmetics] = pStyle
|
||||||
|
|
||||||
|
def PersonalStyleFeatures_=(app : Cosmetics) : Option[Cosmetics] = {
|
||||||
|
pStyle = Some(app)
|
||||||
|
pStyle
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the three implant slots for this player.
|
* Retrieve the three implant slots for this player.
|
||||||
* @return an `Array` of `ImplantSlot` objects
|
* @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 = {
|
def DeleteLoadout(line : Int) : Unit = {
|
||||||
loadouts(line) = None
|
loadouts(line) = None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def Loadouts : Seq[(Int, Loadout)] = loadouts.zipWithIndex.collect { case(Some(loadout), index) => (index, loadout) } toSeq
|
||||||
|
|
||||||
def Locker : LockerContainer = locker
|
def Locker : LockerContainer = locker
|
||||||
|
|
||||||
def FifthSlot : EquipmentSlot = {
|
def FifthSlot : EquipmentSlot = {
|
||||||
|
|
|
||||||
|
|
@ -2,5 +2,8 @@
|
||||||
package net.psforever.objects
|
package net.psforever.objects
|
||||||
|
|
||||||
import net.psforever.objects.equipment.RemoteUnit
|
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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ import net.psforever.objects.serverobject.tube.SpawnTubeDefinition
|
||||||
import net.psforever.objects.serverobject.resourcesilo.ResourceSiloDefinition
|
import net.psforever.objects.serverobject.resourcesilo.ResourceSiloDefinition
|
||||||
import net.psforever.objects.serverobject.turret.{TurretDefinition, TurretUpgrade}
|
import net.psforever.objects.serverobject.turret.{TurretDefinition, TurretUpgrade}
|
||||||
import net.psforever.objects.vehicles.{DestroyedVehicle, SeatArmorRestriction, UtilityType}
|
import net.psforever.objects.vehicles.{DestroyedVehicle, SeatArmorRestriction, UtilityType}
|
||||||
import net.psforever.objects.vital.{DamageType, StandardResolutions}
|
import net.psforever.objects.vital.{DamageType, StandardMaxDamage, StandardResolutions}
|
||||||
import net.psforever.types.{CertificationType, PlanetSideEmpire, Vector3}
|
import net.psforever.types.{CertificationType, ExoSuitType, PlanetSideEmpire, Vector3}
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
@ -29,6 +29,71 @@ object GlobalDefinitions {
|
||||||
*/
|
*/
|
||||||
val avatar = new AvatarDefinition(121)
|
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
|
Implants
|
||||||
*/
|
*/
|
||||||
val advanced_regen = ImplantDefinition(0)
|
val advanced_regen = ImplantDefinition(0)
|
||||||
|
|
@ -880,37 +945,44 @@ object GlobalDefinitions {
|
||||||
/*
|
/*
|
||||||
Miscellaneous
|
Miscellaneous
|
||||||
*/
|
*/
|
||||||
val order_terminal = new OrderTerminalDefinition
|
|
||||||
|
|
||||||
val ams_respawn_tube = new SpawnTubeDefinition(49)
|
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 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_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 = new SpawnTubeDefinition(732)
|
||||||
|
|
||||||
val respawn_tube_tower = new SpawnTubeDefinition(733)
|
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)
|
val adv_med_terminal = new MedicalTerminalDefinition(38)
|
||||||
|
|
||||||
|
|
@ -944,13 +1016,13 @@ object GlobalDefinitions {
|
||||||
|
|
||||||
val lodestar_repair_terminal = new MedicalTerminalDefinition(461)
|
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)
|
val manned_turret = new TurretDefinition(480)
|
||||||
initMiscellaneous()
|
initMiscellaneous()
|
||||||
|
|
@ -1338,6 +1410,68 @@ object GlobalDefinitions {
|
||||||
super_staminakit.Name = "super_staminakit"
|
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.
|
* Initialize `AmmoBoxDefinition` globals.
|
||||||
*/
|
*/
|
||||||
|
|
@ -5578,7 +5712,7 @@ object GlobalDefinitions {
|
||||||
deployable_shield_generator.MaxHealth = 1700
|
deployable_shield_generator.MaxHealth = 1700
|
||||||
deployable_shield_generator.DeployTime = Duration.create(6000, "ms")
|
deployable_shield_generator.DeployTime = Duration.create(6000, "ms")
|
||||||
deployable_shield_generator.Model = StandardResolutions.ComplexDeployables
|
deployable_shield_generator.Model = StandardResolutions.ComplexDeployables
|
||||||
|
|
||||||
router_telepad_deployable.Name = "router_telepad_deployable"
|
router_telepad_deployable.Name = "router_telepad_deployable"
|
||||||
router_telepad_deployable.MaxHealth = 100
|
router_telepad_deployable.MaxHealth = 100
|
||||||
router_telepad_deployable.DeployTime = Duration.create(1, "ms")
|
router_telepad_deployable.DeployTime = Duration.create(1, "ms")
|
||||||
|
|
@ -5595,6 +5729,67 @@ object GlobalDefinitions {
|
||||||
* Initialize `Miscellaneous` globals.
|
* Initialize `Miscellaneous` globals.
|
||||||
*/
|
*/
|
||||||
private def initMiscellaneous() : Unit = {
|
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.Name = "adv_med_terminal"
|
||||||
adv_med_terminal.Interval = 500
|
adv_med_terminal.Interval = 500
|
||||||
adv_med_terminal.HealAmount = 8
|
adv_med_terminal.HealAmount = 8
|
||||||
|
|
@ -5653,20 +5848,24 @@ object GlobalDefinitions {
|
||||||
lodestar_repair_terminal.TargetValidation += ProximityTarget.Vehicle -> ProximityTerminalControl.Validation.RepairSilo
|
lodestar_repair_terminal.TargetValidation += ProximityTarget.Vehicle -> ProximityTerminalControl.Validation.RepairSilo
|
||||||
|
|
||||||
multivehicle_rearm_terminal.Name = "multivehicle_rearm_terminal"
|
multivehicle_rearm_terminal.Name = "multivehicle_rearm_terminal"
|
||||||
multivehicle_rearm_terminal.Page += 3 -> _OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition)
|
multivehicle_rearm_terminal.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition)
|
||||||
multivehicle_rearm_terminal.Page += 4 -> _OrderTerminalDefinition.VehicleLoadoutPage()
|
multivehicle_rearm_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
||||||
|
multivehicle_rearm_terminal.SellEquipmentByDefault = true //TODO ?
|
||||||
|
|
||||||
bfr_rearm_terminal.Name = "bfr_rearm_terminal"
|
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.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(Map.empty[String, ()=>Equipment]) //TODO add stock to page
|
||||||
bfr_rearm_terminal.Page += 4 -> _OrderTerminalDefinition.VehicleLoadoutPage()
|
bfr_rearm_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
||||||
|
bfr_rearm_terminal.SellEquipmentByDefault = true //TODO ?
|
||||||
|
|
||||||
air_rearm_terminal.Name = "air_rearm_terminal"
|
air_rearm_terminal.Name = "air_rearm_terminal"
|
||||||
air_rearm_terminal.Page += 3 -> _OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition)
|
air_rearm_terminal.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition)
|
||||||
air_rearm_terminal.Page += 4 -> _OrderTerminalDefinition.VehicleLoadoutPage()
|
air_rearm_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
||||||
|
air_rearm_terminal.SellEquipmentByDefault = true //TODO ?
|
||||||
|
|
||||||
ground_rearm_terminal.Name = "ground_rearm_terminal"
|
ground_rearm_terminal.Name = "ground_rearm_terminal"
|
||||||
ground_rearm_terminal.Page += 3 -> _OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition)
|
ground_rearm_terminal.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition)
|
||||||
ground_rearm_terminal.Page += 4 -> _OrderTerminalDefinition.VehicleLoadoutPage()
|
ground_rearm_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
||||||
|
ground_rearm_terminal.SellEquipmentByDefault = true //TODO ?
|
||||||
|
|
||||||
manned_turret.Name = "manned_turret"
|
manned_turret.Name = "manned_turret"
|
||||||
manned_turret.MaxHealth = 3600
|
manned_turret.MaxHealth = 3600
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects
|
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`.
|
* A size-checked unit of storage (or mounting) for `Equipment`.
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects
|
package net.psforever.objects
|
||||||
|
|
||||||
import net.psforever.objects.definition.AvatarDefinition
|
import net.psforever.objects.definition.{AvatarDefinition, ExoSuitDefinition, SpecialExoSuitDefinition}
|
||||||
import net.psforever.objects.equipment.{Equipment, EquipmentSize}
|
import net.psforever.objects.equipment.{Equipment, EquipmentSize, EquipmentSlot}
|
||||||
import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem}
|
import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem}
|
||||||
import net.psforever.objects.loadouts.Loadout
|
import net.psforever.objects.loadouts.Loadout
|
||||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
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.vital.{DamageResistanceModel, Vitality}
|
||||||
import net.psforever.objects.zones.ZoneAware
|
import net.psforever.objects.zones.ZoneAware
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
|
import net.psforever.packet.game.objectcreate.{Cosmetics, DetailedCharacterData, PersonalStyle}
|
||||||
import net.psforever.types._
|
import net.psforever.types._
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
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 maxHealth : Int = 100 //TODO affected by empire benefits, territory benefits, and bops
|
||||||
private var maxStamina : Int = 100 //does anything affect this?
|
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 freeHand : EquipmentSlot = new OffhandEquipmentSlot(EquipmentSize.Inventory)
|
||||||
private val holsters : Array[EquipmentSlot] = Array.fill[EquipmentSlot](5)(new EquipmentSlot)
|
private val holsters : Array[EquipmentSlot] = Array.fill[EquipmentSlot](5)(new EquipmentSlot)
|
||||||
private val inventory : GridInventory = GridInventory()
|
private val inventory : GridInventory = GridInventory()
|
||||||
private var drawnSlot : Int = Player.HandsDownSlot
|
private var drawnSlot : Int = Player.HandsDownSlot
|
||||||
private var lastDrawnSlot : Int = Player.HandsDownSlot
|
private var lastDrawnSlot : Int = Player.HandsDownSlot
|
||||||
|
private var backpackAccess : Option[PlanetSideGUID] = None
|
||||||
|
|
||||||
private var facingYawUpper : Float = 0f
|
private var facingYawUpper : Float = 0f
|
||||||
private var crouching : Boolean = false
|
private var crouching : Boolean = false
|
||||||
private var jumping : Boolean = false
|
private var jumping : Boolean = false
|
||||||
private var cloaked : Boolean = false
|
private var cloaked : Boolean = false
|
||||||
private var backpackAccess : Option[PlanetSideGUID] = None
|
|
||||||
|
|
||||||
private var vehicleSeated : Option[PlanetSideGUID] = None
|
private var vehicleSeated : Option[PlanetSideGUID] = None
|
||||||
private var vehicleOwned : Option[PlanetSideGUID] = None
|
private var vehicleOwned : Option[PlanetSideGUID] = None
|
||||||
|
|
@ -347,7 +348,71 @@ class Player(private val core : Avatar) extends PlanetSideGameObject
|
||||||
Cloaked
|
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
|
private var gettingSpecial : ()=>SpecialExoSuitDefinition.Mode.Value = DefaultGettingSpecial
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package net.psforever.objects
|
||||||
|
|
||||||
import akka.actor.ActorRef
|
import akka.actor.ActorRef
|
||||||
import net.psforever.objects.definition.VehicleDefinition
|
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.inventory.{Container, GridInventory, InventoryTile}
|
||||||
import net.psforever.objects.serverobject.mount.Mountable
|
import net.psforever.objects.serverobject.mount.Mountable
|
||||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,27 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// 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.equipment.EquipmentSize
|
||||||
import net.psforever.objects.inventory.InventoryTile
|
import net.psforever.objects.inventory.InventoryTile
|
||||||
import net.psforever.objects.vital._
|
import net.psforever.objects.vital._
|
||||||
import net.psforever.objects.vital.resistance.ResistanceProfileMutators
|
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.
|
* 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.
|
* 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
|
* @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 {
|
with DamageResistanceModel {
|
||||||
protected var permission : Int = 0 //TODO certification type?
|
protected var permissions : List[CertificationType.Value] = List.empty
|
||||||
protected var maxArmor : Int = 0
|
protected var maxArmor : Int = 0
|
||||||
protected val holsters : Array[EquipmentSize.Value] = Array.fill[EquipmentSize.Value](5)(EquipmentSize.Blocked)
|
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 inventoryScale : InventoryTile = InventoryTile.Tile11 //override with custom InventoryTile
|
||||||
protected var inventoryOffset : Int = 0
|
protected var inventoryOffset : Int = 0
|
||||||
|
Name = "exo-suit"
|
||||||
Damage = StandardInfantryDamage
|
Damage = StandardInfantryDamage
|
||||||
Resistance = StandardInfantryResistance
|
Resistance = StandardInfantryResistance
|
||||||
Model = StandardResolutions.Infantry
|
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
|
def Use : ExoSuitDefinition = this
|
||||||
}
|
}
|
||||||
|
|
||||||
class SpecialExoSuitDefinition(private val suitType : ExoSuitType.Value) extends ExoSuitDefinition(suitType) {
|
class SpecialExoSuitDefinition(private val suitType : ExoSuitType.Value) extends ExoSuitDefinition(suitType) {
|
||||||
|
Name = "heavy_armor"
|
||||||
|
|
||||||
private var activatedSpecial : SpecialExoSuitDefinition.Mode.Value = SpecialExoSuitDefinition.Mode.Normal
|
private var activatedSpecial : SpecialExoSuitDefinition.Mode.Value = SpecialExoSuitDefinition.Mode.Normal
|
||||||
|
|
||||||
def UsingSpecial : SpecialExoSuitDefinition.Mode.Value = activatedSpecial
|
def UsingSpecial : SpecialExoSuitDefinition.Mode.Value = activatedSpecial
|
||||||
|
|
@ -118,65 +130,6 @@ object SpecialExoSuitDefinition {
|
||||||
}
|
}
|
||||||
|
|
||||||
object ExoSuitDefinition {
|
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 = {
|
def apply(suitType : ExoSuitType.Value) : ExoSuitDefinition = {
|
||||||
new ExoSuitDefinition(suitType)
|
new ExoSuitDefinition(suitType)
|
||||||
}
|
}
|
||||||
|
|
@ -188,11 +141,11 @@ object ExoSuitDefinition {
|
||||||
*/
|
*/
|
||||||
def Select(suit : ExoSuitType.Value) : ExoSuitDefinition = {
|
def Select(suit : ExoSuitType.Value) : ExoSuitDefinition = {
|
||||||
suit match {
|
suit match {
|
||||||
case ExoSuitType.Agile => ExoSuitDefinition.Agile.Use
|
case ExoSuitType.Agile => GlobalDefinitions.Agile.Use
|
||||||
case ExoSuitType.Infiltration => ExoSuitDefinition.Infiltration.Use
|
case ExoSuitType.Infiltration => GlobalDefinitions.Infiltration.Use
|
||||||
case ExoSuitType.MAX => ExoSuitDefinition.MAX.Use
|
case ExoSuitType.MAX => GlobalDefinitions.MAX.Use
|
||||||
case ExoSuitType.Reinforced => ExoSuitDefinition.Reinforced.Use
|
case ExoSuitType.Reinforced => GlobalDefinitions.Reinforced.Use
|
||||||
case _ => ExoSuitDefinition.Standard.Use
|
case _ => GlobalDefinitions.Standard.Use
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,16 +2,45 @@
|
||||||
package net.psforever.objects.definition.converter
|
package net.psforever.objects.definition.converter
|
||||||
|
|
||||||
import net.psforever.objects.ConstructionItem
|
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}
|
import scala.util.{Success, Try}
|
||||||
|
|
||||||
class ACEConverter extends ObjectCreateConverter[ConstructionItem]() {
|
class ACEConverter extends ObjectCreateConverter[ConstructionItem]() {
|
||||||
override def ConstructorData(obj : ConstructionItem) : Try[ACEData] = {
|
override def ConstructorData(obj : ConstructionItem) : Try[HandheldData] = {
|
||||||
Success(ACEData(0,0))
|
Success(
|
||||||
|
HandheldData(
|
||||||
|
CommonFieldData(
|
||||||
|
obj.Faction,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
PlanetSideGUID(0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def DetailedConstructorData(obj : ConstructionItem) : Try[DetailedACEData] = {
|
override def DetailedConstructorData(obj : ConstructionItem) : Try[DetailedConstructionToolData] = {
|
||||||
Success(DetailedACEData(0))
|
Success(
|
||||||
|
DetailedConstructionToolData(
|
||||||
|
CommonFieldData(
|
||||||
|
obj.Faction,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
PlanetSideGUID(0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,33 @@
|
||||||
package net.psforever.objects.definition.converter
|
package net.psforever.objects.definition.converter
|
||||||
|
|
||||||
import net.psforever.objects.AmmoBox
|
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}
|
import scala.util.{Success, Try}
|
||||||
|
|
||||||
class AmmoBoxConverter extends ObjectCreateConverter[AmmoBox] {
|
class AmmoBoxConverter extends ObjectCreateConverter[AmmoBox] {
|
||||||
override def ConstructorData(obj : AmmoBox) : Try[AmmoBoxData] = {
|
override def ConstructorData(obj : AmmoBox) : Try[CommonFieldData] = {
|
||||||
Success(AmmoBoxData())
|
Success(CommonFieldData()(false))
|
||||||
}
|
}
|
||||||
|
|
||||||
override def DetailedConstructorData(obj : AmmoBox) : Try[DetailedAmmoBoxData] = {
|
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
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.definition.converter
|
package net.psforever.objects.definition.converter
|
||||||
|
|
||||||
import net.psforever.objects.{EquipmentSlot, Player}
|
import net.psforever.objects.Player
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.{Equipment, EquipmentSlot}
|
||||||
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
import net.psforever.packet.game.objectcreate._
|
import net.psforever.packet.game.objectcreate._
|
||||||
import net.psforever.types.{ExoSuitType, GrenadeState, ImplantType}
|
import net.psforever.types.{ExoSuitType, GrenadeState, ImplantType}
|
||||||
|
|
||||||
|
|
@ -63,18 +64,22 @@ object AvatarConverter {
|
||||||
* @param obj the `Player` game object
|
* @param obj the `Player` game object
|
||||||
* @return the resulting `CharacterAppearanceData`
|
* @return the resulting `CharacterAppearanceData`
|
||||||
*/
|
*/
|
||||||
def MakeAppearanceData(obj : Player) : (Int)=>CharacterAppearanceData = {
|
def MakeAppearanceData(obj : Player) : Int=>CharacterAppearanceData = {
|
||||||
val alt_model_flag : Boolean = obj.isBackpack
|
val alt_model_flag : Boolean = obj.isBackpack
|
||||||
val aa : Int=>CharacterAppearanceA = CharacterAppearanceA(
|
val aa : Int=>CharacterAppearanceA = CharacterAppearanceA(
|
||||||
BasicCharacterData(obj.Name, obj.Faction, obj.Sex, obj.Head, obj.Voice),
|
BasicCharacterData(obj.Name, obj.Faction, obj.Sex, obj.Head, obj.Voice),
|
||||||
black_ops = false,
|
CommonFieldData(
|
||||||
alt_model_flag,
|
obj.Faction,
|
||||||
false,
|
bops = false,
|
||||||
None,
|
alt_model_flag,
|
||||||
jammered = false,
|
false,
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
v5 = None,
|
||||||
|
PlanetSideGUID(0)
|
||||||
|
),
|
||||||
obj.ExoSuit,
|
obj.ExoSuit,
|
||||||
None,
|
|
||||||
0,
|
|
||||||
0,
|
0,
|
||||||
0L,
|
0L,
|
||||||
0,
|
0,
|
||||||
|
|
@ -108,22 +113,22 @@ object AvatarConverter {
|
||||||
def MakeCharacterData(obj : Player) : (Boolean,Boolean)=>CharacterData = {
|
def MakeCharacterData(obj : Player) : (Boolean,Boolean)=>CharacterData = {
|
||||||
val MaxArmor = obj.MaxArmor
|
val MaxArmor = obj.MaxArmor
|
||||||
CharacterData(
|
CharacterData(
|
||||||
255 * obj.Health / obj.MaxHealth,
|
StatConverter.Health(obj.Health, obj.MaxHealth),
|
||||||
if(MaxArmor == 0) {
|
if(MaxArmor == 0) {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
255 * obj.Armor / MaxArmor
|
StatConverter.Health(obj.Armor, MaxArmor)
|
||||||
},
|
},
|
||||||
DressBattleRank(obj),
|
DressBattleRank(obj),
|
||||||
0,
|
0,
|
||||||
DressCommandRank(obj),
|
DressCommandRank(obj),
|
||||||
MakeImplantEffectList(obj.Implants),
|
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 bep : Long = obj.BEP
|
||||||
val maxOpt : Option[Long] = if(obj.ExoSuit == ExoSuitType.MAX) { Some(0L) } else { None }
|
val maxOpt : Option[Long] = if(obj.ExoSuit == ExoSuitType.MAX) { Some(0L) } else { None }
|
||||||
val ba : DetailedCharacterA = DetailedCharacterA(
|
val ba : DetailedCharacterA = DetailedCharacterA(
|
||||||
|
|
@ -149,9 +154,9 @@ object AvatarConverter {
|
||||||
0L, 0L, 0L, 0L, 0L,
|
0L, 0L, 0L, 0L, 0L,
|
||||||
Some(DCDExtra2(0, 0)),
|
Some(DCDExtra2(0, 0)),
|
||||||
Nil, Nil, false,
|
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 = {
|
def MakeInventoryData(obj : Player) : InventoryData = {
|
||||||
|
|
@ -219,8 +224,8 @@ object AvatarConverter {
|
||||||
* @see `ImplantEntry` in `DetailedCharacterData`
|
* @see `ImplantEntry` in `DetailedCharacterData`
|
||||||
*/
|
*/
|
||||||
private def MakeImplantEntries(obj : Player) : List[ImplantEntry] = {
|
private def MakeImplantEntries(obj : Player) : List[ImplantEntry] = {
|
||||||
val numImplants : Int = DetailedCharacterData.numberOfImplantSlots(obj.BEP)
|
//val numImplants : Int = DetailedCharacterData.numberOfImplantSlots(obj.BEP)
|
||||||
val implants = obj.Implants
|
//val implants = obj.Implants
|
||||||
obj.Implants.map({ case(implant, initialization, _) =>
|
obj.Implants.map({ case(implant, initialization, _) =>
|
||||||
if(initialization == 0) {
|
if(initialization == 0) {
|
||||||
ImplantEntry(implant, None)
|
ImplantEntry(implant, None)
|
||||||
|
|
@ -238,7 +243,7 @@ object AvatarConverter {
|
||||||
*/
|
*/
|
||||||
private def MakeImplantEffectList(implants : Seq[(ImplantType.Value, Long, Boolean)]) : List[ImplantEffects.Value] = {
|
private def MakeImplantEffectList(implants : Seq[(ImplantType.Value, Long, Boolean)]) : List[ImplantEffects.Value] = {
|
||||||
implants.collect {
|
implants.collect {
|
||||||
case ((implant,_,true)) =>
|
case (implant,_,true) =>
|
||||||
implant match {
|
implant match {
|
||||||
case ImplantType.AdvancedRegen =>
|
case ImplantType.AdvancedRegen =>
|
||||||
ImplantEffects.RegenEffects
|
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.
|
* Should this player be of battle rank 24 or higher, they will have a mandatory cosmetics object in their bitstream.
|
||||||
* @param bep battle experience points
|
* 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`
|
* @see `Cosmetics`
|
||||||
* @return the `Cosmetics` options
|
* @return the `Cosmetics` options
|
||||||
*/
|
*/
|
||||||
def MakeCosmetics(bep : Long) : Option[Cosmetics] =
|
def MakeCosmetics(obj : Player) : Option[Cosmetics] =
|
||||||
if(DetailedCharacterData.isBR24(bep)) {
|
if(DetailedCharacterData.isBR24(obj.BEP)) {
|
||||||
Some(Cosmetics(false, false, false, false, false))
|
obj.PersonalStyleFeatures.orElse(Some(Cosmetics()))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
None
|
None
|
||||||
|
|
@ -290,7 +297,7 @@ object AvatarConverter {
|
||||||
* @param builder the function used to transform to the decoded packet form
|
* @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
|
* @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)
|
recursiveMakeHolsters(obj.Holsters().iterator, builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -338,7 +345,7 @@ object AvatarConverter {
|
||||||
* @param index which holster is currently being explored
|
* @param index which holster is currently being explored
|
||||||
* @return the `List` of inventory data created from the holsters
|
* @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) {
|
if(!iter.hasNext) {
|
||||||
list
|
list
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,20 @@
|
||||||
package net.psforever.objects.definition.converter
|
package net.psforever.objects.definition.converter
|
||||||
|
|
||||||
import net.psforever.objects.SimpleItem
|
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}
|
import scala.util.{Success, Try}
|
||||||
|
|
||||||
class BoomerTriggerConverter extends ObjectCreateConverter[SimpleItem]() {
|
class BoomerTriggerConverter extends ObjectCreateConverter[SimpleItem]() {
|
||||||
override def ConstructorData(obj : SimpleItem) : Try[BoomerTriggerData] = {
|
override def ConstructorData(obj : SimpleItem) : Try[HandheldData] = {
|
||||||
Success(BoomerTriggerData())
|
Success(HandheldData(CommonFieldData()))
|
||||||
}
|
}
|
||||||
|
|
||||||
override def DetailedConstructorData(obj : SimpleItem) : Try[DetailedBoomerTriggerData] = {
|
override def DetailedConstructorData(obj : SimpleItem) : Try[DetailedConstructionToolData] = {
|
||||||
Success(DetailedBoomerTriggerData())
|
Success(DetailedConstructionToolData(
|
||||||
|
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0))
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.definition.converter
|
package net.psforever.objects.definition.converter
|
||||||
|
|
||||||
import net.psforever.objects.{EquipmentSlot, Player}
|
import net.psforever.objects.Player
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.{Equipment, EquipmentSlot}
|
||||||
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
import net.psforever.packet.game.objectcreate._
|
import net.psforever.packet.game.objectcreate._
|
||||||
import net.psforever.types._
|
import net.psforever.types._
|
||||||
|
|
||||||
|
|
@ -35,17 +36,21 @@ class CharacterSelectConverter extends AvatarConverter {
|
||||||
* @see `AvatarConverter.MakeAppearanceData`
|
* @see `AvatarConverter.MakeAppearanceData`
|
||||||
* @return the resulting `CharacterAppearanceData`
|
* @return the resulting `CharacterAppearanceData`
|
||||||
*/
|
*/
|
||||||
private def MakeAppearanceData(obj : Player) : (Int)=>CharacterAppearanceData = {
|
private def MakeAppearanceData(obj : Player) : Int=>CharacterAppearanceData = {
|
||||||
val aa : Int=>CharacterAppearanceA = CharacterAppearanceA(
|
val aa : Int=>CharacterAppearanceA = CharacterAppearanceA(
|
||||||
BasicCharacterData(obj.Name, obj.Faction, obj.Sex, obj.Head, CharacterVoice.Mute),
|
BasicCharacterData(obj.Name, obj.Faction, obj.Sex, obj.Head, CharacterVoice.Mute),
|
||||||
black_ops = false,
|
CommonFieldData(
|
||||||
false,
|
obj.Faction,
|
||||||
false,
|
bops = false,
|
||||||
None,
|
false,
|
||||||
jammered = false,
|
false,
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
v5 = None,
|
||||||
|
PlanetSideGUID(0)
|
||||||
|
),
|
||||||
obj.ExoSuit,
|
obj.ExoSuit,
|
||||||
None,
|
|
||||||
0,
|
|
||||||
0,
|
0,
|
||||||
0L,
|
0L,
|
||||||
0,
|
0,
|
||||||
|
|
@ -76,7 +81,7 @@ class CharacterSelectConverter extends AvatarConverter {
|
||||||
CharacterAppearanceData(aa, ab, RibbonBars())
|
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 bep : Long = obj.BEP
|
||||||
val maxOpt : Option[Long] = if(obj.ExoSuit == ExoSuitType.MAX) { Some(0L) } else { None }
|
val maxOpt : Option[Long] = if(obj.ExoSuit == ExoSuitType.MAX) { Some(0L) } else { None }
|
||||||
val ba : DetailedCharacterA = DetailedCharacterA(
|
val ba : DetailedCharacterA = DetailedCharacterA(
|
||||||
|
|
@ -102,9 +107,9 @@ class CharacterSelectConverter extends AvatarConverter {
|
||||||
0L, 0L, 0L, 0L, 0L,
|
0L, 0L, 0L, 0L, 0L,
|
||||||
Some(DCDExtra2(0, 0)),
|
Some(DCDExtra2(0, 0)),
|
||||||
Nil, Nil, false,
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,46 @@
|
||||||
package net.psforever.objects.definition.converter
|
package net.psforever.objects.definition.converter
|
||||||
|
|
||||||
import net.psforever.objects.SimpleItem
|
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}
|
import scala.util.{Success, Try}
|
||||||
|
|
||||||
class CommandDetonaterConverter extends ObjectCreateConverter[SimpleItem]() {
|
class CommandDetonaterConverter extends ObjectCreateConverter[SimpleItem]() {
|
||||||
override def ConstructorData(obj : SimpleItem) : Try[CommandDetonaterData] = {
|
override def ConstructorData(obj : SimpleItem) : Try[HandheldData] = {
|
||||||
Success(CommandDetonaterData())
|
Success(
|
||||||
|
HandheldData(
|
||||||
|
CommonFieldData(
|
||||||
|
obj.Faction,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
PlanetSideGUID(0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def DetailedConstructorData(obj : SimpleItem) : Try[DetailedCommandDetonaterData] = {
|
override def DetailedConstructorData(obj : SimpleItem) : Try[DetailedCommandDetonaterData] = {
|
||||||
Success(DetailedCommandDetonaterData())
|
Success(
|
||||||
|
DetailedCommandDetonaterData(
|
||||||
|
CommonFieldData(
|
||||||
|
obj.Faction,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
PlanetSideGUID(0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.definition.converter
|
package net.psforever.objects.definition.converter
|
||||||
|
|
||||||
import net.psforever.objects.{EquipmentSlot, Player}
|
import net.psforever.objects.Player
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.{Equipment, EquipmentSlot}
|
||||||
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
import net.psforever.packet.game.objectcreate._
|
import net.psforever.packet.game.objectcreate._
|
||||||
import net.psforever.types._
|
import net.psforever.types._
|
||||||
|
|
||||||
|
|
@ -30,17 +31,21 @@ class CorpseConverter extends AvatarConverter {
|
||||||
* @param obj the `Player` game object
|
* @param obj the `Player` game object
|
||||||
* @return the resulting `CharacterAppearanceData`
|
* @return the resulting `CharacterAppearanceData`
|
||||||
*/
|
*/
|
||||||
private def MakeAppearanceData(obj : Player) : (Int)=>CharacterAppearanceData = {
|
private def MakeAppearanceData(obj : Player) : Int=>CharacterAppearanceData = {
|
||||||
val aa : Int=>CharacterAppearanceA = CharacterAppearanceA(
|
val aa : Int=>CharacterAppearanceA = CharacterAppearanceA(
|
||||||
BasicCharacterData(obj.Name, obj.Faction, CharacterGender.Male, 0, CharacterVoice.Mute),
|
BasicCharacterData(obj.Name, obj.Faction, CharacterGender.Male, 0, CharacterVoice.Mute),
|
||||||
black_ops = false,
|
CommonFieldData(
|
||||||
altModel = true,
|
obj.Faction,
|
||||||
false,
|
bops = false,
|
||||||
None,
|
alternate = true,
|
||||||
jammered = false,
|
false,
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
v5 = None,
|
||||||
|
PlanetSideGUID(0)
|
||||||
|
),
|
||||||
obj.ExoSuit,
|
obj.ExoSuit,
|
||||||
None,
|
|
||||||
0,
|
|
||||||
0,
|
0,
|
||||||
0L,
|
0L,
|
||||||
0,
|
0,
|
||||||
|
|
@ -71,7 +76,7 @@ class CorpseConverter extends AvatarConverter {
|
||||||
CharacterAppearanceData(aa, ab, RibbonBars())
|
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 maxOpt : Option[Long] = if(obj.ExoSuit == ExoSuitType.MAX) { Some(0L) } else { None }
|
||||||
val ba : DetailedCharacterA = DetailedCharacterA(
|
val ba : DetailedCharacterA = DetailedCharacterA(
|
||||||
bep = 0L,
|
bep = 0L,
|
||||||
|
|
|
||||||
|
|
@ -11,22 +11,26 @@ import scala.util.{Failure, Success, Try}
|
||||||
|
|
||||||
class FieldTurretConverter extends ObjectCreateConverter[TurretDeployable]() {
|
class FieldTurretConverter extends ObjectCreateConverter[TurretDeployable]() {
|
||||||
override def ConstructorData(obj : TurretDeployable) : Try[OneMannedFieldTurretData] = {
|
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) {
|
if(health > 3) {
|
||||||
Success(
|
Success(
|
||||||
OneMannedFieldTurretData(
|
OneMannedFieldTurretData(
|
||||||
SmallDeployableData(
|
CommonFieldDataWithPlacement(
|
||||||
PlacementData(obj.Position, obj.Orientation),
|
PlacementData(obj.Position, obj.Orientation),
|
||||||
obj.Faction,
|
CommonFieldData(
|
||||||
bops = false,
|
obj.Faction,
|
||||||
destroyed = false,
|
bops = false,
|
||||||
unk1 = 0,
|
alternate = false,
|
||||||
obj.Jammered,
|
true,
|
||||||
unk2 = false,
|
None,
|
||||||
obj.Owner match {
|
false,
|
||||||
case Some(owner) => owner
|
Some(false),
|
||||||
case None => PlanetSideGUID(0)
|
None,
|
||||||
}
|
obj.Owner match {
|
||||||
|
case Some(owner) => owner
|
||||||
|
case None => PlanetSideGUID(0)
|
||||||
|
}
|
||||||
|
)
|
||||||
),
|
),
|
||||||
health,
|
health,
|
||||||
Some(InventoryData(FieldTurretConverter.MakeMountings(obj)))
|
Some(InventoryData(FieldTurretConverter.MakeMountings(obj)))
|
||||||
|
|
@ -36,18 +40,21 @@ class FieldTurretConverter extends ObjectCreateConverter[TurretDeployable]() {
|
||||||
else {
|
else {
|
||||||
Success(
|
Success(
|
||||||
OneMannedFieldTurretData(
|
OneMannedFieldTurretData(
|
||||||
SmallDeployableData(
|
CommonFieldDataWithPlacement(
|
||||||
PlacementData(obj.Position, obj.Orientation),
|
PlacementData(obj.Position, obj.Orientation),
|
||||||
obj.Faction,
|
CommonFieldData(
|
||||||
bops = false,
|
obj.Faction,
|
||||||
destroyed = true,
|
bops = false,
|
||||||
unk1 = 0,
|
alternate = true,
|
||||||
jammered = false,
|
true,
|
||||||
unk2 = false,
|
None,
|
||||||
owner_guid = PlanetSideGUID(0)
|
false,
|
||||||
|
Some(false),
|
||||||
|
None,
|
||||||
|
PlanetSideGUID(0)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
0,
|
0
|
||||||
None
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -60,7 +67,7 @@ class FieldTurretConverter extends ObjectCreateConverter[TurretDeployable]() {
|
||||||
object FieldTurretConverter {
|
object FieldTurretConverter {
|
||||||
private def MakeMountings(obj : WeaponTurret) : List[InventoryItemData.InventoryItem] = {
|
private def MakeMountings(obj : WeaponTurret) : List[InventoryItemData.InventoryItem] = {
|
||||||
obj.Weapons.map({
|
obj.Weapons.map({
|
||||||
case((index, slot)) =>
|
case(index, slot) =>
|
||||||
val equip : Equipment = slot.Equipment.get
|
val equip : Equipment = slot.Equipment.get
|
||||||
val equipDef = equip.Definition
|
val equipDef = equip.Definition
|
||||||
InventoryItemData(equipDef.ObjectId, equip.GUID, index, equipDef.Packet.ConstructorData(equip).get)
|
InventoryItemData(equipDef.ObjectId, equip.GUID, index, equipDef.Packet.ConstructorData(equip).get)
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -3,12 +3,39 @@ package net.psforever.objects.definition.converter
|
||||||
|
|
||||||
import net.psforever.objects.PlanetSideGameObject
|
import net.psforever.objects.PlanetSideGameObject
|
||||||
import net.psforever.objects.ce.TelepadLike
|
import net.psforever.objects.ce.TelepadLike
|
||||||
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
import net.psforever.packet.game.objectcreate._
|
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]() {
|
class InternalTelepadDeployableConverter extends ObjectCreateConverter[PlanetSideGameObject with TelepadLike]() {
|
||||||
override def ConstructorData(obj : PlanetSideGameObject with TelepadLike) : Try[ContainedTelepadDeployableData] = {
|
override def ConstructorData(obj : PlanetSideGameObject with TelepadLike) : Try[TelepadDeployableData] = {
|
||||||
Success(ContainedTelepadDeployableData(101, obj.Router.get))
|
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"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@
|
||||||
package net.psforever.objects.definition.converter
|
package net.psforever.objects.definition.converter
|
||||||
|
|
||||||
import net.psforever.objects.Kit
|
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}
|
import scala.util.{Success, Try}
|
||||||
|
|
||||||
class KitConverter extends ObjectCreateConverter[Kit]() {
|
class KitConverter extends ObjectCreateConverter[Kit]() {
|
||||||
override def ConstructorData(obj : Kit) : Try[AmmoBoxData] = {
|
override def ConstructorData(obj : Kit) : Try[CommonFieldData] = {
|
||||||
Success(AmmoBoxData())
|
Success(CommonFieldData()(false))
|
||||||
}
|
}
|
||||||
|
|
||||||
override def DetailedConstructorData(obj : Kit) : Try[DetailedAmmoBoxData] = {
|
override def DetailedConstructorData(obj : Kit) : Try[DetailedAmmoBoxData] = {
|
||||||
|
|
|
||||||
|
|
@ -4,21 +4,34 @@ package net.psforever.objects.definition.converter
|
||||||
import net.psforever.objects.LockerContainer
|
import net.psforever.objects.LockerContainer
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.Equipment
|
||||||
import net.psforever.objects.inventory.GridInventory
|
import net.psforever.objects.inventory.GridInventory
|
||||||
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
import net.psforever.packet.game.objectcreate._
|
import net.psforever.packet.game.objectcreate._
|
||||||
|
import net.psforever.types.PlanetSideEmpire
|
||||||
|
|
||||||
import scala.util.{Success, Try}
|
import scala.util.{Success, Try}
|
||||||
|
|
||||||
class LockerContainerConverter extends ObjectCreateConverter[LockerContainer]() {
|
class LockerContainerConverter extends ObjectCreateConverter[LockerContainer]() {
|
||||||
override def ConstructorData(obj : LockerContainer) : Try[LockerContainerData] = {
|
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] = {
|
override def DetailedConstructorData(obj : LockerContainer) : Try[DetailedLockerContainerData] = {
|
||||||
if(obj.Inventory.Size > 0) {
|
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 {
|
else {
|
||||||
Success(DetailedLockerContainerData(8, None))
|
Success(DetailedLockerContainerData(
|
||||||
|
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)),
|
||||||
|
None
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,45 @@
|
||||||
package net.psforever.objects.definition.converter
|
package net.psforever.objects.definition.converter
|
||||||
|
|
||||||
import net.psforever.objects.SimpleItem
|
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}
|
import scala.util.{Success, Try}
|
||||||
|
|
||||||
class REKConverter extends ObjectCreateConverter[SimpleItem]() {
|
class REKConverter extends ObjectCreateConverter[SimpleItem]() {
|
||||||
override def ConstructorData(obj : SimpleItem) : Try[REKData] = {
|
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] = {
|
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)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,21 +9,26 @@ import scala.util.{Failure, Success, Try}
|
||||||
|
|
||||||
class ShieldGeneratorConverter extends ObjectCreateConverter[ShieldGeneratorDeployable]() {
|
class ShieldGeneratorConverter extends ObjectCreateConverter[ShieldGeneratorDeployable]() {
|
||||||
override def ConstructorData(obj : ShieldGeneratorDeployable) : Try[AegisShieldGeneratorData] = {
|
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) {
|
if(health > 0) {
|
||||||
Success(
|
Success(
|
||||||
AegisShieldGeneratorData(
|
AegisShieldGeneratorData(
|
||||||
CommonFieldData(
|
CommonFieldDataWithPlacement(
|
||||||
PlacementData(obj.Position, obj.Orientation),
|
PlacementData(obj.Position, obj.Orientation),
|
||||||
obj.Faction,
|
CommonFieldData(
|
||||||
bops = false,
|
obj.Faction,
|
||||||
destroyed = false,
|
bops = false,
|
||||||
unk = 0,
|
alternate = false,
|
||||||
jammered = false,
|
v1 = false,
|
||||||
obj.Owner match {
|
v2 = None,
|
||||||
case Some(owner) => owner
|
v3 = false,
|
||||||
case None => PlanetSideGUID(0)
|
None,
|
||||||
}
|
None,
|
||||||
|
obj.Owner match {
|
||||||
|
case Some(owner) => owner
|
||||||
|
case None => PlanetSideGUID(0)
|
||||||
|
}
|
||||||
|
)
|
||||||
),
|
),
|
||||||
health
|
health
|
||||||
)
|
)
|
||||||
|
|
@ -32,14 +37,19 @@ class ShieldGeneratorConverter extends ObjectCreateConverter[ShieldGeneratorDepl
|
||||||
else {
|
else {
|
||||||
Success(
|
Success(
|
||||||
AegisShieldGeneratorData(
|
AegisShieldGeneratorData(
|
||||||
CommonFieldData(
|
CommonFieldDataWithPlacement(
|
||||||
PlacementData(obj.Position, obj.Orientation),
|
PlacementData(obj.Position, obj.Orientation),
|
||||||
obj.Faction,
|
CommonFieldData(
|
||||||
bops = false,
|
obj.Faction,
|
||||||
destroyed = true,
|
bops = false,
|
||||||
unk = 0,
|
alternate = true,
|
||||||
jammered = false,
|
v1 = false,
|
||||||
player_guid = PlanetSideGUID(0)
|
v2 = None,
|
||||||
|
v3 = false,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
PlanetSideGUID(0)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
0
|
0
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -4,29 +4,33 @@ package net.psforever.objects.definition.converter
|
||||||
import net.psforever.objects.ce.Deployable
|
import net.psforever.objects.ce.Deployable
|
||||||
import net.psforever.objects.PlanetSideGameObject
|
import net.psforever.objects.PlanetSideGameObject
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
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}
|
import scala.util.{Failure, Success, Try}
|
||||||
|
|
||||||
class SmallDeployableConverter extends ObjectCreateConverter[PlanetSideGameObject with Deployable]() {
|
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(
|
Success(
|
||||||
SmallDeployableData(
|
CommonFieldDataWithPlacement(
|
||||||
PlacementData(obj.Position, obj.Orientation),
|
PlacementData(obj.Position, obj.Orientation),
|
||||||
obj.Faction,
|
CommonFieldData(
|
||||||
bops = false,
|
obj.Faction,
|
||||||
destroyed = false,
|
false,
|
||||||
unk1 = 0,
|
false,
|
||||||
jammered = false,
|
false,
|
||||||
unk2 = false,
|
None,
|
||||||
obj.Owner match {
|
false,
|
||||||
case Some(owner) => owner
|
Some(false),
|
||||||
case None => PlanetSideGUID(0)
|
None,
|
||||||
}
|
obj.Owner match {
|
||||||
|
case Some(owner) => owner
|
||||||
|
case None => PlanetSideGUID(0)
|
||||||
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def DetailedConstructorData(obj : PlanetSideGameObject with Deployable) : Try[SmallDeployableData] =
|
override def DetailedConstructorData(obj : PlanetSideGameObject with Deployable) : Try[CommonFieldDataWithPlacement] =
|
||||||
Failure(new Exception("converter should not be used to generate detailed SmallDeployableData"))
|
Failure(new Exception("converter should not be used to generate detailed small deployable data"))
|
||||||
}
|
}
|
||||||
|
|
@ -11,22 +11,26 @@ import scala.util.{Failure, Success, Try}
|
||||||
|
|
||||||
class SmallTurretConverter extends ObjectCreateConverter[TurretDeployable]() {
|
class SmallTurretConverter extends ObjectCreateConverter[TurretDeployable]() {
|
||||||
override def ConstructorData(obj : TurretDeployable) : Try[SmallTurretData] = {
|
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) {
|
if(health > 0) {
|
||||||
Success(
|
Success(
|
||||||
SmallTurretData(
|
SmallTurretData(
|
||||||
SmallDeployableData(
|
CommonFieldDataWithPlacement(
|
||||||
PlacementData(obj.Position, obj.Orientation),
|
PlacementData(obj.Position, obj.Orientation),
|
||||||
obj.Faction,
|
CommonFieldData(
|
||||||
bops = false,
|
obj.Faction,
|
||||||
destroyed = false,
|
bops = false,
|
||||||
unk1 = 0,
|
alternate = false,
|
||||||
obj.Jammered,
|
false,
|
||||||
unk2 = false,
|
None,
|
||||||
obj.Owner match {
|
false,
|
||||||
case Some(owner) => owner
|
Some(true),
|
||||||
case None => PlanetSideGUID(0)
|
None,
|
||||||
}
|
obj.Owner match {
|
||||||
|
case Some(owner) => owner
|
||||||
|
case None => PlanetSideGUID(0)
|
||||||
|
}
|
||||||
|
)
|
||||||
),
|
),
|
||||||
health,
|
health,
|
||||||
Some(InventoryData(SmallTurretConverter.MakeMountings(obj)))
|
Some(InventoryData(SmallTurretConverter.MakeMountings(obj)))
|
||||||
|
|
@ -36,18 +40,21 @@ class SmallTurretConverter extends ObjectCreateConverter[TurretDeployable]() {
|
||||||
else {
|
else {
|
||||||
Success(
|
Success(
|
||||||
SmallTurretData(
|
SmallTurretData(
|
||||||
SmallDeployableData(
|
CommonFieldDataWithPlacement(
|
||||||
PlacementData(obj.Position, obj.Orientation),
|
PlacementData(obj.Position, obj.Orientation),
|
||||||
obj.Faction,
|
CommonFieldData(
|
||||||
bops = false,
|
obj.Faction,
|
||||||
destroyed = true,
|
bops = false,
|
||||||
unk1 = 0,
|
alternate = true,
|
||||||
jammered = false,
|
false,
|
||||||
unk2 = false,
|
None,
|
||||||
owner_guid = PlanetSideGUID(0)
|
false,
|
||||||
|
Some(false),
|
||||||
|
None,
|
||||||
|
PlanetSideGUID(0)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
0,
|
0
|
||||||
None
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
package net.psforever.objects.definition.converter
|
package net.psforever.objects.definition.converter
|
||||||
|
|
||||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
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}
|
import scala.util.{Success, Try}
|
||||||
|
|
||||||
class SpawnTubeConverter extends ObjectCreateConverter[SpawnTube]() {
|
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)) }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.<br>
|
||||||
|
* <br>
|
||||||
|
* 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
|
||||||
|
}
|
||||||
|
|
@ -9,22 +9,26 @@ import scala.util.{Failure, Success, Try}
|
||||||
|
|
||||||
class TRAPConverter extends ObjectCreateConverter[TrapDeployable]() {
|
class TRAPConverter extends ObjectCreateConverter[TrapDeployable]() {
|
||||||
override def ConstructorData(obj : TrapDeployable) : Try[TRAPData] = {
|
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) {
|
if(health > 0) {
|
||||||
Success(
|
Success(
|
||||||
TRAPData(
|
TRAPData(
|
||||||
SmallDeployableData(
|
CommonFieldDataWithPlacement(
|
||||||
PlacementData(obj.Position, obj.Orientation),
|
PlacementData(obj.Position, obj.Orientation),
|
||||||
obj.Faction,
|
CommonFieldData(
|
||||||
bops = false,
|
obj.Faction,
|
||||||
destroyed = false,
|
bops = false,
|
||||||
unk1 = 0,
|
alternate = false,
|
||||||
jammered = false,
|
true,
|
||||||
unk2 = false,
|
None,
|
||||||
obj.Owner match {
|
false,
|
||||||
case Some(owner) => owner
|
Some(true),
|
||||||
case None => PlanetSideGUID(0)
|
None,
|
||||||
}
|
obj.Owner match {
|
||||||
|
case Some(owner) => owner
|
||||||
|
case None => PlanetSideGUID(0)
|
||||||
|
}
|
||||||
|
)
|
||||||
),
|
),
|
||||||
health
|
health
|
||||||
)
|
)
|
||||||
|
|
@ -33,15 +37,19 @@ class TRAPConverter extends ObjectCreateConverter[TrapDeployable]() {
|
||||||
else {
|
else {
|
||||||
Success(
|
Success(
|
||||||
TRAPData(
|
TRAPData(
|
||||||
SmallDeployableData(
|
CommonFieldDataWithPlacement(
|
||||||
PlacementData(obj.Position, obj.Orientation),
|
PlacementData(obj.Position, obj.Orientation),
|
||||||
obj.Faction,
|
CommonFieldData(
|
||||||
bops = false,
|
obj.Faction,
|
||||||
destroyed = true,
|
bops = false,
|
||||||
unk1 = 0,
|
alternate = true,
|
||||||
jammered = false,
|
true,
|
||||||
unk2 = false,
|
None,
|
||||||
owner_guid = PlanetSideGUID(0)
|
false,
|
||||||
|
Some(true),
|
||||||
|
None,
|
||||||
|
PlanetSideGUID(0)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
0
|
0
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -2,24 +2,53 @@
|
||||||
package net.psforever.objects.definition.converter
|
package net.psforever.objects.definition.converter
|
||||||
|
|
||||||
import net.psforever.objects.Telepad
|
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}
|
import scala.util.{Failure, Success, Try}
|
||||||
|
|
||||||
class TelepadConverter extends ObjectCreateConverter[Telepad]() {
|
class TelepadConverter extends ObjectCreateConverter[Telepad]() {
|
||||||
override def ConstructorData(obj : Telepad) : Try[TelepadData] = {
|
override def ConstructorData(obj : Telepad) : Try[HandheldData] = {
|
||||||
obj.Router match {
|
obj.Router match {
|
||||||
case Some(_) =>
|
case Some(router) =>
|
||||||
Success(TelepadData (0, obj.Router))
|
Success(
|
||||||
|
HandheldData(
|
||||||
|
CommonFieldData(
|
||||||
|
obj.Faction,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
Some(router.guid),
|
||||||
|
PlanetSideGUID(0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
case None =>
|
case None =>
|
||||||
Failure(new IllegalStateException("TelepadConverter: telepad needs to know id of its router"))
|
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 {
|
obj.Router match {
|
||||||
case Some(_) =>
|
case Some(router) =>
|
||||||
Success(DetailedTelepadData (0, obj.Router))
|
Success(
|
||||||
|
DetailedConstructionToolData(
|
||||||
|
CommonFieldData(
|
||||||
|
obj.Faction,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
Some(router.guid),
|
||||||
|
PlanetSideGUID(0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
case None =>
|
case None =>
|
||||||
Failure(new IllegalStateException("TelepadConverter: telepad needs to know id of its router"))
|
Failure(new IllegalStateException("TelepadConverter: telepad needs to know id of its router"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,39 +8,59 @@ import net.psforever.packet.game.objectcreate._
|
||||||
import scala.util.{Failure, Success, Try}
|
import scala.util.{Failure, Success, Try}
|
||||||
|
|
||||||
class TelepadDeployableConverter extends ObjectCreateConverter[TelepadDeployable]() {
|
class TelepadDeployableConverter extends ObjectCreateConverter[TelepadDeployable]() {
|
||||||
override def ConstructorData(obj : TelepadDeployable) : Try[TelepadDeployableData] = {
|
override def ConstructorData(obj : TelepadDeployable) : Try[DroppedItemData[TelepadDeployableData]] = {
|
||||||
if(obj.Router.isEmpty || obj.Router.contains(PlanetSideGUID(0))) {
|
obj.Router match {
|
||||||
Failure(new IllegalStateException("TelepadDeployableConverter: telepad deployable needs to know id of its router"))
|
case Some(PlanetSideGUID(0)) =>
|
||||||
}
|
Failure(new IllegalStateException("TelepadDeployableConverter: knowledge of associated Router is null"))
|
||||||
else {
|
|
||||||
if(obj.Health > 0) {
|
case Some(router) =>
|
||||||
Success(TelepadDeployableData(
|
if(obj.Health > 0) {
|
||||||
PlacementData(obj.Position, obj.Orientation),
|
Success(
|
||||||
obj.Faction,
|
DroppedItemData(
|
||||||
bops = false,
|
PlacementData(obj.Position, obj.Orientation),
|
||||||
destroyed = false,
|
TelepadDeployableData(
|
||||||
unk1 = 2,
|
CommonFieldData(
|
||||||
unk2 = true,
|
obj.Faction,
|
||||||
obj.Router.get,
|
bops = false,
|
||||||
obj.Owner.getOrElse(PlanetSideGUID(0)),
|
alternate = false,
|
||||||
unk3 = 87,
|
true,
|
||||||
unk4 = 12
|
None,
|
||||||
))
|
false,
|
||||||
}
|
None,
|
||||||
else {
|
Some(router.guid),
|
||||||
Success(TelepadDeployableData(
|
obj.Owner.getOrElse(PlanetSideGUID(0))
|
||||||
PlacementData(obj.Position, obj.Orientation),
|
),
|
||||||
obj.Faction,
|
unk1 = 87,
|
||||||
bops = false,
|
unk2 = 12
|
||||||
destroyed = true,
|
)
|
||||||
unk1 = 2,
|
)
|
||||||
unk2 = true,
|
)
|
||||||
obj.Router.get,
|
}
|
||||||
owner_guid = PlanetSideGUID(0),
|
else {
|
||||||
unk3 = 0,
|
Success(
|
||||||
unk4 = 6
|
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"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
package net.psforever.objects.definition.converter
|
package net.psforever.objects.definition.converter
|
||||||
|
|
||||||
import net.psforever.objects.serverobject.terminals.Terminal
|
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}
|
import scala.util.{Success, Try}
|
||||||
|
|
||||||
class TerminalConverter extends ObjectCreateConverter[Terminal]() {
|
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)) }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,29 +2,57 @@
|
||||||
package net.psforever.objects.definition.converter
|
package net.psforever.objects.definition.converter
|
||||||
|
|
||||||
import net.psforever.objects.Tool
|
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}
|
import scala.util.{Success, Try}
|
||||||
|
|
||||||
class ToolConverter extends ObjectCreateConverter[Tool]() {
|
class ToolConverter extends ObjectCreateConverter[Tool]() {
|
||||||
override def ConstructorData(obj : Tool) : Try[WeaponData] = {
|
override def ConstructorData(obj : Tool) : Try[WeaponData] = {
|
||||||
val maxSlot : Int = obj.MaxAmmoSlot
|
val slots : List[InternalSlot] = (0 until obj.MaxAmmoSlot).map(index => {
|
||||||
val slots : ListBuffer[InternalSlot] = ListBuffer[InternalSlot]()
|
|
||||||
(0 until maxSlot).foreach(index => {
|
|
||||||
val box = obj.AmmoSlots(index).Box
|
val box = obj.AmmoSlots(index).Box
|
||||||
slots += InternalSlot(box.Definition.ObjectId, box.GUID, index, box.Definition.Packet.ConstructorData(box).get)
|
InternalSlot(box.Definition.ObjectId, box.GUID, index, box.Definition.Packet.ConstructorData(box).get)
|
||||||
})
|
}).toList
|
||||||
Success(WeaponData(4,8, obj.FireModeIndex, slots.toList)(maxSlot))
|
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] = {
|
override def DetailedConstructorData(obj : Tool) : Try[DetailedWeaponData] = {
|
||||||
val maxSlot : Int = obj.MaxAmmoSlot
|
val slots : List[InternalSlot] = (0 until obj.MaxAmmoSlot).map(index => {
|
||||||
val slots : ListBuffer[InternalSlot] = ListBuffer[InternalSlot]()
|
|
||||||
(0 until maxSlot).foreach(index => {
|
|
||||||
val box = obj.AmmoSlots(index).Box
|
val box = obj.AmmoSlots(index).Box
|
||||||
slots += InternalSlot(box.Definition.ObjectId, box.GUID, index, box.Definition.Packet.DetailedConstructorData(box).get)
|
InternalSlot(box.Definition.ObjectId, box.GUID, index, box.Definition.Packet.DetailedConstructorData(box).get)
|
||||||
})
|
}).toList
|
||||||
Success(DetailedWeaponData(4,8, obj.FireModeIndex, slots.toList)(maxSlot))
|
Success(
|
||||||
|
DetailedWeaponData(
|
||||||
|
CommonFieldData(
|
||||||
|
obj.Faction,
|
||||||
|
bops = false,
|
||||||
|
alternate = false,
|
||||||
|
true,
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
PlanetSideGUID(0)
|
||||||
|
),
|
||||||
|
obj.FireModeIndex,
|
||||||
|
slots
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ package net.psforever.objects.definition.converter
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.Equipment
|
||||||
import net.psforever.objects.Vehicle
|
import net.psforever.objects.Vehicle
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
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 net.psforever.types.DriveState
|
||||||
|
|
||||||
import scala.util.{Failure, Success, Try}
|
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)"))
|
Failure(new Exception("VehicleConverter should not be used to generate detailed VehicleData (nothing should)"))
|
||||||
|
|
||||||
override def ConstructorData(obj : Vehicle) : Try[VehicleData] = {
|
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
|
if(health > 0) { //active
|
||||||
Success(
|
Success(
|
||||||
VehicleData(
|
VehicleData(
|
||||||
PlacementData(obj.Position, obj.Orientation, obj.Velocity),
|
PlacementData(obj.Position, obj.Orientation, obj.Velocity),
|
||||||
obj.Faction,
|
CommonFieldData(
|
||||||
bops = false,
|
obj.Faction,
|
||||||
destroyed = false,
|
bops = false,
|
||||||
unk1 = 0,
|
alternate = false,
|
||||||
obj.Jammered,
|
v1 = false,
|
||||||
unk2 = false,
|
v2 = None,
|
||||||
obj.Owner match {
|
v3 = false,
|
||||||
case Some(owner) => owner
|
v4 = Some(false),
|
||||||
case None => PlanetSideGUID(0)
|
v5 = None,
|
||||||
},
|
obj.Owner match {
|
||||||
|
case Some(owner) => owner
|
||||||
|
case None => PlanetSideGUID(0)
|
||||||
|
}
|
||||||
|
),
|
||||||
unk3 = false,
|
unk3 = false,
|
||||||
health,
|
health,
|
||||||
unk4 = false,
|
unk4 = false,
|
||||||
|
|
@ -46,13 +50,17 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() {
|
||||||
Success(
|
Success(
|
||||||
VehicleData(
|
VehicleData(
|
||||||
PlacementData(obj.Position, obj.Orientation),
|
PlacementData(obj.Position, obj.Orientation),
|
||||||
obj.Faction,
|
CommonFieldData(
|
||||||
bops = false,
|
obj.Faction,
|
||||||
destroyed = true,
|
bops = false,
|
||||||
unk1 = 0,
|
alternate = true,
|
||||||
jammered = false,
|
v1 = false,
|
||||||
unk2 = false,
|
v2 = None,
|
||||||
owner_guid = PlanetSideGUID(0),
|
v3 = false,
|
||||||
|
v4 = Some(false),
|
||||||
|
v5 = None,
|
||||||
|
guid = PlanetSideGUID(0)
|
||||||
|
),
|
||||||
unk3 = false,
|
unk3 = false,
|
||||||
health = 0,
|
health = 0,
|
||||||
unk4 = false,
|
unk4 = false,
|
||||||
|
|
@ -80,7 +88,7 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() {
|
||||||
|
|
||||||
private def MakeMountings(obj : Vehicle) : List[InventoryItemData.InventoryItem] = {
|
private def MakeMountings(obj : Vehicle) : List[InventoryItemData.InventoryItem] = {
|
||||||
obj.Weapons.map({
|
obj.Weapons.map({
|
||||||
case((index, slot)) =>
|
case(index, slot) =>
|
||||||
val equip : Equipment = slot.Equipment.get
|
val equip : Equipment = slot.Equipment.get
|
||||||
val equipDef = equip.Definition
|
val equipDef = equip.Definition
|
||||||
InventoryItemData(equipDef.ObjectId, equip.GUID, index, equipDef.Packet.ConstructorData(equip).get)
|
InventoryItemData(equipDef.ObjectId, equip.GUID, index, equipDef.Packet.ConstructorData(equip).get)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.equipment
|
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 {
|
object CItem extends Enumeration {
|
||||||
final val ace = Value(32)
|
final val ace = Value(32)
|
||||||
final val advanced_ace = Value(39) //fdu
|
final val advanced_ace = Value(39) //fdu
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ package net.psforever.objects.equipment
|
||||||
import net.psforever.objects.PlanetSideGameObject
|
import net.psforever.objects.PlanetSideGameObject
|
||||||
import net.psforever.objects.definition.EquipmentDefinition
|
import net.psforever.objects.definition.EquipmentDefinition
|
||||||
import net.psforever.objects.inventory.InventoryTile
|
import net.psforever.objects.inventory.InventoryTile
|
||||||
|
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||||
|
import net.psforever.types.PlanetSideEmpire
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* `Equipment` is anything that can be:
|
* `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, special carried (like a lattice logic unit);
|
||||||
* and, dropped on the ground in the game world and render where it was deposited.
|
* 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 Size : EquipmentSize.Value = Definition.Size
|
||||||
|
|
||||||
def Tile : InventoryTile = Definition.Tile
|
def Tile : InventoryTile = Definition.Tile
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.equipment
|
package net.psforever.objects.equipment
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An `Enumeration` of common equipment sizes in the game.
|
||||||
|
* Check the comments for originating use.
|
||||||
|
*/
|
||||||
object EquipmentSize extends Enumeration {
|
object EquipmentSize extends Enumeration {
|
||||||
val
|
val
|
||||||
Blocked,
|
Blocked,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects
|
package net.psforever.objects.equipment
|
||||||
|
|
||||||
import net.psforever.objects.equipment.{Equipment, EquipmentSize}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A size-checked unit of storage (or mounting) for `Equipment`.
|
* A size-checked unit of storage (or mounting) for `Equipment`.
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.equipment
|
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 {
|
object SItem extends Enumeration {
|
||||||
final val boomer_trigger = Value(149)
|
final val boomer_trigger = Value(149)
|
||||||
final val command_detonater = Value(213) //cud
|
final val command_detonater = Value(213) //cud
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package net.psforever.objects.guid
|
||||||
|
|
||||||
import akka.actor.ActorRef
|
import akka.actor.ActorRef
|
||||||
import net.psforever.objects.entity.IdentifiableEntity
|
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._
|
||||||
import net.psforever.objects.inventory.Container
|
import net.psforever.objects.inventory.Container
|
||||||
import net.psforever.objects.serverobject.turret.WeaponTurret
|
import net.psforever.objects.serverobject.turret.WeaponTurret
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.inventory
|
package net.psforever.objects.inventory
|
||||||
|
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.{Equipment, EquipmentSlot}
|
||||||
import net.psforever.objects.{EquipmentSlot, OffhandEquipmentSlot}
|
import net.psforever.objects.OffhandEquipmentSlot
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
|
|
||||||
import scala.util.Try
|
import scala.util.Try
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,7 @@ package net.psforever.objects.inventory
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.{Equipment, EquipmentSlot}
|
||||||
import net.psforever.objects.EquipmentSlot
|
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package net.psforever.objects.loadouts
|
||||||
|
|
||||||
import net.psforever.objects._
|
import net.psforever.objects._
|
||||||
import net.psforever.objects.definition._
|
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 net.psforever.objects.inventory.InventoryItem
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
|
|
|
||||||
|
|
@ -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"
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
// Copyright (c) 2017 PSForever
|
|
||||||
package net.psforever.objects.serverobject.terminals
|
|
||||||
|
|
||||||
class BFRTerminalDefinition extends VehicleTerminalDefinition(143) {
|
|
||||||
vehicles = bfrVehicles
|
|
||||||
Name = "bfr_terminal"
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +1,14 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.serverobject.terminals
|
package net.psforever.objects.serverobject.terminals
|
||||||
|
|
||||||
import net.psforever.objects.Player
|
|
||||||
import net.psforever.packet.game.ItemTransactionMessage
|
|
||||||
import net.psforever.types.CertificationType
|
import net.psforever.types.CertificationType
|
||||||
|
|
||||||
/**
|
object CertTerminalDefinition {
|
||||||
* 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"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The certifications available.
|
* The certifications available.
|
||||||
* All entries are listed on page (tab) number 0.
|
* 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,
|
"medium_assault" -> CertificationType.MediumAssault,
|
||||||
"reinforced_armor" -> CertificationType.ReinforcedExoSuit,
|
"reinforced_armor" -> CertificationType.ReinforcedExoSuit,
|
||||||
"quad_all" -> CertificationType.ATV,
|
"quad_all" -> CertificationType.ATV,
|
||||||
|
|
@ -59,34 +51,4 @@ class CertTerminalDefinition extends TerminalDefinition(171) {
|
||||||
"advanced_medical" -> CertificationType.AdvancedMedical
|
"advanced_medical" -> CertificationType.AdvancedMedical
|
||||||
//TODO bfr certification entries
|
//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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"
|
|
||||||
}
|
|
||||||
|
|
@ -10,24 +10,6 @@ import net.psforever.types.ExoSuitType
|
||||||
|
|
||||||
import scala.annotation.switch
|
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 {
|
object EquipmentTerminalDefinition {
|
||||||
private[this] val log = org.log4s.getLogger("TerminalDefinition")
|
private[this] val log = org.log4s.getLogger("TerminalDefinition")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -4,29 +4,19 @@ package net.psforever.objects.serverobject.terminals
|
||||||
import akka.actor.ActorContext
|
import akka.actor.ActorContext
|
||||||
import net.psforever.objects.Player
|
import net.psforever.objects.Player
|
||||||
import net.psforever.objects.serverobject.structures.Amenity
|
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".
|
* 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) {
|
class MatrixTerminalDefinition(objectId : Int) extends TerminalDefinition(objectId) {
|
||||||
Name = if(object_id == 517) {
|
def Request(player : Player, msg : Any) : Terminal.Exchange = Terminal.NoDeal()
|
||||||
"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()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object MatrixTerminalDefinition {
|
object MatrixTerminalDefinition {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.serverobject.terminals
|
package net.psforever.objects.serverobject.terminals
|
||||||
|
|
||||||
|
import net.psforever.objects.Player
|
||||||
|
|
||||||
import scala.concurrent.duration.{Duration, FiniteDuration}
|
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.
|
* 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).
|
* 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 interval : FiniteDuration = Duration(0, "seconds")
|
||||||
private var healAmount : Int = 0
|
private var healAmount : Int = 0
|
||||||
private var armorAmount : Int = 0
|
private var armorAmount : Int = 0
|
||||||
|
|
@ -37,4 +39,6 @@ class MedicalTerminalDefinition(objectId : Int) extends TerminalDefinition(objec
|
||||||
armorAmount = amount
|
armorAmount = amount
|
||||||
ArmorAmount
|
ArmorAmount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def Request(player : Player, msg : Any) : Terminal.Exchange = Terminal.NoDeal()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.<br>
|
|
||||||
* <br>
|
|
||||||
* `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}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -10,61 +10,39 @@ import net.psforever.objects.inventory.InventoryItem
|
||||||
import net.psforever.objects.serverobject.structures.Amenity
|
import net.psforever.objects.serverobject.structures.Amenity
|
||||||
import net.psforever.packet.game.ItemTransactionMessage
|
import net.psforever.packet.game.ItemTransactionMessage
|
||||||
import net.psforever.objects.serverobject.terminals.EquipmentTerminalDefinition._
|
import net.psforever.objects.serverobject.terminals.EquipmentTerminalDefinition._
|
||||||
import net.psforever.types.{CertificationType, ExoSuitType}
|
import net.psforever.types.{CertificationType, ExoSuitType, TransactionType}
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The definition for any `Terminal` that is of a type "order_terminal".
|
* The definition for any `Terminal` from which specifications can be altered.
|
||||||
* This kind of "order_terminal" is applicable to facilities.<br>
|
* 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.<br>
|
||||||
* <br>
|
* <br>
|
||||||
* `Buy` and `Sell` `Equipment` items and `AmmoBox` items.
|
* Equipment terminals are the property of bases and vehicles ("amenities").
|
||||||
* Change `ExoSuitType` and retrieve `Loadout` entries.
|
* 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) {
|
class OrderTerminalDefinition(objId : Int) extends TerminalDefinition(objId) {
|
||||||
Name = "order_terminal"
|
/** 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
|
||||||
|
|
||||||
/**
|
def Tab : mutable.HashMap[Int, OrderTerminalDefinition.Tab] = tabs
|
||||||
* 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 SellEquipmentByDefault : Boolean = sellEquipmentDefault
|
def SellEquipmentByDefault : Boolean = sellEquipmentDefault
|
||||||
|
|
||||||
|
|
@ -73,8 +51,24 @@ class _OrderTerminalDefinition(objId : Int) extends TerminalDefinition(objId) {
|
||||||
SellEquipmentByDefault
|
SellEquipmentByDefault
|
||||||
}
|
}
|
||||||
|
|
||||||
override def Buy(player: Player, msg : ItemTransactionMessage) : Terminal.Exchange = {
|
def Request(player : Player, msg : Any) : Terminal.Exchange = msg match {
|
||||||
pages.get(msg.item_page) 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) =>
|
case Some(page) =>
|
||||||
page.Buy(player, msg)
|
page.Buy(player, msg)
|
||||||
case _ =>
|
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) {
|
if(sellEquipmentDefault) {
|
||||||
Terminal.SellEquipment()
|
Terminal.SellEquipment()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pages.get(msg.item_page) match {
|
tabs.get(msg.item_page) match {
|
||||||
case Some(page) =>
|
case Some(page) =>
|
||||||
page.Sell(player, msg)
|
page.Sell(player, msg)
|
||||||
case _ =>
|
case _ =>
|
||||||
|
|
@ -99,14 +93,24 @@ class _OrderTerminalDefinition(objId : Int) extends TerminalDefinition(objId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object _OrderTerminalDefinition {
|
object OrderTerminalDefinition {
|
||||||
abstract class PageDefinition(stock : Map[String, Any]) {
|
/**
|
||||||
def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange
|
* A basic tab outlining the specific type of stock available from this part of the terminal's interface.
|
||||||
def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange
|
* @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 {
|
stock.get(msg.item_name) match {
|
||||||
case Some((suit : ExoSuitType.Value, subtype : Int)) =>
|
case Some((suit : ExoSuitType.Value, subtype : Int)) =>
|
||||||
Terminal.BuyExosuit(suit, subtype)
|
Terminal.BuyExosuit(suit, subtype)
|
||||||
|
|
@ -114,12 +118,42 @@ object _OrderTerminalDefinition {
|
||||||
Terminal.NoDeal()
|
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 {
|
stock.get(msg.item_name) match {
|
||||||
case Some(cert : CertificationType.Value) =>
|
case Some(cert : CertificationType.Value) =>
|
||||||
Terminal.LearnCertification(cert)
|
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 {
|
stock.get(msg.item_name) match {
|
||||||
case Some(cert : CertificationType.Value) =>
|
case Some(cert : CertificationType.Value) =>
|
||||||
Terminal.SellCertification(cert)
|
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 {
|
stock.get(msg.item_name) match {
|
||||||
case Some(item : (()=>Equipment)) =>
|
case Some(item : (()=>Equipment)) =>
|
||||||
Terminal.BuyEquipment(item())
|
Terminal.BuyEquipment(item())
|
||||||
|
|
@ -147,12 +186,18 @@ object _OrderTerminalDefinition {
|
||||||
Terminal.NoDeal()
|
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 {
|
stock.get(msg.item_name) match {
|
||||||
case Some(implant : ImplantDefinition) =>
|
case Some(implant : ImplantDefinition) =>
|
||||||
Terminal.LearnImplant(implant)
|
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 {
|
stock.get(msg.item_name) match {
|
||||||
case Some(implant : ImplantDefinition) =>
|
case Some(implant : ImplantDefinition) =>
|
||||||
Terminal.SellImplant(implant)
|
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 {
|
player.LoadLoadout(msg.unk1) match {
|
||||||
case Some(loadout : InfantryLoadout) =>
|
case Some(loadout : InfantryLoadout) =>
|
||||||
val holsters = loadout.visible_slots.map(entry => { InventoryItem(BuildSimplifiedPattern(entry.item), entry.index) })
|
val holsters = loadout.visible_slots.map(entry => { InventoryItem(BuildSimplifiedPattern(entry.item), entry.index) })
|
||||||
|
|
@ -182,12 +238,20 @@ object _OrderTerminalDefinition {
|
||||||
Terminal.NoDeal()
|
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 {
|
player.LoadLoadout(msg.unk1 + 10) match {
|
||||||
case Some(loadout : VehicleLoadout) =>
|
case Some(loadout : VehicleLoadout) =>
|
||||||
val weapons = loadout.visible_slots.map(entry => { InventoryItem(BuildSimplifiedPattern(entry.item), entry.index) })
|
val weapons = loadout.visible_slots.map(entry => { InventoryItem(BuildSimplifiedPattern(entry.item), entry.index) })
|
||||||
|
|
@ -197,13 +261,21 @@ object _OrderTerminalDefinition {
|
||||||
Terminal.NoDeal()
|
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
|
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) {
|
final case class VehiclePage(stock : Map[String, ()=>Vehicle], trunk : Map[String, Contents]) extends Tab {
|
||||||
def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = {
|
override def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = {
|
||||||
stock.get(msg.item_name) match {
|
stock.get(msg.item_name) match {
|
||||||
case Some(vehicle) =>
|
case Some(vehicle) =>
|
||||||
val (weapons, inventory) = trunk.get(msg.item_name) match {
|
val (weapons, inventory) = trunk.get(msg.item_name) match {
|
||||||
|
|
@ -220,8 +292,6 @@ object _OrderTerminalDefinition {
|
||||||
Terminal.NoDeal()
|
Terminal.NoDeal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,23 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.serverobject.terminals
|
package net.psforever.objects.serverobject.terminals
|
||||||
|
|
||||||
import net.psforever.objects.{PlanetSideGameObject, Player}
|
import net.psforever.objects.PlanetSideGameObject
|
||||||
import net.psforever.packet.game.ItemTransactionMessage
|
import net.psforever.objects.definition.ObjectDefinition
|
||||||
|
|
||||||
import scala.collection.mutable
|
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
|
* This includes the limited proximity-based functionality of the formal medical terminals
|
||||||
* and the actual proximity-based functionality of the cavern crystals.
|
* 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 {
|
trait ProximityDefinition {
|
||||||
|
this : ObjectDefinition =>
|
||||||
|
|
||||||
private var useRadius : Float = 0f //TODO belongs on a wider range of object definitions
|
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
|
def UseRadius : Float = useRadius
|
||||||
|
|
||||||
|
|
@ -23,9 +26,9 @@ trait ProximityDefinition {
|
||||||
UseRadius
|
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 {
|
targetValidation.headOption match {
|
||||||
case Some(_) =>
|
case Some(_) =>
|
||||||
targetValidation.values.toSeq
|
targetValidation.values.toSeq
|
||||||
|
|
@ -33,10 +36,8 @@ trait ProximityDefinition {
|
||||||
Seq(ProximityDefinition.Invalid)
|
Seq(ProximityDefinition.Invalid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object ProximityDefinition {
|
object ProximityDefinition {
|
||||||
protected val Invalid : (PlanetSideGameObject=>Boolean) = (_ : PlanetSideGameObject) => false
|
protected val Invalid : PlanetSideGameObject=>Boolean = (_ : PlanetSideGameObject) => false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.serverobject.terminals
|
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.objects.serverobject.structures.Amenity
|
||||||
import net.psforever.types.Vector3
|
import net.psforever.types.Vector3
|
||||||
import services.Service
|
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.
|
* 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
|
* @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 {
|
object ProximityTerminal {
|
||||||
/**
|
/**
|
||||||
* Overloaded constructor.
|
* Overloaded constructor.
|
||||||
* @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
|
* @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)
|
new ProximityTerminal(tdef)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -33,7 +44,7 @@ object ProximityTerminal {
|
||||||
* @param context a context to allow the object to properly set up `ActorSystem` functionality
|
* @param context a context to allow the object to properly set up `ActorSystem` functionality
|
||||||
* @return the `Terminal` object
|
* @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
|
import akka.actor.Props
|
||||||
val obj = ProximityTerminal(tdef)
|
val obj = ProximityTerminal(tdef)
|
||||||
obj.Actor = context.actorOf(Props(classOf[ProximityTerminalControl], obj), s"${tdef.Name}_$id")
|
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.
|
* 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 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 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
|
* @param context a context to allow the object to properly set up `ActorSystem` functionality
|
||||||
* @return the `Terminal` object
|
* @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
|
import akka.actor.Props
|
||||||
val obj = ProximityTerminal(tdef)
|
val obj = ProximityTerminal(tdef)
|
||||||
obj.Position = pos
|
obj.Position = pos
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
@ -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}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -6,10 +6,14 @@ import net.psforever.objects.definition.VehicleDefinition
|
||||||
import net.psforever.objects.serverobject.hackable.Hackable
|
import net.psforever.objects.serverobject.hackable.Hackable
|
||||||
import net.psforever.objects.serverobject.structures.Amenity
|
import net.psforever.objects.serverobject.structures.Amenity
|
||||||
import net.psforever.packet.game.{ItemTransactionMessage, TriggeredSound}
|
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
|
* @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
|
||||||
*/
|
*/
|
||||||
class Terminal(tdef : TerminalDefinition) extends Amenity with Hackable {
|
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 player the player
|
||||||
* @param msg the original packet carrying the request
|
* @param msg the original packet carrying the request
|
||||||
* @return an actionable message that explains what resulted from interacting with this `Terminal`
|
* @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) {
|
if(Faction == player.Faction || HackedBy.isDefined) {
|
||||||
msg.transaction_type match {
|
tdef.Request(player, msg)
|
||||||
case TransactionType.Buy | TransactionType.Learn =>
|
|
||||||
Buy(player, msg)
|
|
||||||
|
|
||||||
case TransactionType.Sell =>
|
|
||||||
Sell(player, msg)
|
|
||||||
|
|
||||||
case TransactionType.Loadout =>
|
|
||||||
Loadout(player, msg)
|
|
||||||
|
|
||||||
case _ =>
|
|
||||||
Terminal.NoDeal()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Terminal.NoDeal()
|
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
|
def Definition : TerminalDefinition = tdef
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,9 @@ package net.psforever.objects.serverobject.terminals
|
||||||
|
|
||||||
import net.psforever.objects.Player
|
import net.psforever.objects.Player
|
||||||
import net.psforever.objects.definition.converter.TerminalConverter
|
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
|
* @param objectId the object's identifier number
|
||||||
*/
|
*/
|
||||||
abstract class TerminalDefinition(objectId : Int) extends net.psforever.objects.definition.ObjectDefinition(objectId) {
|
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
|
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
|
def Request(player : Player, msg : Any) : 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()
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"
|
|
||||||
}
|
|
||||||
|
|
@ -2,23 +2,17 @@
|
||||||
package net.psforever.objects.serverobject.terminals
|
package net.psforever.objects.serverobject.terminals
|
||||||
|
|
||||||
import net.psforever.objects.definition.VehicleDefinition
|
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.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 net.psforever.objects.GlobalDefinitions._
|
||||||
import VehicleTerminalDefinition.MakeVehicle
|
|
||||||
/**
|
/**
|
||||||
* A `Map` of operations for producing a ground-based `Vehicle`.
|
* A `Map` of operations for producing a ground-based `Vehicle`.
|
||||||
* key - an identification string sent by the client
|
* key - an identification string sent by the client
|
||||||
* value - a curried function that builds the object
|
* value - a curried function that builds the object
|
||||||
*/
|
*/
|
||||||
protected val groundVehicles : Map[String, () => Vehicle] = Map(
|
val groundVehicles : Map[String, () => Vehicle] = Map(
|
||||||
"quadassault" -> MakeVehicle(quadassault),
|
"quadassault" -> MakeVehicle(quadassault),
|
||||||
"fury" -> MakeVehicle(fury),
|
"fury" -> MakeVehicle(fury),
|
||||||
"quadstealth" -> MakeVehicle(quadstealth),
|
"quadstealth" -> MakeVehicle(quadstealth),
|
||||||
|
|
@ -50,7 +44,7 @@ abstract class VehicleTerminalDefinition(objId : Int) extends TerminalDefinition
|
||||||
* key - an identification string sent by the client
|
* key - an identification string sent by the client
|
||||||
* value - a curried function that builds the object
|
* value - a curried function that builds the object
|
||||||
*/
|
*/
|
||||||
protected val flight1Vehicles : Map[String, ()=>Vehicle] = Map(
|
val flight1Vehicles : Map[String, ()=>Vehicle] = Map(
|
||||||
"mosquito" -> MakeVehicle(mosquito),
|
"mosquito" -> MakeVehicle(mosquito),
|
||||||
"lightgunship" -> MakeVehicle(lightgunship),
|
"lightgunship" -> MakeVehicle(lightgunship),
|
||||||
"wasp" -> MakeVehicle(wasp),
|
"wasp" -> MakeVehicle(wasp),
|
||||||
|
|
@ -64,7 +58,7 @@ abstract class VehicleTerminalDefinition(objId : Int) extends TerminalDefinition
|
||||||
* key - an identification string sent by the client
|
* key - an identification string sent by the client
|
||||||
* value - a curried function that builds the object
|
* value - a curried function that builds the object
|
||||||
*/
|
*/
|
||||||
protected val flight2Vehicles : Map[String, ()=>Vehicle] = Map(
|
val flight2Vehicles : Map[String, ()=>Vehicle] = Map(
|
||||||
"dropship" -> MakeVehicle(dropship),
|
"dropship" -> MakeVehicle(dropship),
|
||||||
"galaxy_gunship" -> MakeVehicle(galaxy_gunship),
|
"galaxy_gunship" -> MakeVehicle(galaxy_gunship),
|
||||||
"lodestar" -> MakeVehicle(lodestar)
|
"lodestar" -> MakeVehicle(lodestar)
|
||||||
|
|
@ -75,7 +69,7 @@ abstract class VehicleTerminalDefinition(objId : Int) extends TerminalDefinition
|
||||||
* key - an identification string sent by the client
|
* key - an identification string sent by the client
|
||||||
* value - a curried function that builds the object
|
* 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_gunner" -> (()=>Unit),
|
||||||
// "colossus_flight" -> (()=>Unit),
|
// "colossus_flight" -> (()=>Unit),
|
||||||
// "peregrine_gunner" -> (()=>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)
|
* key - an identification string sent by the client (for the vehicle)
|
||||||
* value - a curried function that builds the object
|
* 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_12mm = ShorthandAmmoBox(bullet_12mm, bullet_12mm.Capacity)
|
||||||
val ammo_15mm = ShorthandAmmoBox(bullet_15mm, bullet_15mm.Capacity)
|
val ammo_15mm = ShorthandAmmoBox(bullet_15mm, bullet_15mm.Capacity)
|
||||||
val ammo_25mm = ShorthandAmmoBox(bullet_25mm, bullet_25mm.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.
|
* Create a new `Vehicle` from provided `VehicleDefinition` objects.
|
||||||
* @param vdef the `VehicleDefinition` object
|
* @param vdef the `VehicleDefinition` object
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package net.psforever.objects.serverobject.turret
|
||||||
|
|
||||||
import net.psforever.objects.definition.{AmmoBoxDefinition, SeatDefinition, ToolDefinition}
|
import net.psforever.objects.definition.{AmmoBoxDefinition, SeatDefinition, ToolDefinition}
|
||||||
import net.psforever.objects._
|
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.inventory.{Container, GridInventory}
|
||||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||||
import net.psforever.objects.serverobject.mount.Mountable
|
import net.psforever.objects.serverobject.mount.Mountable
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.vehicles
|
package net.psforever.objects.vehicles
|
||||||
|
|
||||||
import net.psforever.objects.{EquipmentSlot, PlanetSideGameObject}
|
import net.psforever.objects.PlanetSideGameObject
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.{Equipment, EquipmentSlot}
|
||||||
import net.psforever.objects.inventory.Container
|
import net.psforever.objects.inventory.Container
|
||||||
import net.psforever.objects.serverobject.mount.Mountable
|
import net.psforever.objects.serverobject.mount.Mountable
|
||||||
import net.psforever.objects.vehicles.{Seat => Chair}
|
import net.psforever.objects.vehicles.{Seat => Chair}
|
||||||
|
|
|
||||||
|
|
@ -45,11 +45,11 @@ object UtilityType extends Enumeration {
|
||||||
* Ostensibly, the purpose of the additional logic, when it is called,
|
* Ostensibly, the purpose of the additional logic, when it is called,
|
||||||
* is to initialize a control `Actor` for the contained object.
|
* is to initialize a control `Actor` for the contained object.
|
||||||
* This `Actor` is expected by other logic.
|
* This `Actor` is expected by other logic.
|
||||||
|
* @see `Amenity.Owner`
|
||||||
* @see `Vehicle.LoadDefinition`
|
* @see `Vehicle.LoadDefinition`
|
||||||
* @see `VehicleDefinition.Utilities`
|
* @see `VehicleDefinition.Utilities`
|
||||||
* @param util the type of the `Amenity` object to be created
|
* @param util the type of the `Amenity` object to be created
|
||||||
* @param vehicle the owner of this object
|
* @param vehicle the owner of this object
|
||||||
* @see `Amenity.Owner`
|
|
||||||
*/
|
*/
|
||||||
class Utility(util : UtilityType.Value, vehicle : Vehicle) {
|
class Utility(util : UtilityType.Value, vehicle : Vehicle) {
|
||||||
private val obj : Amenity = Utility.BuildUtilityFunc(util)
|
private val obj : Amenity = Utility.BuildUtilityFunc(util)
|
||||||
|
|
@ -154,9 +154,8 @@ object Utility {
|
||||||
* The `Terminal` `Utility` produced has proximity effects.
|
* The `Terminal` `Utility` produced has proximity effects.
|
||||||
* @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
|
* @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 UtilityWorldEntity
|
||||||
with ProximityUnit
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override for a `Terminal` object so that it inherits the spatial characteristics of its `Owner`.
|
* 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) {
|
class TeleportPadTerminalUtility(tdef : TerminalDefinition) extends TerminalUtility(tdef) {
|
||||||
/**
|
/**
|
||||||
* na
|
* This kind of `Terminal` object only produces one object of importance - a Router's telepad unit.
|
||||||
* @param player na
|
* When this `Telepad` object is produced, it shlould be associated with the Router,
|
||||||
* @param msg na
|
* that is, with the owner of the `Terminal` object.
|
||||||
* @return na
|
* @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 = {
|
override def Request(player : Player, msg : Any) : Terminal.Exchange = {
|
||||||
val reply = super.Buy(player, msg)
|
msg match {
|
||||||
reply match {
|
case message : ItemTransactionMessage =>
|
||||||
case Terminal.BuyEquipment(obj : Telepad) =>
|
val reply = super.Request(player, message)
|
||||||
obj.Router = Owner.GUID
|
reply match {
|
||||||
case _ => ;
|
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 =>
|
case UtilityType.ams_respawn_tube =>
|
||||||
SpawnTubeDefinition.Setup
|
SpawnTubeDefinition.Setup
|
||||||
case UtilityType.bfr_rearm_terminal =>
|
case UtilityType.bfr_rearm_terminal =>
|
||||||
_OrderTerminalDefinition.Setup
|
OrderTerminalDefinition.Setup
|
||||||
case UtilityType.lodestar_repair_terminal =>
|
case UtilityType.lodestar_repair_terminal =>
|
||||||
ProximityTerminal.Setup
|
ProximityTerminal.Setup
|
||||||
case UtilityType.matrix_terminalc =>
|
case UtilityType.matrix_terminalc =>
|
||||||
MatrixTerminalDefinition.Setup
|
MatrixTerminalDefinition.Setup
|
||||||
case UtilityType.multivehicle_rearm_terminal =>
|
case UtilityType.multivehicle_rearm_terminal =>
|
||||||
_OrderTerminalDefinition.Setup
|
OrderTerminalDefinition.Setup
|
||||||
case UtilityType.order_terminala =>
|
case UtilityType.order_terminala =>
|
||||||
OrderTerminalABDefinition.Setup
|
OrderTerminalDefinition.Setup
|
||||||
case UtilityType.order_terminalb =>
|
case UtilityType.order_terminalb =>
|
||||||
OrderTerminalABDefinition.Setup
|
OrderTerminalDefinition.Setup
|
||||||
case UtilityType.teleportpad_terminal =>
|
case UtilityType.teleportpad_terminal =>
|
||||||
TeleportPadTerminalDefinition.Setup
|
OrderTerminalDefinition.Setup
|
||||||
case UtilityType.internal_router_telepad_deployable =>
|
case UtilityType.internal_router_telepad_deployable =>
|
||||||
TelepadLike.Setup
|
TelepadLike.Setup
|
||||||
}
|
}
|
||||||
|
|
||||||
//private def defaultSetup(o1 : Amenity, o2 : ActorContext) : Unit = { }
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.vital.resistance
|
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.ballistics._
|
||||||
|
import net.psforever.objects.definition.ExoSuitDefinition
|
||||||
import net.psforever.objects.vital.projectile.ProjectileCalculations
|
import net.psforever.objects.vital.projectile.ProjectileCalculations
|
||||||
import net.psforever.types.ExoSuitType
|
import net.psforever.types.ExoSuitType
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -236,10 +236,10 @@ object PacketHelpers {
|
||||||
* A `peek` that decodes like the normal but encodes nothing.
|
* 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.
|
* 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.
|
* 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`
|
* @see `scodec.codecs.peek` or `codecs/package.scala:peek`
|
||||||
* @param target codec that decodes the value
|
* @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 peek[A](target: Codec[A]): Codec[A] = new Codec[A] {
|
||||||
def sizeBound = target.sizeBound
|
def sizeBound = target.sizeBound
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,22 @@ final case class DeployRequestMessage(player_guid : PlanetSideGUID,
|
||||||
}
|
}
|
||||||
|
|
||||||
object DeployRequestMessage extends Marshallable[DeployRequestMessage] {
|
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] = (
|
implicit val codec : Codec[DeployRequestMessage] = (
|
||||||
("player_guid" | PlanetSideGUID.codec) ::
|
("player_guid" | PlanetSideGUID.codec) ::
|
||||||
("vehicle_guid" | PlanetSideGUID.codec) ::
|
("vehicle_guid" | PlanetSideGUID.codec) ::
|
||||||
("deploy_state" | DriveState.codec) ::
|
("deploy_state" | driveState3u) ::
|
||||||
("unk2" | uint(5)) ::
|
("unk2" | uint(5)) ::
|
||||||
("unk3" | bool) ::
|
("unk3" | bool) ::
|
||||||
("pos" | Vector3.codec_pos)
|
("pos" | Vector3.codec_pos)
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ final case class ObjectCreateDetailedMessage(streamLength : Long,
|
||||||
objectClass : Int,
|
objectClass : Int,
|
||||||
guid : PlanetSideGUID,
|
guid : PlanetSideGUID,
|
||||||
parentInfo : Option[ObjectCreateMessageParent],
|
parentInfo : Option[ObjectCreateMessageParent],
|
||||||
data : Option[ConstructorData])
|
data : ConstructorData)
|
||||||
extends PlanetSideGamePacket {
|
extends PlanetSideGamePacket {
|
||||||
type Packet = ObjectCreateDetailedMessage
|
type Packet = ObjectCreateDetailedMessage
|
||||||
def opcode = GamePacketOpcode.ObjectCreateMessage
|
def opcode = GamePacketOpcode.ObjectCreateMessage
|
||||||
|
|
@ -57,7 +57,7 @@ object ObjectCreateDetailedMessage extends Marshallable[ObjectCreateDetailedMess
|
||||||
*/
|
*/
|
||||||
def apply(objectClass : Int, guid : PlanetSideGUID, parentInfo : ObjectCreateMessageParent, data : ConstructorData) : ObjectCreateDetailedMessage = {
|
def apply(objectClass : Int, guid : PlanetSideGUID, parentInfo : ObjectCreateMessageParent, data : ConstructorData) : ObjectCreateDetailedMessage = {
|
||||||
val parentInfoOpt : Option[ObjectCreateMessageParent] = Some(parentInfo)
|
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
|
* @return an ObjectCreateMessage
|
||||||
*/
|
*/
|
||||||
def apply(objectClass : Int, guid : PlanetSideGUID, data : ConstructorData) : ObjectCreateDetailedMessage = {
|
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] (
|
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"))
|
Attempt.failure(Err("no data to decode"))
|
||||||
|
|
||||||
case len :: cls :: guid :: par :: data :: HNil =>
|
case len :: cls :: guid :: par :: data :: HNil =>
|
||||||
val obj = ObjectCreateBase.decodeData(cls, data,
|
ObjectCreateBase.decodeData(cls, data,
|
||||||
if(par.isDefined) {
|
if(par.isDefined) {
|
||||||
ObjectClass.selectDataDetailedCodec
|
ObjectClass.selectDataDetailedCodec
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ObjectClass.selectDataDroppedDetailedCodec
|
ObjectClass.selectDataDroppedDetailedCodec
|
||||||
}
|
}
|
||||||
)
|
) match {
|
||||||
Attempt.successful(ObjectCreateDetailedMessage(len, cls, guid, par, obj))
|
case Attempt.Successful(obj) =>
|
||||||
|
Attempt.successful(ObjectCreateDetailedMessage(len, cls, guid, par, obj))
|
||||||
|
case Attempt.Failure(err) =>
|
||||||
|
Attempt.failure(err)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case ObjectCreateDetailedMessage(_ , _ , _, _, None) =>
|
case ObjectCreateDetailedMessage(_, cls, guid, par, obj) =>
|
||||||
Attempt.failure(Err("no object to encode"))
|
|
||||||
|
|
||||||
case ObjectCreateDetailedMessage(_, cls, guid, par, Some(obj)) =>
|
|
||||||
val len = ObjectCreateBase.streamLen(par, obj) //even if a stream length has been assigned, it can not be trusted during encoding
|
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) {
|
if(par.isDefined) {
|
||||||
ObjectClass.selectDataDetailedCodec
|
ObjectClass.selectDataDetailedCodec
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ObjectClass.selectDataDroppedDetailedCodec
|
ObjectClass.selectDataDroppedDetailedCodec
|
||||||
}
|
}
|
||||||
)
|
) match {
|
||||||
Attempt.successful(len :: cls :: guid :: par :: bitvec :: HNil)
|
case Attempt.Successful(bvec) =>
|
||||||
|
Attempt.successful(len :: cls :: guid :: par :: bvec :: HNil)
|
||||||
|
case Attempt.Failure(err) =>
|
||||||
|
Attempt.failure(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
package net.psforever.packet.game
|
package net.psforever.packet.game
|
||||||
|
|
||||||
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
|
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.{Attempt, Codec, Err}
|
||||||
import scodec.bits.BitVector
|
import scodec.bits.BitVector
|
||||||
import shapeless.{::, HNil}
|
import shapeless.{::, HNil}
|
||||||
|
|
@ -50,7 +50,7 @@ final case class ObjectCreateMessage(streamLength : Long,
|
||||||
objectClass : Int,
|
objectClass : Int,
|
||||||
guid : PlanetSideGUID,
|
guid : PlanetSideGUID,
|
||||||
parentInfo : Option[ObjectCreateMessageParent],
|
parentInfo : Option[ObjectCreateMessageParent],
|
||||||
data : Option[ConstructorData])
|
data : ConstructorData)
|
||||||
extends PlanetSideGamePacket {
|
extends PlanetSideGamePacket {
|
||||||
type Packet = ObjectCreateMessage
|
type Packet = ObjectCreateMessage
|
||||||
def opcode = GamePacketOpcode.ObjectCreateMessage_Duplicate
|
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 = {
|
def apply(objectClass : Int, guid : PlanetSideGUID, parentInfo : ObjectCreateMessageParent, data : ConstructorData) : ObjectCreateMessage = {
|
||||||
val parentInfoOpt : Option[ObjectCreateMessageParent] = Some(parentInfo)
|
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`
|
* @return an `ObjectCreateMessage`
|
||||||
*/
|
*/
|
||||||
def apply(objectClass : Int, guid : PlanetSideGUID, data : ConstructorData) : 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] (
|
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"))
|
Attempt.failure(Err("no data to decode"))
|
||||||
|
|
||||||
case len :: cls :: guid :: par :: data :: HNil =>
|
case len :: cls :: guid :: par :: data :: HNil =>
|
||||||
val obj = ObjectCreateBase.decodeData(cls, data,
|
ObjectCreateBase.decodeData(cls, data, if(par.isDefined) {
|
||||||
if(par.isDefined) {
|
ObjectClass.selectDataCodec
|
||||||
ObjectClass.selectDataCodec
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ObjectClass.selectDataDroppedCodec
|
ObjectClass.selectDataDroppedCodec
|
||||||
}
|
}
|
||||||
)
|
) match {
|
||||||
Attempt.successful(ObjectCreateMessage(len, cls, guid, par, obj))
|
case Attempt.Successful(obj) =>
|
||||||
|
Attempt.successful(ObjectCreateMessage(len, cls, guid, par, obj))
|
||||||
|
case Attempt.Failure(err) =>
|
||||||
|
Attempt.failure(err)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case ObjectCreateMessage(_ , _ , _, _, None) =>
|
case ObjectCreateMessage(_, cls, guid, par, obj) =>
|
||||||
Attempt.failure(Err("no object to encode"))
|
|
||||||
|
|
||||||
case ObjectCreateMessage(_, cls, guid, par, Some(obj)) =>
|
|
||||||
val len = ObjectCreateBase.streamLen(par, obj) //even if a stream length has been assigned, it can not be trusted during encoding
|
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) {
|
if(par.isDefined) {
|
||||||
ObjectClass.selectDataCodec
|
ObjectClass.selectDataCodec
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ObjectClass.selectDataDroppedCodec
|
ObjectClass.selectDataDroppedCodec
|
||||||
}
|
}
|
||||||
)
|
) match {
|
||||||
Attempt.successful(len :: cls :: guid :: par :: bitvec :: HNil)
|
case Attempt.Successful(bvec) =>
|
||||||
|
Attempt.successful(len :: cls :: guid :: par :: bvec :: HNil)
|
||||||
|
case Attempt.Failure(err) =>
|
||||||
|
Attempt.failure(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -11,7 +11,7 @@ import shapeless.{::, HNil}
|
||||||
* @param deploy data common to objects spawned by the (advanced) adaptive construction engine
|
* @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 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
|
health : Int
|
||||||
) extends ConstructorData {
|
) extends ConstructorData {
|
||||||
override def bitsize : Long = {
|
override def bitsize : Long = {
|
||||||
|
|
@ -21,15 +21,16 @@ final case class AegisShieldGeneratorData(deploy : CommonFieldData,
|
||||||
|
|
||||||
object AegisShieldGeneratorData extends Marshallable[AegisShieldGeneratorData] {
|
object AegisShieldGeneratorData extends Marshallable[AegisShieldGeneratorData] {
|
||||||
implicit val codec : Codec[AegisShieldGeneratorData] = (
|
implicit val codec : Codec[AegisShieldGeneratorData] = (
|
||||||
("deploy" | CommonFieldData.codec) ::
|
("deploy" | CommonFieldDataWithPlacement.codec) ::
|
||||||
("health" | uint8L) ::
|
("health" | uint8L) ::
|
||||||
uint32 :: uint32 :: uint32 :: uint4L //100 bits
|
uint32 :: uint32 :: uint32 :: uint4L //100 bits
|
||||||
).exmap[AegisShieldGeneratorData] (
|
).exmap[AegisShieldGeneratorData] (
|
||||||
{
|
{
|
||||||
case deploy :: health :: 0 :: 0 :: 0 :: 0 :: HNil =>
|
case deploy :: health :: 0 :: 0 :: 0 :: 0 :: HNil =>
|
||||||
Attempt.successful(AegisShieldGeneratorData(deploy, health))
|
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) =>
|
case AegisShieldGeneratorData(deploy, health) =>
|
||||||
|
|
|
||||||
|
|
@ -1,53 +1,26 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.packet.game.objectcreate
|
package net.psforever.packet.game.objectcreate
|
||||||
|
|
||||||
import net.psforever.packet.Marshallable
|
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
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.
|
* 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.
|
* 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.<br>
|
* It can also be constructed directly inside a weapon as its magazine.<br>
|
||||||
* <br>
|
* <br>
|
||||||
* This ammunition object ompletely ignores thr capacity field, normal to detailed ammunition objects.
|
* 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) reveals a single round.
|
* Creating an object of this type directly and picking it up or observing it (in a weapon) will reveals single round.
|
||||||
* @param unk na;
|
|
||||||
* defaults to 0
|
|
||||||
* @see `DetailedAmmoBoxData`
|
* @see `DetailedAmmoBoxData`
|
||||||
*/
|
*/
|
||||||
final case class AmmoBoxData(unk : Int = 0) extends ConstructorData {
|
object AmmoBoxData {
|
||||||
override def bitsize : Long = 24L
|
|
||||||
}
|
|
||||||
|
|
||||||
object AmmoBoxData extends Marshallable[AmmoBoxData] {
|
|
||||||
/**
|
/**
|
||||||
* An abbreviated constructor for creating `AmmoBoxData` while masking use of `InternalSlot`.
|
* An abbreviated constructor for creating `AmmoBoxData` while masking use of `InternalSlot`.
|
||||||
* @param cls the code for the type of object being constructed
|
* @param cls the code for the type of object being constructed
|
||||||
* @param guid the GUID this object will be assigned
|
* @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 parentSlot a parent-defined slot identifier that explains where the child is to be attached to the parent
|
||||||
* @param ammo the ammunition object
|
* @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)
|
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)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -50,8 +50,9 @@ object CaptureFlagData extends Marshallable[CaptureFlagData] {
|
||||||
{
|
{
|
||||||
case pos :: fac :: false :: 4 :: 0 :: unk1 :: 0 :: unk2 :: 0 :: unk3 :: unk4 :: 0 :: HNil =>
|
case pos :: fac :: false :: 4 :: 0 :: unk1 :: 0 :: unk2 :: 0 :: unk3 :: unk4 :: 0 :: HNil =>
|
||||||
Attempt.Successful(CaptureFlagData(pos, fac, unk1, unk2, unk3, unk4))
|
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) =>
|
case CaptureFlagData(pos, fac, unk1, unk2, unk3, unk4) =>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.packet.game.objectcreate
|
package net.psforever.packet.game.objectcreate
|
||||||
|
|
||||||
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
import net.psforever.packet.{Marshallable, PacketHelpers}
|
import net.psforever.packet.{Marshallable, PacketHelpers}
|
||||||
import net.psforever.types._
|
import net.psforever.types._
|
||||||
import scodec.{Attempt, Codec, Err}
|
import scodec.{Attempt, Codec, Err}
|
||||||
|
|
@ -12,22 +13,20 @@ import shapeless.{::, HNil}
|
||||||
* @see `CharacterData`
|
* @see `CharacterData`
|
||||||
* @see `DetailedCharacterData`
|
* @see `DetailedCharacterData`
|
||||||
* @see `ExoSuitType`
|
* @see `ExoSuitType`
|
||||||
* @param app the player's cardinal appearance settings
|
* @param app the player's cardinal appearance settings
|
||||||
* @param black_ops whether or not this avatar is enrolled in Black OPs
|
* @param data common field data<br>
|
||||||
* @param jammered the player has been caught in an EMP blast recently;
|
* -bops - this vehicle belongs to the Black Ops, regardless of the faction field;
|
||||||
* creates a jammered sound effect that follows the player around and can be heard by others
|
* activates the green camo and adjusts permissions<br>
|
||||||
* @param exosuit the type of exo-suit the avatar will be depicted in;
|
* -destroyed - flagged when using a model that is not the standard player in some stance<br>
|
||||||
* for Black OPs, the agile exo-suit and the reinforced exo-suit are replaced with the Black OPs exo-suits
|
* -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<br>
|
||||||
|
* -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,
|
final case class CharacterAppearanceA(app : BasicCharacterData,
|
||||||
black_ops : Boolean,
|
data : CommonFieldData,
|
||||||
altModel : Boolean,
|
|
||||||
unk1 : Boolean,
|
|
||||||
unk2 : Option[CharacterAppearanceData.ExtraData],
|
|
||||||
jammered : Boolean,
|
|
||||||
exosuit : ExoSuitType.Value,
|
exosuit : ExoSuitType.Value,
|
||||||
unk3 : Option[Int],
|
|
||||||
unk4 : Int,
|
|
||||||
unk5 : Int,
|
unk5 : Int,
|
||||||
unk6 : Long,
|
unk6 : Long,
|
||||||
unk7 : Int,
|
unk7 : Int,
|
||||||
|
|
@ -36,11 +35,9 @@ final case class CharacterAppearanceA(app : BasicCharacterData,
|
||||||
unkA : Int)
|
unkA : Int)
|
||||||
(name_padding : Int) extends StreamBitSize {
|
(name_padding : Int) extends StreamBitSize {
|
||||||
override def bitsize : Long = {
|
override def bitsize : Long = {
|
||||||
//factor guard bool values into the base size, not its corresponding optional field
|
val dataSize : Long = data.bitsize
|
||||||
val unk2Size : Long = unk2 match { case Some(n) => n.bitsize ; case None => 0L }
|
|
||||||
val nameStringSize : Long = StreamBitSize.stringBitSize(app.name, 16) + name_padding
|
val nameStringSize : Long = StreamBitSize.stringBitSize(app.name, 16) + name_padding
|
||||||
val unk3Size : Long = unk3 match { case Some(_) => 32L ; case None => 0L }
|
114L + dataSize + nameStringSize
|
||||||
137L + unk2Size + nameStringSize + unk3Size
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -162,14 +159,23 @@ object CharacterAppearanceData extends Marshallable[CharacterAppearanceData] {
|
||||||
val altModel : Boolean = backpack || on_zipline.isDefined
|
val altModel : Boolean = backpack || on_zipline.isDefined
|
||||||
val a = CharacterAppearanceA(
|
val a = CharacterAppearanceA(
|
||||||
app,
|
app,
|
||||||
black_ops,
|
CommonFieldData(
|
||||||
altModel,
|
app.faction,
|
||||||
false,
|
black_ops,
|
||||||
None,
|
altModel,
|
||||||
jammered,
|
false,
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
if(jammered) {
|
||||||
|
Some(0)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
PlanetSideGUID(0)
|
||||||
|
),
|
||||||
exosuit,
|
exosuit,
|
||||||
None,
|
|
||||||
0,
|
|
||||||
0,
|
0,
|
||||||
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 = {
|
def apply(a : Int=>CharacterAppearanceA, b : (Boolean,Int)=>CharacterAppearanceB, ribbons : RibbonBars)(name_padding : Int) : CharacterAppearanceData = {
|
||||||
val first = a(name_padding)
|
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
|
* @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) {
|
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 {
|
else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
def namePadding(inheritPad : Int, pad : Option[ExtraData]) : Int = {
|
def namePadding(inheritPad : Int, pad : Option[CommonFieldDataExtra]) : Int = {
|
||||||
pad match {
|
pad match {
|
||||||
case Some(n) =>
|
case Some(n) =>
|
||||||
val bitsize = n.bitsize.toInt % 8
|
val bitsize = n.bitsize.toInt % 8
|
||||||
|
|
@ -282,45 +293,48 @@ object CharacterAppearanceData extends Marshallable[CharacterAppearanceData] {
|
||||||
* @return na
|
* @return na
|
||||||
*/
|
*/
|
||||||
def a_codec(name_padding : Int) : Codec[CharacterAppearanceA] = (
|
def a_codec(name_padding : Int) : Codec[CharacterAppearanceA] = (
|
||||||
("faction" | PlanetSideEmpire.codec) ::
|
("data" | CommonFieldData.codec) >>:~ { data =>
|
||||||
("black_ops" | bool) ::
|
("name" | PacketHelpers.encodedWideStringAligned(namePadding(name_padding, data.v2))) ::
|
||||||
(("alt_model" | bool) >>:~ { alt_model => //modifies stream format (to display alternate player models)
|
("exosuit" | ExoSuitType.codec) ::
|
||||||
("unk1" | bool) :: //serves a different internal purpose depending on the state of alt_model
|
("unk5" | uint2) :: //unknown
|
||||||
(conditional(false, "unk2" | extra_codec) >>:~ { extra => //TODO not sure what causes this branch
|
("sex" | CharacterGender.codec) ::
|
||||||
("jammered" | bool) ::
|
("head" | uint8L) ::
|
||||||
optional(bool, "unk3" | uint16L) ::
|
("voice" | CharacterVoice.codec) ::
|
||||||
("unk4" | uint16L) ::
|
("unk6" | uint32L) ::
|
||||||
("name" | PacketHelpers.encodedWideStringAligned(namePadding(name_padding, extra))) ::
|
("unk7" | uint16L) ::
|
||||||
("exosuit" | ExoSuitType.codec) ::
|
("unk8" | uint16L) ::
|
||||||
("unk5" | uint2) :: //unknown
|
("unk9" | uint16L) ::
|
||||||
("sex" | CharacterGender.codec) ::
|
("unkA" | uint16L) //usually either 0 or 65535
|
||||||
("head" | uint8L) ::
|
}
|
||||||
("voice" | CharacterVoice.codec) ::
|
|
||||||
("unk6" | uint32L) ::
|
|
||||||
("unk7" | uint16L) ::
|
|
||||||
("unk8" | uint16L) ::
|
|
||||||
("unk9" | uint16L) ::
|
|
||||||
("unkA" | uint16L) //usually either 0 or 65535
|
|
||||||
})
|
|
||||||
})
|
|
||||||
).exmap[CharacterAppearanceA] (
|
).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(
|
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 _ =>
|
case _ =>
|
||||||
Attempt.Failure(Err("invalid character appearance data; can not encode"))
|
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"))
|
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) =>
|
case CharacterAppearanceA(BasicCharacterData(name, faction, sex, head, v1), data, suit, u5, u6, u7, u8, u9, uA) =>
|
||||||
Attempt.successful(
|
if(faction != data.faction) {
|
||||||
faction :: bops :: alt :: u1 :: u2 :: jamd :: u3 :: u4 :: name :: suit :: u5 :: sex :: head :: v1 :: u6 :: u7 :: u8 :: u9 :: uA :: HNil
|
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 _ =>
|
case _ =>
|
||||||
Attempt.Failure(Err("invalid character appearance data; can not decode"))
|
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] = (
|
def codec(name_padding : Int) : Codec[CharacterAppearanceData] = (
|
||||||
("a" | a_codec(name_padding)) >>:~ { a =>
|
("a" | a_codec(name_padding)) >>:~ { a =>
|
||||||
("b" | b_codec(a.altModel, name_padding)) ::
|
("b" | b_codec(a.data.alternate, name_padding)) ::
|
||||||
("ribbons" | RibbonBars.codec)
|
("ribbons" | RibbonBars.codec)
|
||||||
}
|
}
|
||||||
).xmap[CharacterAppearanceData] (
|
).xmap[CharacterAppearanceData] (
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,8 @@ object ImplantEffects extends Enumeration {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Values for the four different color designs that impact a player's uniform.
|
* 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 {
|
object UniformStyle extends Enumeration {
|
||||||
type Type = Value
|
type Type = Value
|
||||||
|
|
@ -35,9 +36,11 @@ object UniformStyle extends Enumeration {
|
||||||
val Normal = Value(0)
|
val Normal = Value(0)
|
||||||
val FirstUpgrade = Value(1)
|
val FirstUpgrade = Value(1)
|
||||||
val SecondUpgrade = Value(2)
|
val SecondUpgrade = Value(2)
|
||||||
|
val SecondUpgradeEx = Value(3)
|
||||||
val ThirdUpgrade = Value(4)
|
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
|
uint(3) :: //uniform_upgrade is actually interpreted as a 6u field, but the lower 3u seems to be discarded
|
||||||
("command_rank" | uintL(3)) ::
|
("command_rank" | uintL(3)) ::
|
||||||
listOfN(uint2, "implant_effects" | ImplantEffects.codec) ::
|
listOfN(uint2, "implant_effects" | ImplantEffects.codec) ::
|
||||||
conditional(style == UniformStyle.ThirdUpgrade, "cosmetics" | Cosmetics.codec)
|
conditional(style.id > UniformStyle.SecondUpgrade.id,"cosmetics" | Cosmetics.codec)
|
||||||
})
|
})
|
||||||
).exmap[CharacterData] (
|
).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
|
uint(3) :: //uniform_upgrade is actually interpreted as a 6u field, but the lower 3u seems to be discarded
|
||||||
("command_rank" | uintL(3)) ::
|
("command_rank" | uintL(3)) ::
|
||||||
listOfN(uint2, "implant_effects" | ImplantEffects.codec) ::
|
listOfN(uint2, "implant_effects" | ImplantEffects.codec) ::
|
||||||
conditional(style == UniformStyle.ThirdUpgrade, "cosmetics" | Cosmetics.codec)
|
conditional(style.id > UniformStyle.SecondUpgrade.id, "cosmetics" | Cosmetics.codec)
|
||||||
}
|
}
|
||||||
).exmap[CharacterData] (
|
).exmap[CharacterData] (
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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.<br>
|
|
||||||
* 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)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -8,96 +8,138 @@ import scodec.{Attempt, Codec, Err}
|
||||||
import scodec.codecs._
|
import scodec.codecs._
|
||||||
import shapeless.{::, HNil}
|
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.
|
* Data that is common to a number of game object serializations.
|
||||||
* @param pos where and how the object is oriented
|
* @param faction faction affinity
|
||||||
* @param faction association of the object with
|
* `NEUTRAL` when not required to be any specific value
|
||||||
* @param unk na
|
* @param bops usually indicates black ops affiliation
|
||||||
* @param player_guid the player who placed/leverages/[action]s this object
|
* @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,
|
final case class CommonFieldData(faction : PlanetSideEmpire.Value,
|
||||||
faction : PlanetSideEmpire.Value,
|
|
||||||
bops : Boolean,
|
bops : Boolean,
|
||||||
destroyed : Boolean,
|
alternate : Boolean,
|
||||||
unk : Int,
|
v1 : Boolean,
|
||||||
jammered : Boolean,
|
v2 : Option[CommonFieldDataExtra],
|
||||||
player_guid : PlanetSideGUID
|
v3 : Boolean,
|
||||||
) extends StreamBitSize {
|
v4 : Option[Boolean],
|
||||||
override def bitsize : Long = 23L + pos.bitsize
|
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] {
|
object CommonFieldData extends Marshallable[CommonFieldData] {
|
||||||
final val internalWeapon_bitsize : Long = 10
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overloaded constructor that eliminates the need to list the fourth, optional, GUID field.
|
* Overloaded constructors.
|
||||||
* @param pos where and how the object is oriented
|
|
||||||
* @param faction association of the object with
|
|
||||||
* @param unk na
|
|
||||||
* @return a `CommonFieldData` object
|
* @return a `CommonFieldData` object
|
||||||
*/
|
*/
|
||||||
def apply(pos : PlacementData, faction : PlanetSideEmpire.Value, unk : Int) : CommonFieldData =
|
def apply() : CommonFieldData =
|
||||||
CommonFieldData(pos, faction, false, false, unk, false, PlanetSideGUID(0))
|
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 =
|
def apply(faction : PlanetSideEmpire.Value) : CommonFieldData =
|
||||||
CommonFieldData(pos, faction, false, false, unk, false, player_guid)
|
CommonFieldData(faction, false, false, false, None, false, None, None, PlanetSideGUID(0))
|
||||||
|
|
||||||
def apply(pos : PlacementData, faction : PlanetSideEmpire.Value, destroyed : Boolean, unk : Int) : CommonFieldData =
|
def apply(faction : PlanetSideEmpire.Value, unk : Int) : CommonFieldData =
|
||||||
CommonFieldData(pos, faction, false, destroyed, unk, false, PlanetSideGUID(0))
|
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 =
|
def apply(faction : PlanetSideEmpire.Value, unk : Int, player_guid : PlanetSideGUID) : CommonFieldData =
|
||||||
CommonFieldData(pos, faction, false, destroyed, unk, false, player_guid)
|
CommonFieldData(faction, false, false, unk>1, None, unk%1==1, None, None, player_guid)
|
||||||
|
|
||||||
/**
|
def apply(faction : PlanetSideEmpire.Value, destroyed : Boolean, unk : Int) : CommonFieldData =
|
||||||
* `Codec` for transforming reliable `WeaponData` from the internal structure of the turret when it is defined.
|
CommonFieldData(faction, false, destroyed, unk>1, None, unk%1==1, None, None, PlanetSideGUID(0))
|
||||||
* Works for both `SmallTurretData` and `OneMannedFieldTurretData`.
|
|
||||||
*/
|
def apply(faction : PlanetSideEmpire.Value, destroyed : Boolean, unk : Int, player_guid : PlanetSideGUID) : CommonFieldData =
|
||||||
val internalWeaponCodec : Codec[InternalSlot] = (
|
CommonFieldData(faction, false, destroyed, unk>1, None, unk%1==1, None, None, player_guid)
|
||||||
uint8L :: //number of internal weapons (should be 1)?
|
|
||||||
uint2L ::
|
def apply(faction : PlanetSideEmpire.Value, bops : Boolean, destroyed : Boolean, unk : Int, jammered : Boolean, player_guid : PlanetSideGUID) : CommonFieldData = {
|
||||||
InternalSlot.codec
|
val jammeredField = if(jammered) { Some(0) } else { None }
|
||||||
).exmap[InternalSlot] (
|
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 =>
|
case faction :: bops :: alternate :: v1 :: v2 :: v3 :: v5 :: player_guid :: HNil =>
|
||||||
Attempt.successful(InternalSlot(a1, b1, c1, WeaponData(a2, b2, c2, d)))
|
CommonFieldData(faction, bops, alternate, v1, v2, v3, None, v5, player_guid)
|
||||||
|
|
||||||
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 InternalSlot(a1, b1, c1, WeaponData(a2, b2, c2, d)) =>
|
case CommonFieldData(faction, bops, alternate, v1, v2, v3, _, v5, guid) =>
|
||||||
Attempt.successful(1 :: 0 :: InternalSlot(a1, b1, c1, WeaponData(a2, b2, c2, d)) :: HNil)
|
faction :: bops :: alternate :: v1 :: v2 :: v3 :: v5 :: guid :: HNil
|
||||||
|
|
||||||
case InternalSlot(_, _, _, _) =>
|
|
||||||
Attempt.failure(Err(s"turret internals must contain weapon data"))
|
|
||||||
|
|
||||||
case _ =>
|
|
||||||
Attempt.failure(Err("invalid turret internals data format"))
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
implicit val codec : Codec[CommonFieldData] = (
|
implicit val codec : Codec[CommonFieldData] = codec(false)
|
||||||
("pos" | PlacementData.codec) ::
|
|
||||||
("faction" | PlanetSideEmpire.codec) ::
|
def codec2(extra : Boolean) : Codec[CommonFieldData] = (
|
||||||
|
("faction" | PlanetSideEmpire.codec) ::
|
||||||
("bops" | bool) ::
|
("bops" | bool) ::
|
||||||
("destroyed" | bool) ::
|
("alternate" | bool) ::
|
||||||
("unk" | uint2L) :: //3 - na, 2 - common, 1 - na, 0 - common?
|
("v1" | bool) :: //though the code path differs depending on the previous bit, this one gets read one way or another
|
||||||
("jammered" | bool) ::
|
conditional(extra, "v2" | CommonFieldDataExtra.codec) ::
|
||||||
("player_guid" | PlanetSideGUID.codec)
|
("v3" | bool) ::
|
||||||
|
optional(bool, "v5" | uint16L) ::
|
||||||
|
("v4" | bool) ::
|
||||||
|
("guid" | PlanetSideGUID.codec)
|
||||||
).exmap[CommonFieldData] (
|
).exmap[CommonFieldData] (
|
||||||
{
|
{
|
||||||
case pos :: fac :: bops :: wrecked :: unk :: jammered :: player :: HNil =>
|
case faction :: bops :: alternate :: v1 :: v2 :: v3 :: v5 :: v4 :: guid :: HNil =>
|
||||||
Attempt.successful(CommonFieldData(pos, fac, bops, wrecked, unk,jammered, player))
|
Attempt.successful(CommonFieldData(faction, bops, alternate, v1, v2, v3, Some(v4), v5, guid))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case CommonFieldData(pos, fac, bops, wrecked, unk, jammered, player) =>
|
case CommonFieldData(_, _, _, _, _, _, None, _, _) =>
|
||||||
Attempt.successful(pos :: fac :: bops :: wrecked :: unk :: jammered :: player :: HNil)
|
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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -16,30 +16,32 @@ abstract class ConstructorData extends StreamBitSize
|
||||||
|
|
||||||
object ConstructorData {
|
object ConstructorData {
|
||||||
/**
|
/**
|
||||||
* This pattern is intended to provide common conversion between all of the `Codec`s of the children of this class.
|
* Transform a `Codec[T]` for object type `T` into `ConstructorData`.
|
||||||
* 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`.
|
|
||||||
* @param objCodec a `Codec` that satisfies the transformation `Codec[T] -> T`
|
* @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;
|
* @param objType a `String` that explains what the object should be identified as in the `Err` message;
|
||||||
* defaults to "object"
|
* defaults to "object"
|
||||||
* @tparam T a subclass of `ConstructorData` that indicates what type the object is
|
* @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] =
|
def apply[T <: ConstructorData](objCodec : Codec[T], objType : String = "object") : Codec[ConstructorData] =
|
||||||
objCodec.exmap[ConstructorData.genericPattern] (
|
objCodec.exmap[ConstructorData] (
|
||||||
{
|
x => {
|
||||||
case x =>
|
try {
|
||||||
Attempt.successful(Some(x.asInstanceOf[ConstructorData]))
|
Attempt.successful(x.asInstanceOf[ConstructorData])
|
||||||
},
|
}
|
||||||
{
|
catch {
|
||||||
case Some(x) =>
|
case ex : Exception =>
|
||||||
Attempt.successful(x.asInstanceOf[T]) //why does this work? shouldn't type erasure be a problem?
|
Attempt.failure(Err(s"can not cast decode of $x to $objType - $ex"))
|
||||||
case _ =>
|
}
|
||||||
Attempt.failure(Err(s"can not encode as $objType data"))
|
},
|
||||||
}
|
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"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -4,6 +4,25 @@ package net.psforever.packet.game.objectcreate
|
||||||
import scodec.codecs._
|
import scodec.codecs._
|
||||||
import scodec.Codec
|
import scodec.Codec
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Values for the different specific customizations available as cosmetics.<br>
|
||||||
|
* `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`<br>
|
||||||
|
* `Beret` player dons a beret<br>
|
||||||
|
* `Sunglasses` player dons sunglasses<br>
|
||||||
|
* `Earpiece` player dons an earpiece on the left<br>
|
||||||
|
* `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.<br>
|
* The different cosmetics that a player can apply to their character model's head.<br>
|
||||||
* <br>
|
* <br>
|
||||||
|
|
@ -11,31 +30,99 @@ import scodec.Codec
|
||||||
* These flags are only valid if the player has:
|
* These flags are only valid if the player has:
|
||||||
* for `DetailedCharacterData`, achieved at least battle rank twenty-four (battle experience points greater than 2286230),
|
* 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).
|
* 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.
|
* `CharacterData`, as suggested, 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;
|
* @param pstyles a value that indicates certain cosmetic features by bitwise math
|
||||||
* all other cosmetics require `no_helmet` to be `true` before they can be seen
|
* @see `UniformStyle`
|
||||||
* @param beret player dons a beret
|
* @see `PersonalStyleFeatures`
|
||||||
* @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`
|
|
||||||
*/
|
*/
|
||||||
final case class Cosmetics(no_helmet : Boolean,
|
final case class Cosmetics(pstyles : Int) extends StreamBitSize {
|
||||||
beret : Boolean,
|
|
||||||
sunglasses : Boolean,
|
|
||||||
earpiece : Boolean,
|
|
||||||
brimmed_cap : Boolean
|
|
||||||
) extends StreamBitSize {
|
|
||||||
override def bitsize : Long = 5L
|
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.<br>
|
||||||
|
* `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.<br>
|
||||||
|
* * `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 {
|
object Cosmetics {
|
||||||
implicit val codec : Codec[Cosmetics] = (
|
/**
|
||||||
("no_helmet" | bool) ::
|
* Overloaded constructor for `Cosmetics` that loads no option.
|
||||||
("beret" | bool) ::
|
* @return a `Cosmetics` object
|
||||||
("sunglasses" | bool) ::
|
*/
|
||||||
("earpiece" | bool) ::
|
def apply() : Cosmetics = Cosmetics(0)
|
||||||
("brimmed_cap" | bool)
|
|
||||||
).as[Cosmetics]
|
/**
|
||||||
|
* 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]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -3,6 +3,7 @@ package net.psforever.packet.game.objectcreate
|
||||||
|
|
||||||
import net.psforever.packet.Marshallable
|
import net.psforever.packet.Marshallable
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
|
import net.psforever.types.PlanetSideEmpire
|
||||||
import scodec.{Attempt, Codec, Err}
|
import scodec.{Attempt, Codec, Err}
|
||||||
import scodec.codecs._
|
import scodec.codecs._
|
||||||
import shapeless.{::, HNil}
|
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.
|
* 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.
|
* 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.
|
* 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
|
* @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
|
magazine : Int
|
||||||
) extends ConstructorData {
|
) extends ConstructorData {
|
||||||
override def bitsize : Long = 40L
|
override def bitsize : Long = {
|
||||||
|
val dataSize = data.bitsize
|
||||||
|
17L + dataSize
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object DetailedAmmoBoxData extends Marshallable[DetailedAmmoBoxData] {
|
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 =
|
def apply(cls : Int, guid : PlanetSideGUID, parentSlot : Int, ammo : DetailedAmmoBoxData) : InternalSlot =
|
||||||
new InternalSlot(cls, guid, parentSlot, ammo)
|
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] = (
|
implicit val codec : Codec[DetailedAmmoBoxData] = (
|
||||||
uint4L ::
|
("data" | CommonFieldData.codec) ::
|
||||||
("unk" | uint4L) :: // 8 - common - 4 - safe, 2 - stream misalignment, 1 - safe, 0 - common
|
|
||||||
uint(15) ::
|
|
||||||
("magazine" | uint16L) ::
|
("magazine" | uint16L) ::
|
||||||
bool
|
bool
|
||||||
).exmap[DetailedAmmoBoxData] (
|
).exmap[DetailedAmmoBoxData] (
|
||||||
{
|
{
|
||||||
case 0xC :: unk :: 0 :: mag :: false :: HNil =>
|
case data :: mag :: false :: HNil =>
|
||||||
Attempt.successful(DetailedAmmoBoxData(unk, mag))
|
Attempt.successful(DetailedAmmoBoxData(data, mag))
|
||||||
case _ =>
|
|
||||||
Attempt.failure(Err("invalid ammunition data format"))
|
case data =>
|
||||||
|
Attempt.failure(Err(s"invalid detailed ammunition data format - $data"))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case DetailedAmmoBoxData(unk, mag) =>
|
case DetailedAmmoBoxData(data, mag) =>
|
||||||
Attempt.successful(0xC :: unk :: 0 :: mag :: false:: HNil)
|
Attempt.successful(data :: mag :: false:: HNil)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -7,32 +7,32 @@ import scodec.codecs._
|
||||||
import shapeless.{::, HNil}
|
import shapeless.{::, HNil}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A representation of the command uplink device.<br>
|
* 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 DetailedCommandDetonaterData(unk1 : Int = 8,
|
final case class DetailedCommandDetonaterData(data : CommonFieldData) extends ConstructorData {
|
||||||
unk2 : Int = 0) extends ConstructorData {
|
override def bitsize : Long = {
|
||||||
override def bitsize : Long = 51L
|
val dataSize = data.bitsize
|
||||||
|
28L + dataSize
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object DetailedCommandDetonaterData extends Marshallable[DetailedCommandDetonaterData] {
|
object DetailedCommandDetonaterData extends Marshallable[DetailedCommandDetonaterData] {
|
||||||
implicit val codec : Codec[DetailedCommandDetonaterData] = (
|
implicit val codec : Codec[DetailedCommandDetonaterData] = (
|
||||||
("unk1" | uint4L) ::
|
("data" | CommonFieldData.codec) ::
|
||||||
("unk2" | uint4L) ::
|
uint8 ::
|
||||||
uint(20) ::
|
|
||||||
uint4L ::
|
|
||||||
uint16 ::
|
uint16 ::
|
||||||
uint(3)
|
uint4
|
||||||
).exmap[DetailedCommandDetonaterData] (
|
).exmap[DetailedCommandDetonaterData] (
|
||||||
{
|
{
|
||||||
case unk1 :: unk2 :: 0 :: 2 :: 0 :: 4 :: HNil =>
|
case data :: 1 :: 0 :: 4 :: HNil =>
|
||||||
Attempt.successful(DetailedCommandDetonaterData(unk1, unk2))
|
Attempt.successful(DetailedCommandDetonaterData(data))
|
||||||
case _ =>
|
|
||||||
Attempt.failure(Err("invalid command detonator data format"))
|
case data =>
|
||||||
|
Attempt.failure(Err(s"invalid detailed command detonater data format - $data"))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case DetailedCommandDetonaterData(unk1, unk2) =>
|
case DetailedCommandDetonaterData(data) =>
|
||||||
Attempt.successful(unk1 :: unk2 :: 0 :: 2 :: 0 :: 4 :: HNil)
|
Attempt.successful(data :: 1 :: 0 :: 4 :: HNil)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -3,6 +3,7 @@ package net.psforever.packet.game.objectcreate
|
||||||
|
|
||||||
import net.psforever.packet.Marshallable
|
import net.psforever.packet.Marshallable
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
|
import net.psforever.types.PlanetSideEmpire
|
||||||
import scodec.codecs._
|
import scodec.codecs._
|
||||||
import scodec.{Attempt, Codec, Err}
|
import scodec.{Attempt, Codec, Err}
|
||||||
import shapeless.{::, HNil}
|
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.
|
* 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.
|
* 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.
|
* 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
|
* @param inventory the items in this inventory
|
||||||
*/
|
*/
|
||||||
final case class DetailedLockerContainerData(unk : Int,
|
final case class DetailedLockerContainerData(data : CommonFieldData,
|
||||||
inventory : Option[InventoryData]
|
inventory : Option[InventoryData]
|
||||||
) extends ConstructorData {
|
) extends ConstructorData {
|
||||||
override def bitsize : Long = {
|
override def bitsize : Long = {
|
||||||
|
|
@ -34,7 +35,7 @@ object DetailedLockerContainerData extends Marshallable[DetailedLockerContainerD
|
||||||
* @return a `DetailedLockerContainerData` object
|
* @return a `DetailedLockerContainerData` object
|
||||||
*/
|
*/
|
||||||
def apply(unk : Int) : DetailedLockerContainerData =
|
def apply(unk : Int) : DetailedLockerContainerData =
|
||||||
new DetailedLockerContainerData(unk, None)
|
new DetailedLockerContainerData(CommonFieldData(PlanetSideEmpire.NEUTRAL, unk), None)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overloaded constructor for creating `DetailedLockerContainerData` containing known items.
|
* Overloaded constructor for creating `DetailedLockerContainerData` containing known items.
|
||||||
|
|
@ -43,7 +44,7 @@ object DetailedLockerContainerData extends Marshallable[DetailedLockerContainerD
|
||||||
* @return a `DetailedLockerContainerData` object
|
* @return a `DetailedLockerContainerData` object
|
||||||
*/
|
*/
|
||||||
def apply(unk : Int, inventory : List[InternalSlot]) : DetailedLockerContainerData =
|
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`.
|
* 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)
|
new InternalSlot(cls, guid, parentSlot, locker)
|
||||||
|
|
||||||
implicit val codec : Codec[DetailedLockerContainerData] = (
|
implicit val codec : Codec[DetailedLockerContainerData] = (
|
||||||
uint4L ::
|
("data" | CommonFieldData.codec) ::
|
||||||
("unk" | uint4L) :: // 8 - common - 4 - safe, 2 - stream misalignment, 1 - safe, 0 - common
|
|
||||||
uint(15) ::
|
|
||||||
uint16L :: //always 1
|
uint16L :: //always 1
|
||||||
optional(bool, InventoryData.codec_detailed)
|
optional(bool, InventoryData.codec_detailed)
|
||||||
).exmap[DetailedLockerContainerData] (
|
).exmap[DetailedLockerContainerData] (
|
||||||
{
|
{
|
||||||
case 0xC :: unk :: 0 :: 1 :: None :: HNil =>
|
case data :: 1 :: None :: HNil =>
|
||||||
Attempt.successful(DetailedLockerContainerData(unk, None))
|
Attempt.successful(DetailedLockerContainerData(data, None))
|
||||||
|
|
||||||
case 0xC :: unk :: 0 :: 1 :: Some(inv) :: HNil =>
|
case data :: 1 :: Some(inv) :: HNil =>
|
||||||
Attempt.successful(DetailedLockerContainerData(unk, Some(inv)))
|
Attempt.successful(DetailedLockerContainerData(data, Some(inv)))
|
||||||
case _ =>
|
|
||||||
Attempt.failure(Err(s"invalid locker container data format"))
|
case data =>
|
||||||
|
Attempt.failure(Err(s"invalid detailed locker container data format - $data"))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case DetailedLockerContainerData(unk, None) =>
|
case DetailedLockerContainerData(data, None) =>
|
||||||
Attempt.successful(0xC :: unk :: 0 :: 1 :: None :: HNil)
|
Attempt.successful(data :: 1 :: None :: HNil)
|
||||||
|
|
||||||
case DetailedLockerContainerData(unk, Some(inv)) =>
|
case DetailedLockerContainerData(data, Some(inv)) =>
|
||||||
Attempt.successful(0xC :: unk :: 0 :: 1 :: Some(inv) :: HNil)
|
Attempt.successful(data :: 1 :: Some(inv) :: HNil)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ object DetailedPlayerData extends Marshallable[DetailedPlayerData] {
|
||||||
* technically, always `DrawnSlot.None`, but the field is preserved to maintain similarity
|
* technically, always `DrawnSlot.None`, but the field is preserved to maintain similarity
|
||||||
* @return a `DetailedPlayerData` object
|
* @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)
|
val appearance = basic_appearance(5)
|
||||||
DetailedPlayerData(None, appearance, character_data(appearance.altModelBit), Some(inventory), drawn_slot)(false)
|
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
|
* technically, always `DrawnSlot.None`, but the field is preserved to maintain similarity
|
||||||
* @return a `DetailedPlayerData` object
|
* @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)
|
val appearance = basic_appearance(5)
|
||||||
DetailedPlayerData(None, appearance, character_data(appearance.altModelBit), None, drawn_slot)(false)
|
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"
|
* @param drawn_slot the holster that is depicted as exposed, or "drawn"
|
||||||
* @return a `DetailedPlayerData` object
|
* @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)))
|
val appearance = basic_appearance(PlayerData.PaddingOffset(Some(pos)))
|
||||||
DetailedPlayerData(Some(pos), appearance, character_data(appearance.altModelBit), Some(inventory), drawn_slot)(true)
|
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"
|
* @param drawn_slot the holster that is depicted as exposed, or "drawn"
|
||||||
* @return a `DetailedPlayerData` object
|
* @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)))
|
val appearance = basic_appearance(PlayerData.PaddingOffset(Some(pos)))
|
||||||
DetailedPlayerData(Some(pos), appearance, character_data(appearance.altModelBit), None, drawn_slot)(true)
|
DetailedPlayerData(Some(pos), appearance, character_data(appearance.altModelBit), None, drawn_slot)(true)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,34 +11,36 @@ import shapeless.{::, HNil}
|
||||||
* This data will help construct the "tool" called a Remote Electronics Kit.<br>
|
* This data will help construct the "tool" called a Remote Electronics Kit.<br>
|
||||||
* <br>
|
* <br>
|
||||||
* Of note is the first portion of the data which resembles the `DetailedWeaponData` format.
|
* Of note is the first portion of the data which resembles the `DetailedWeaponData` format.
|
||||||
* @param unk1 na
|
* @param data na
|
||||||
* @param unk2 na
|
* @param unk na
|
||||||
*/
|
*/
|
||||||
final case class DetailedREKData(unk1 : Int,
|
final case class DetailedREKData(data : CommonFieldData,
|
||||||
unk2 : Int = 0
|
unk : Int = 0
|
||||||
) extends ConstructorData {
|
) extends ConstructorData {
|
||||||
override def bitsize : Long = 67L
|
override def bitsize : Long = {
|
||||||
|
val dataSize = data.bitsize
|
||||||
|
43L + dataSize
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object DetailedREKData extends Marshallable[DetailedREKData] {
|
object DetailedREKData extends Marshallable[DetailedREKData] {
|
||||||
implicit val codec : Codec[DetailedREKData] = (
|
implicit val codec : Codec[DetailedREKData] = (
|
||||||
("unk" | uint4L) ::
|
("data" | CommonFieldData.codec2) ::
|
||||||
uint4L ::
|
uint8 ::
|
||||||
uintL(20) ::
|
|
||||||
uint4L ::
|
|
||||||
uint16L ::
|
uint16L ::
|
||||||
uint4L ::
|
uint4L ::
|
||||||
("unk2" | uintL(15))
|
("unk" | uint8) ::
|
||||||
|
uint(7)
|
||||||
).exmap[DetailedREKData] (
|
).exmap[DetailedREKData] (
|
||||||
{
|
{
|
||||||
case code :: 8 :: 0 :: 2 :: 0 :: 8 :: unk2 :: HNil =>
|
case data :: 2 :: 0 :: 8 :: unk :: 0 :: HNil =>
|
||||||
Attempt.successful(DetailedREKData(code, unk2))
|
Attempt.successful(DetailedREKData(data, unk))
|
||||||
case _ =>
|
case data =>
|
||||||
Attempt.failure(Err("invalid rek data format"))
|
Attempt.failure(Err(s"invalid detailed rek data format - $data"))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case DetailedREKData(code, unk2) =>
|
case DetailedREKData(data, unk) =>
|
||||||
Attempt.successful(code :: 8 :: 0 :: 2 :: 0 :: 8 :: unk2 :: HNil)
|
Attempt.successful(data :: 2 :: 0 :: 8 :: unk :: 0 :: HNil)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -3,6 +3,7 @@ package net.psforever.packet.game.objectcreate
|
||||||
|
|
||||||
import net.psforever.packet.Marshallable
|
import net.psforever.packet.Marshallable
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
|
import net.psforever.types.PlanetSideEmpire
|
||||||
import scodec.{Attempt, Codec, Err}
|
import scodec.{Attempt, Codec, Err}
|
||||||
import scodec.codecs._
|
import scodec.codecs._
|
||||||
import shapeless.{::, HNil}
|
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.
|
* 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.
|
* 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.
|
* An "expected" number of ammunition slot data can be passed into the function.
|
||||||
* @param unk1 na
|
* @param data field common to multiple game objects
|
||||||
* @param unk2 na
|
* @param fire_mode the current fire mode
|
||||||
* @param ammo data regarding the currently loaded ammunition type(s) and quantity(ies)
|
* @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 `DetailedAmmoBoxData`
|
||||||
* @see `WeaponData`
|
* @see `WeaponData`
|
||||||
*/
|
*/
|
||||||
final case class DetailedWeaponData(unk1 : Int,
|
final case class DetailedWeaponData(data : CommonFieldData,
|
||||||
unk2 : Int,
|
|
||||||
fire_mode : Int,
|
fire_mode : Int,
|
||||||
ammo : List[InternalSlot]
|
ammo : List[InternalSlot],
|
||||||
)(implicit val mag_capacity : Int = 1) extends ConstructorData {
|
unk : Boolean = false
|
||||||
|
) extends ConstructorData {
|
||||||
override def bitsize : Long = {
|
override def bitsize : Long = {
|
||||||
var bitsize : Long = 0L
|
val dataSize = data.bitsize
|
||||||
for(o <- ammo) {
|
val ammoSize : Long = ammo.foldLeft(0L)(_ + _.bitsize)
|
||||||
bitsize += o.bitsize
|
38L + dataSize + ammoSize //28 + 10 (from InventoryData) + ammo
|
||||||
}
|
|
||||||
61L + bitsize //51 + 10 (from InventoryData) + ammo
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,8 +44,23 @@ object DetailedWeaponData extends Marshallable[DetailedWeaponData] {
|
||||||
* @param ammo the constructor data for the ammunition
|
* @param ammo the constructor data for the ammunition
|
||||||
* @return a `DetailedWeaponData` object
|
* @return a `DetailedWeaponData` object
|
||||||
*/
|
*/
|
||||||
def apply(unk1 : Int, unk2 : Int, cls : Int, guid : PlanetSideGUID, parentSlot : Int, ammo : DetailedAmmoBoxData) : DetailedWeaponData =
|
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)
|
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
|
* @param ammo the constructor data for the ammunition
|
||||||
* @return a `DetailedWeaponData` object
|
* @return a `DetailedWeaponData` object
|
||||||
*/
|
*/
|
||||||
def apply(unk1 : Int, unk2 : Int, fire_mode : Int, cls : Int, guid : PlanetSideGUID, parentSlot : Int, ammo : DetailedAmmoBoxData) : DetailedWeaponData =
|
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)
|
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))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
implicit val codec : Codec[DetailedWeaponData] = (
|
||||||
* A `Codec` for `DetailedWeaponData`
|
("data" | CommonFieldData.codec) ::
|
||||||
* @param mag_capacity the total number of concurrently-loaded ammunition types allowed in this weapon;
|
uint8 ::
|
||||||
* defaults to 1
|
uint8 ::
|
||||||
* @return a `WeaponData` object or a `BitVector`
|
("fire_mode" | uint8) ::
|
||||||
*/
|
uint2 ::
|
||||||
def codec(mag_capacity : Int = 1) : Codec[DetailedWeaponData] = (
|
optional(bool, "ammo" | InventoryData.codec_detailed) ::
|
||||||
("unk1" | uint(3)) ::
|
("unk" | bool)
|
||||||
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
|
|
||||||
).exmap[DetailedWeaponData] (
|
).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
|
val magSize = ammo.size
|
||||||
if(mag_capacity == 0 || magSize == 0) {
|
if(magSize == 0) {
|
||||||
Attempt.failure(Err("weapon must decode some ammunition"))
|
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 {
|
else {
|
||||||
Attempt.successful(DetailedWeaponData(unk1, unk2, fmode, ammo)(magSize))
|
Attempt.successful(DetailedWeaponData(data, fmode, ammo, unk))
|
||||||
}
|
}
|
||||||
|
|
||||||
case _ =>
|
case data =>
|
||||||
Attempt.failure(Err("invalid weapon data format"))
|
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 magSize = ammo.size
|
||||||
val magCapacity = obj.mag_capacity
|
if(magSize == 0) {
|
||||||
if(mag_capacity == 0 || magCapacity == 0 || magSize == 0) {
|
|
||||||
Attempt.failure(Err("weapon must encode some ammunition"))
|
Attempt.failure(Err("weapon must encode some ammunition"))
|
||||||
}
|
}
|
||||||
else if(magCapacity < 0 || mag_capacity < 0) {
|
else if(magSize >= 255) {
|
||||||
Attempt.successful(unk1 :: false :: unk2 :: 2 :: 0 :: fmode :: 3 :: InventoryData(ammo) :: false :: HNil)
|
Attempt.failure(Err("weapon encodes too much ammunition (255+ types!)"))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(magCapacity != mag_capacity) {
|
Attempt.successful(data :: 1 :: 0 :: fmode :: 1 :: Some(InventoryData(ammo)) :: unk :: HNil)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case _ =>
|
|
||||||
Attempt.failure(Err("invalid weapon data format"))
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
implicit val codec : Codec[DetailedWeaponData] = codec()
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ final case class DroppedItemData[T <: ConstructorData](pos : PlacementData, obj
|
||||||
|
|
||||||
object DroppedItemData {
|
object DroppedItemData {
|
||||||
/**
|
/**
|
||||||
* Transform `DroppedItemData[T]` for object type `T` into `ConstructorData.genericPattern`.<br>
|
* Transform `DroppedItemData[T]` for object type `T` into `ConstructorData`.<br>
|
||||||
* <br>
|
* <br>
|
||||||
* This function eliminates the need to have a separate "DroppedFooData" class for every object "Foo."
|
* 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`.
|
* 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;
|
* @param objType a `String` that explains what the object should be identified as in the log;
|
||||||
* defaults to "object"
|
* defaults to "object"
|
||||||
* @tparam T a subclass of `ConstructorData` that indicates what type the object is
|
* @tparam T a subclass of `ConstructorData` that indicates what type the object is
|
||||||
* @return `ConstructorData.genericPattern`
|
* @return `Codec[ConstructorData]`
|
||||||
* @see `ConstructorData.genericPattern` (function)
|
* @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) ::
|
("pos" | PlacementData.codec) ::
|
||||||
("obj" | objCodec)
|
("obj" | objCodec)
|
||||||
).xmap[DroppedItemData[T]] (
|
).xmap[DroppedItemData[T]] (
|
||||||
|
|
@ -47,16 +47,24 @@ object DroppedItemData {
|
||||||
case DroppedItemData(pos, obj) =>
|
case DroppedItemData(pos, obj) =>
|
||||||
pos :: obj :: HNil
|
pos :: obj :: HNil
|
||||||
}
|
}
|
||||||
).exmap[ConstructorData.genericPattern] (
|
).exmap[ConstructorData] (
|
||||||
{
|
x => {
|
||||||
case x =>
|
try {
|
||||||
Attempt.successful(Some(x.asInstanceOf[ConstructorData]))
|
Attempt.successful(x.asInstanceOf[ConstructorData])
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
case ex : Exception =>
|
||||||
|
Attempt.failure(Err(s"can not cast decode of $x to dropped $objType - $ex"))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
x => {
|
||||||
case Some(x) =>
|
try {
|
||||||
Attempt.successful(x.asInstanceOf[DroppedItemData[T]])
|
Attempt.successful(x.asInstanceOf[DroppedItemData[T]]) //why does this work? shouldn't type erasure be a problem?
|
||||||
case _ =>
|
}
|
||||||
Attempt.failure(Err(s"can not encode dropped $objType data"))
|
catch {
|
||||||
|
case ex : Exception =>
|
||||||
|
Attempt.failure(Err(s"can not cast encode $x to dropped $objType - $ex"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package net.psforever.packet.game.objectcreate
|
||||||
|
|
||||||
import net.psforever.packet.Marshallable
|
import net.psforever.packet.Marshallable
|
||||||
import scodec.codecs._
|
import scodec.codecs._
|
||||||
import scodec.{Attempt, Codec}
|
import scodec.{Attempt, Codec, Err}
|
||||||
import shapeless.{::, HNil}
|
import shapeless.{::, HNil}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -31,7 +31,7 @@ import shapeless.{::, HNil}
|
||||||
* @see `DroppodLaunchRequestMessage`
|
* @see `DroppodLaunchRequestMessage`
|
||||||
* @see `DroppodLaunchResponseMessage`
|
* @see `DroppodLaunchResponseMessage`
|
||||||
*/
|
*/
|
||||||
final case class DroppodData(basic : CommonFieldData,
|
final case class DroppodData(basic : CommonFieldDataWithPlacement,
|
||||||
burn : Boolean = false,
|
burn : Boolean = false,
|
||||||
health : Int = 255
|
health : Int = 255
|
||||||
) extends ConstructorData {
|
) extends ConstructorData {
|
||||||
|
|
@ -43,7 +43,7 @@ final case class DroppodData(basic : CommonFieldData,
|
||||||
|
|
||||||
object DroppodData extends Marshallable[DroppodData] {
|
object DroppodData extends Marshallable[DroppodData] {
|
||||||
implicit val codec : Codec[DroppodData] = (
|
implicit val codec : Codec[DroppodData] = (
|
||||||
("basic" | CommonFieldData.codec) ::
|
("basic" | CommonFieldDataWithPlacement.codec) ::
|
||||||
bool ::
|
bool ::
|
||||||
("health" | uint8L) :: //health
|
("health" | uint8L) :: //health
|
||||||
uintL(5) :: //0x0
|
uintL(5) :: //0x0
|
||||||
|
|
@ -56,6 +56,9 @@ object DroppodData extends Marshallable[DroppodData] {
|
||||||
case basic :: false :: health :: 0 :: 0xF :: 0 :: boosters :: false :: HNil =>
|
case basic :: false :: health :: 0 :: 0xF :: 0 :: boosters :: false :: HNil =>
|
||||||
val burn : Boolean = boosters == 0
|
val burn : Boolean = boosters == 0
|
||||||
Attempt.successful(DroppodData(basic, burn, health))
|
Attempt.successful(DroppodData(basic, burn, health))
|
||||||
|
|
||||||
|
case data =>
|
||||||
|
Attempt.failure(Err(s"invalid droppod data format - $data"))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case DroppodData(basic, burn, health) =>
|
case DroppodData(basic, burn, health) =>
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -45,12 +45,12 @@ object InternalSlot {
|
||||||
}
|
}
|
||||||
).xmap[InternalSlot] (
|
).xmap[InternalSlot] (
|
||||||
{
|
{
|
||||||
case cls :: guid :: slot :: Some(obj) :: HNil =>
|
case cls :: guid :: slot :: obj :: HNil =>
|
||||||
InternalSlot(cls, guid, slot, obj)
|
InternalSlot(cls, guid, slot, obj)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case 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] (
|
).xmap[InternalSlot] (
|
||||||
{
|
{
|
||||||
case cls :: guid :: slot :: Some(obj) :: HNil =>
|
case cls :: guid :: slot :: obj :: HNil =>
|
||||||
InternalSlot(cls, guid, slot, obj)
|
InternalSlot(cls, guid, slot, obj)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case InternalSlot(cls, guid, slot, obj) =>
|
case InternalSlot(cls, guid, slot, obj) =>
|
||||||
cls :: guid :: slot :: Some(obj) :: HNil
|
cls :: guid :: slot :: obj :: HNil
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,19 +7,9 @@ import scodec.{Attempt, Codec, Err}
|
||||||
import shapeless.{::, HNil}
|
import shapeless.{::, HNil}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A representation of the Spitfire-based small turrets deployed using an adaptive construction engine.<br>
|
* This class currently is unused but is based on the `SmallTurretData` `Codec` class.
|
||||||
* <br>
|
|
||||||
* 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.<br>
|
|
||||||
* <br>
|
|
||||||
* 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
|
|
||||||
*/
|
*/
|
||||||
final case class LargeDeployableData(deploy : SmallDeployableData,
|
final case class LargeDeployableData(deploy : CommonFieldDataWithPlacement,
|
||||||
health : Int,
|
health : Int,
|
||||||
internals : Option[InventoryData] = None
|
internals : Option[InventoryData] = None
|
||||||
) extends ConstructorData {
|
) extends ConstructorData {
|
||||||
|
|
@ -37,7 +27,7 @@ final case class LargeDeployableData(deploy : SmallDeployableData,
|
||||||
|
|
||||||
object LargeDeployableData extends Marshallable[LargeDeployableData] {
|
object LargeDeployableData extends Marshallable[LargeDeployableData] {
|
||||||
implicit val codec : Codec[LargeDeployableData] = (
|
implicit val codec : Codec[LargeDeployableData] = (
|
||||||
("deploy" | SmallDeployableData.codec) ::
|
("deploy" | CommonFieldDataWithPlacement.codec2) ::
|
||||||
("health" | uint8L) ::
|
("health" | uint8L) ::
|
||||||
uintL(7) ::
|
uintL(7) ::
|
||||||
uint4L ::
|
uint4L ::
|
||||||
|
|
@ -54,8 +44,9 @@ object LargeDeployableData extends Marshallable[LargeDeployableData] {
|
||||||
}
|
}
|
||||||
Attempt.successful(LargeDeployableData(deploy, newHealth, newInternals))
|
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) =>
|
case LargeDeployableData(deploy, health, internals) =>
|
||||||
|
|
|
||||||
|
|
@ -12,27 +12,39 @@ import shapeless.{::, HNil}
|
||||||
* For whatever reason, these "lockers" are typically placed at the origin coordinates.
|
* For whatever reason, these "lockers" are typically placed at the origin coordinates.
|
||||||
* @param inventory the items inside this locker
|
* @param inventory the items inside this locker
|
||||||
*/
|
*/
|
||||||
final case class LockerContainerData(inventory : InventoryData) extends ConstructorData {
|
final case class LockerContainerData(inventory : Option[InventoryData]) extends ConstructorData {
|
||||||
override def bitsize : Long = 105L + inventory.bitsize //81u + 2u + 21u + 1u
|
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] {
|
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] = (
|
implicit val codec : Codec[LockerContainerData] = (
|
||||||
uint32 :: uint32 :: uint(17) :: //can substitute with PlacementData, if ever necessary
|
uint32 :: uint32 :: uint(17) ::
|
||||||
uint2L ::
|
uint2L ::
|
||||||
uint(21) ::
|
uint(21) ::
|
||||||
bool ::
|
("inventory" | optional(bool, InventoryData.codec))
|
||||||
InventoryData.codec
|
|
||||||
).exmap[LockerContainerData] (
|
).exmap[LockerContainerData] (
|
||||||
{
|
{
|
||||||
case 0 :: 0 :: 0 :: 3 :: 0 :: true :: inv :: HNil =>
|
case 0 :: 0 :: 0 :: 3 :: 0 :: inventory :: HNil =>
|
||||||
Attempt.successful(LockerContainerData(inv))
|
Attempt.successful(LockerContainerData(inventory))
|
||||||
case _ =>
|
|
||||||
Attempt.failure(Err("invalid locker container format"))
|
case data =>
|
||||||
|
Attempt.failure(Err(s"invalid locker container data format - $data"))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case LockerContainerData(inv) =>
|
case LockerContainerData(inventory) =>
|
||||||
Attempt.successful(0L :: 0L :: 0 :: 3 :: 0 :: true :: inv :: HNil)
|
Attempt.successful(0L :: 0L :: 0 :: 3 :: 0 :: inventory :: HNil)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue