mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-16 08:55:16 +00:00
Damage Fix, and Stuff (#235)
* redid splash damage radial degrade calculations; lasher damage fixed to 6/0 or 2/4 depending on armor; fixed direct hit distance for weapons that act like slash weapons; gave Falcon a valid projectile * delayed resource silo startup to avoid crash; discovered issue with MAX armor resulting from incorrect manipulation of inventory items during suit transfer * modifications to consider a specific modifier that exists on some vehicles and armored equipment called Subtract, a DamageProfile that reduces damage due to a set flag; manually controlling damage tick marks rather than relying only on HitHint (from client) * Tools now have default firemodes (temporary?); ammo gotten from loadouts is always full; loadouts and exo-suits juggle armor values differently on being changed; log messages for damage to players and vehicles * weapons with one (last) shot need support communicating that one (last) shot * fixing tests * correcting the codec for BindPlayerMessage * changed wording that identifies the damage log entries * switching exosuit no longer causes butterfingers * extending exosuit swap armor value changes to infantry loadout changes * ranges removed from non-vehicle containers * enabled partial damage functionality to facility turrets * BindPlayerMessage replacing BattleplanMessage for purposes of depicting the closest AMS spawn point; specific enums in relation to spawning in BPM and SpawnRequestMessage * rewrote exo-suit switching and loadout switching code, paying extra-special attention for the needs of MAX's * quick amendment for previous commit * switching from mount point check to seat checks in VehicleRemover; started refactoring of Cargo functions before realizing how complicated the full effort would be, so these changes are merely wrapping object identification by GUID * adding a minor server delay to terminal operations
This commit is contained in:
parent
7cec0bb577
commit
4eca226b5b
41 changed files with 900 additions and 453 deletions
|
|
@ -85,6 +85,10 @@ class SpecialExoSuitDefinition(private val suitType : ExoSuitType.Value) extends
|
||||||
obj.MaxArmor = MaxArmor
|
obj.MaxArmor = MaxArmor
|
||||||
obj.InventoryScale = InventoryScale
|
obj.InventoryScale = InventoryScale
|
||||||
obj.InventoryOffset = InventoryOffset
|
obj.InventoryOffset = InventoryOffset
|
||||||
|
obj.Subtract.Damage0 = Subtract.Damage0
|
||||||
|
obj.Subtract.Damage1 = Subtract.Damage1
|
||||||
|
obj.Subtract.Damage2 = Subtract.Damage2
|
||||||
|
obj.Subtract.Damage3 = Subtract.Damage3
|
||||||
obj.ResistanceDirectHit = ResistanceDirectHit
|
obj.ResistanceDirectHit = ResistanceDirectHit
|
||||||
obj.ResistanceSplash = ResistanceSplash
|
obj.ResistanceSplash = ResistanceSplash
|
||||||
obj.ResistanceAggravated = ResistanceAggravated
|
obj.ResistanceAggravated = ResistanceAggravated
|
||||||
|
|
@ -166,6 +170,7 @@ object ExoSuitDefinition {
|
||||||
MAX.InventoryOffset = 6
|
MAX.InventoryOffset = 6
|
||||||
MAX.Holster(0, EquipmentSize.Max)
|
MAX.Holster(0, EquipmentSize.Max)
|
||||||
MAX.Holster(4, EquipmentSize.Melee)
|
MAX.Holster(4, EquipmentSize.Melee)
|
||||||
|
MAX.Subtract.Damage1 = -2
|
||||||
MAX.ResistanceDirectHit = 6
|
MAX.ResistanceDirectHit = 6
|
||||||
MAX.ResistanceSplash = 35
|
MAX.ResistanceSplash = 35
|
||||||
MAX.ResistanceAggravated = 10
|
MAX.ResistanceAggravated = 10
|
||||||
|
|
|
||||||
|
|
@ -555,11 +555,19 @@ object GlobalDefinitions {
|
||||||
|
|
||||||
val maelstrom = ToolDefinition(ObjectClass.maelstrom)
|
val maelstrom = ToolDefinition(ObjectClass.maelstrom)
|
||||||
|
|
||||||
val phoenix = ToolDefinition(ObjectClass.phoenix) //decimator
|
val phoenix = new ToolDefinition(ObjectClass.phoenix) {
|
||||||
|
override def NextFireModeIndex(index : Int) : Int = index
|
||||||
|
} //decimator
|
||||||
|
|
||||||
val striker = ToolDefinition(ObjectClass.striker)
|
val striker = new ToolDefinition(ObjectClass.striker) {
|
||||||
|
override def NextFireModeIndex(index : Int) : Int = index
|
||||||
|
DefaultFireModeIndex = 1
|
||||||
|
}
|
||||||
|
|
||||||
val hunterseeker = ToolDefinition(ObjectClass.hunterseeker) //phoenix
|
val hunterseeker = new ToolDefinition(ObjectClass.hunterseeker) {
|
||||||
|
override def NextFireModeIndex(index : Int) : Int = index
|
||||||
|
DefaultFireModeIndex = 1
|
||||||
|
} //phoenix
|
||||||
|
|
||||||
val lancer = ToolDefinition(ObjectClass.lancer)
|
val lancer = ToolDefinition(ObjectClass.lancer)
|
||||||
|
|
||||||
|
|
@ -573,7 +581,7 @@ object GlobalDefinitions {
|
||||||
|
|
||||||
val bolt_driver = ToolDefinition(ObjectClass.bolt_driver)
|
val bolt_driver = ToolDefinition(ObjectClass.bolt_driver)
|
||||||
|
|
||||||
val oicw = ToolDefinition(ObjectClass.oicw) //scorpion
|
val oicw = ToolDefinition(ObjectClass.oicw)
|
||||||
|
|
||||||
val flamethrower = ToolDefinition(ObjectClass.flamethrower)
|
val flamethrower = ToolDefinition(ObjectClass.flamethrower)
|
||||||
|
|
||||||
|
|
@ -718,7 +726,9 @@ object GlobalDefinitions {
|
||||||
|
|
||||||
val lightgunship_weapon_system = ToolDefinition(ObjectClass.lightgunship_weapon_system)
|
val lightgunship_weapon_system = ToolDefinition(ObjectClass.lightgunship_weapon_system)
|
||||||
|
|
||||||
val wasp_weapon_system = ToolDefinition(ObjectClass.wasp_weapon_system)
|
val wasp_weapon_system = new ToolDefinition(ObjectClass.wasp_weapon_system) {
|
||||||
|
override def NextFireModeIndex(index : Int) : Int = index
|
||||||
|
}
|
||||||
|
|
||||||
val liberator_weapon_system = ToolDefinition(ObjectClass.liberator_weapon_system)
|
val liberator_weapon_system = ToolDefinition(ObjectClass.liberator_weapon_system)
|
||||||
|
|
||||||
|
|
@ -3924,6 +3934,7 @@ object GlobalDefinitions {
|
||||||
nchev_falcon.Name = "nchev_falcon"
|
nchev_falcon.Name = "nchev_falcon"
|
||||||
nchev_falcon.Size = EquipmentSize.Max
|
nchev_falcon.Size = EquipmentSize.Max
|
||||||
nchev_falcon.AmmoTypes += falcon_ammo
|
nchev_falcon.AmmoTypes += falcon_ammo
|
||||||
|
nchev_falcon.ProjectileTypes += falcon_projectile
|
||||||
nchev_falcon.FireModes += new FireModeDefinition
|
nchev_falcon.FireModes += new FireModeDefinition
|
||||||
nchev_falcon.FireModes.head.AmmoTypeIndices += 0
|
nchev_falcon.FireModes.head.AmmoTypeIndices += 0
|
||||||
nchev_falcon.FireModes.head.AmmoSlotIndex = 0
|
nchev_falcon.FireModes.head.AmmoSlotIndex = 0
|
||||||
|
|
@ -4763,6 +4774,7 @@ object GlobalDefinitions {
|
||||||
threemanheavybuggy.TrunkOffset = 30
|
threemanheavybuggy.TrunkOffset = 30
|
||||||
threemanheavybuggy.AutoPilotSpeeds = (22, 8)
|
threemanheavybuggy.AutoPilotSpeeds = (22, 8)
|
||||||
threemanheavybuggy.DestroyedModel = Some(DestroyedVehicle.ThreeManHeavyBuggy)
|
threemanheavybuggy.DestroyedModel = Some(DestroyedVehicle.ThreeManHeavyBuggy)
|
||||||
|
threemanheavybuggy.Subtract.Damage1 = 5
|
||||||
|
|
||||||
twomanheavybuggy.Name = "twomanheavybuggy"
|
twomanheavybuggy.Name = "twomanheavybuggy"
|
||||||
twomanheavybuggy.MaxHealth = 1800
|
twomanheavybuggy.MaxHealth = 1800
|
||||||
|
|
@ -4779,6 +4791,7 @@ object GlobalDefinitions {
|
||||||
twomanheavybuggy.TrunkOffset = 30
|
twomanheavybuggy.TrunkOffset = 30
|
||||||
twomanheavybuggy.AutoPilotSpeeds = (22, 8)
|
twomanheavybuggy.AutoPilotSpeeds = (22, 8)
|
||||||
twomanheavybuggy.DestroyedModel = Some(DestroyedVehicle.TwoManHeavyBuggy)
|
twomanheavybuggy.DestroyedModel = Some(DestroyedVehicle.TwoManHeavyBuggy)
|
||||||
|
twomanheavybuggy.Subtract.Damage1 = 5
|
||||||
|
|
||||||
twomanhoverbuggy.Name = "twomanhoverbuggy"
|
twomanhoverbuggy.Name = "twomanhoverbuggy"
|
||||||
twomanhoverbuggy.MaxHealth = 1600
|
twomanhoverbuggy.MaxHealth = 1600
|
||||||
|
|
@ -4795,6 +4808,7 @@ object GlobalDefinitions {
|
||||||
twomanhoverbuggy.TrunkOffset = 30
|
twomanhoverbuggy.TrunkOffset = 30
|
||||||
twomanhoverbuggy.AutoPilotSpeeds = (22, 10)
|
twomanhoverbuggy.AutoPilotSpeeds = (22, 10)
|
||||||
twomanhoverbuggy.DestroyedModel = Some(DestroyedVehicle.TwoManHoverBuggy)
|
twomanhoverbuggy.DestroyedModel = Some(DestroyedVehicle.TwoManHoverBuggy)
|
||||||
|
twomanhoverbuggy.Subtract.Damage1 = 5
|
||||||
|
|
||||||
mediumtransport.Name = "mediumtransport"
|
mediumtransport.Name = "mediumtransport"
|
||||||
mediumtransport.MaxHealth = 2500
|
mediumtransport.MaxHealth = 2500
|
||||||
|
|
@ -4818,6 +4832,7 @@ object GlobalDefinitions {
|
||||||
mediumtransport.TrunkOffset = 30
|
mediumtransport.TrunkOffset = 30
|
||||||
mediumtransport.AutoPilotSpeeds = (18, 6)
|
mediumtransport.AutoPilotSpeeds = (18, 6)
|
||||||
mediumtransport.DestroyedModel = Some(DestroyedVehicle.MediumTransport)
|
mediumtransport.DestroyedModel = Some(DestroyedVehicle.MediumTransport)
|
||||||
|
mediumtransport.Subtract.Damage1 = 7
|
||||||
|
|
||||||
battlewagon.Name = "battlewagon"
|
battlewagon.Name = "battlewagon"
|
||||||
battlewagon.MaxHealth = 2500
|
battlewagon.MaxHealth = 2500
|
||||||
|
|
@ -4868,6 +4883,7 @@ object GlobalDefinitions {
|
||||||
thunderer.TrunkOffset = 30
|
thunderer.TrunkOffset = 30
|
||||||
thunderer.AutoPilotSpeeds = (18, 6)
|
thunderer.AutoPilotSpeeds = (18, 6)
|
||||||
thunderer.DestroyedModel = Some(DestroyedVehicle.MediumTransport)
|
thunderer.DestroyedModel = Some(DestroyedVehicle.MediumTransport)
|
||||||
|
thunderer.Subtract.Damage1 = 7
|
||||||
|
|
||||||
aurora.Name = "aurora"
|
aurora.Name = "aurora"
|
||||||
aurora.MaxHealth = 2500
|
aurora.MaxHealth = 2500
|
||||||
|
|
@ -4891,6 +4907,7 @@ object GlobalDefinitions {
|
||||||
aurora.TrunkOffset = 30
|
aurora.TrunkOffset = 30
|
||||||
aurora.AutoPilotSpeeds = (18, 6)
|
aurora.AutoPilotSpeeds = (18, 6)
|
||||||
aurora.DestroyedModel = Some(DestroyedVehicle.MediumTransport)
|
aurora.DestroyedModel = Some(DestroyedVehicle.MediumTransport)
|
||||||
|
aurora.Subtract.Damage1 = 7
|
||||||
|
|
||||||
apc_tr.Name = "apc_tr"
|
apc_tr.Name = "apc_tr"
|
||||||
apc_tr.MaxHealth = 6000
|
apc_tr.MaxHealth = 6000
|
||||||
|
|
@ -5043,6 +5060,7 @@ object GlobalDefinitions {
|
||||||
lightning.TrunkOffset = 30
|
lightning.TrunkOffset = 30
|
||||||
lightning.AutoPilotSpeeds = (20, 8)
|
lightning.AutoPilotSpeeds = (20, 8)
|
||||||
lightning.DestroyedModel = Some(DestroyedVehicle.Lightning)
|
lightning.DestroyedModel = Some(DestroyedVehicle.Lightning)
|
||||||
|
lightning.Subtract.Damage1 = 7
|
||||||
|
|
||||||
prowler.Name = "prowler"
|
prowler.Name = "prowler"
|
||||||
prowler.MaxHealth = 4800
|
prowler.MaxHealth = 4800
|
||||||
|
|
@ -5062,6 +5080,7 @@ object GlobalDefinitions {
|
||||||
prowler.TrunkOffset = 30
|
prowler.TrunkOffset = 30
|
||||||
prowler.AutoPilotSpeeds = (14, 6)
|
prowler.AutoPilotSpeeds = (14, 6)
|
||||||
prowler.DestroyedModel = Some(DestroyedVehicle.Prowler)
|
prowler.DestroyedModel = Some(DestroyedVehicle.Prowler)
|
||||||
|
prowler.Subtract.Damage1 = 9
|
||||||
|
|
||||||
vanguard.Name = "vanguard"
|
vanguard.Name = "vanguard"
|
||||||
vanguard.MaxHealth = 5400
|
vanguard.MaxHealth = 5400
|
||||||
|
|
@ -5077,6 +5096,7 @@ object GlobalDefinitions {
|
||||||
vanguard.TrunkOffset = 30
|
vanguard.TrunkOffset = 30
|
||||||
vanguard.AutoPilotSpeeds = (16, 6)
|
vanguard.AutoPilotSpeeds = (16, 6)
|
||||||
vanguard.DestroyedModel = Some(DestroyedVehicle.Vanguard)
|
vanguard.DestroyedModel = Some(DestroyedVehicle.Vanguard)
|
||||||
|
vanguard.Subtract.Damage1 = 9
|
||||||
|
|
||||||
magrider.Name = "magrider"
|
magrider.Name = "magrider"
|
||||||
magrider.MaxHealth = 4200
|
magrider.MaxHealth = 4200
|
||||||
|
|
@ -5094,6 +5114,7 @@ object GlobalDefinitions {
|
||||||
magrider.TrunkOffset = 30
|
magrider.TrunkOffset = 30
|
||||||
magrider.AutoPilotSpeeds = (18, 6)
|
magrider.AutoPilotSpeeds = (18, 6)
|
||||||
magrider.DestroyedModel = Some(DestroyedVehicle.Magrider)
|
magrider.DestroyedModel = Some(DestroyedVehicle.Magrider)
|
||||||
|
magrider.Subtract.Damage1 = 9
|
||||||
|
|
||||||
val utilityConverter = new UtilityVehicleConverter
|
val utilityConverter = new UtilityVehicleConverter
|
||||||
ant.Name = "ant"
|
ant.Name = "ant"
|
||||||
|
|
@ -5110,6 +5131,7 @@ object GlobalDefinitions {
|
||||||
ant.MaximumCapacitor = 1500
|
ant.MaximumCapacitor = 1500
|
||||||
ant.Packet = utilityConverter
|
ant.Packet = utilityConverter
|
||||||
ant.DestroyedModel = Some(DestroyedVehicle.Ant)
|
ant.DestroyedModel = Some(DestroyedVehicle.Ant)
|
||||||
|
ant.Subtract.Damage1 = 5
|
||||||
|
|
||||||
ams.Name = "ams"
|
ams.Name = "ams"
|
||||||
ams.MaxHealth = 3000
|
ams.MaxHealth = 3000
|
||||||
|
|
@ -5129,6 +5151,7 @@ object GlobalDefinitions {
|
||||||
ams.AutoPilotSpeeds = (18, 6)
|
ams.AutoPilotSpeeds = (18, 6)
|
||||||
ams.Packet = utilityConverter
|
ams.Packet = utilityConverter
|
||||||
ams.DestroyedModel = Some(DestroyedVehicle.Ams)
|
ams.DestroyedModel = Some(DestroyedVehicle.Ams)
|
||||||
|
ams.Subtract.Damage1 = 10
|
||||||
|
|
||||||
val variantConverter = new VariantVehicleConverter
|
val variantConverter = new VariantVehicleConverter
|
||||||
router.Name = "router"
|
router.Name = "router"
|
||||||
|
|
@ -5147,6 +5170,7 @@ object GlobalDefinitions {
|
||||||
router.AutoPilotSpeeds = (16, 6)
|
router.AutoPilotSpeeds = (16, 6)
|
||||||
router.Packet = variantConverter
|
router.Packet = variantConverter
|
||||||
router.DestroyedModel = Some(DestroyedVehicle.Router)
|
router.DestroyedModel = Some(DestroyedVehicle.Router)
|
||||||
|
router.Subtract.Damage1 = 5
|
||||||
|
|
||||||
switchblade.Name = "switchblade"
|
switchblade.Name = "switchblade"
|
||||||
switchblade.MaxHealth = 1750
|
switchblade.MaxHealth = 1750
|
||||||
|
|
@ -5164,6 +5188,8 @@ object GlobalDefinitions {
|
||||||
switchblade.AutoPilotSpeeds = (22, 8)
|
switchblade.AutoPilotSpeeds = (22, 8)
|
||||||
switchblade.Packet = variantConverter
|
switchblade.Packet = variantConverter
|
||||||
switchblade.DestroyedModel = Some(DestroyedVehicle.Switchblade)
|
switchblade.DestroyedModel = Some(DestroyedVehicle.Switchblade)
|
||||||
|
switchblade.Subtract.Damage0 = 5
|
||||||
|
switchblade.Subtract.Damage1 = 5
|
||||||
|
|
||||||
flail.Name = "flail"
|
flail.Name = "flail"
|
||||||
flail.MaxHealth = 2400
|
flail.MaxHealth = 2400
|
||||||
|
|
@ -5180,6 +5206,7 @@ object GlobalDefinitions {
|
||||||
flail.AutoPilotSpeeds = (14, 6)
|
flail.AutoPilotSpeeds = (14, 6)
|
||||||
flail.Packet = variantConverter
|
flail.Packet = variantConverter
|
||||||
flail.DestroyedModel = Some(DestroyedVehicle.Flail)
|
flail.DestroyedModel = Some(DestroyedVehicle.Flail)
|
||||||
|
flail.Subtract.Damage1 = 7
|
||||||
|
|
||||||
mosquito.Name = "mosquito"
|
mosquito.Name = "mosquito"
|
||||||
mosquito.MaxHealth = 665
|
mosquito.MaxHealth = 665
|
||||||
|
|
@ -5210,6 +5237,7 @@ object GlobalDefinitions {
|
||||||
lightgunship.AutoPilotSpeeds = (0, 4)
|
lightgunship.AutoPilotSpeeds = (0, 4)
|
||||||
lightgunship.Packet = variantConverter
|
lightgunship.Packet = variantConverter
|
||||||
lightgunship.DestroyedModel = Some(DestroyedVehicle.LightGunship)
|
lightgunship.DestroyedModel = Some(DestroyedVehicle.LightGunship)
|
||||||
|
lightgunship.Subtract.Damage1 = 3
|
||||||
|
|
||||||
wasp.Name = "wasp"
|
wasp.Name = "wasp"
|
||||||
wasp.MaxHealth = 515
|
wasp.MaxHealth = 515
|
||||||
|
|
@ -5247,6 +5275,7 @@ object GlobalDefinitions {
|
||||||
liberator.AutoPilotSpeeds = (0, 4)
|
liberator.AutoPilotSpeeds = (0, 4)
|
||||||
liberator.Packet = variantConverter
|
liberator.Packet = variantConverter
|
||||||
liberator.DestroyedModel = Some(DestroyedVehicle.Liberator)
|
liberator.DestroyedModel = Some(DestroyedVehicle.Liberator)
|
||||||
|
liberator.Subtract.Damage1 = 5
|
||||||
|
|
||||||
vulture.Name = "vulture"
|
vulture.Name = "vulture"
|
||||||
vulture.MaxHealth = 2500
|
vulture.MaxHealth = 2500
|
||||||
|
|
@ -5269,6 +5298,7 @@ object GlobalDefinitions {
|
||||||
vulture.AutoPilotSpeeds = (0, 4)
|
vulture.AutoPilotSpeeds = (0, 4)
|
||||||
vulture.Packet = variantConverter
|
vulture.Packet = variantConverter
|
||||||
vulture.DestroyedModel = Some(DestroyedVehicle.Liberator) //add_property vulture destroyedphysics liberator_destroyed
|
vulture.DestroyedModel = Some(DestroyedVehicle.Liberator) //add_property vulture destroyedphysics liberator_destroyed
|
||||||
|
vulture.Subtract.Damage1 = 5
|
||||||
|
|
||||||
dropship.Name = "dropship"
|
dropship.Name = "dropship"
|
||||||
dropship.MaxHealth = 5000
|
dropship.MaxHealth = 5000
|
||||||
|
|
@ -5323,6 +5353,7 @@ object GlobalDefinitions {
|
||||||
dropship.AutoPilotSpeeds = (0, 4)
|
dropship.AutoPilotSpeeds = (0, 4)
|
||||||
dropship.Packet = variantConverter
|
dropship.Packet = variantConverter
|
||||||
dropship.DestroyedModel = Some(DestroyedVehicle.Dropship)
|
dropship.DestroyedModel = Some(DestroyedVehicle.Dropship)
|
||||||
|
dropship.Subtract.Damage1 = 7
|
||||||
|
|
||||||
galaxy_gunship.Name = "galaxy_gunship"
|
galaxy_gunship.Name = "galaxy_gunship"
|
||||||
galaxy_gunship.MaxHealth = 6000
|
galaxy_gunship.MaxHealth = 6000
|
||||||
|
|
@ -5354,6 +5385,7 @@ object GlobalDefinitions {
|
||||||
galaxy_gunship.AutoPilotSpeeds = (0, 4)
|
galaxy_gunship.AutoPilotSpeeds = (0, 4)
|
||||||
galaxy_gunship.Packet = variantConverter
|
galaxy_gunship.Packet = variantConverter
|
||||||
galaxy_gunship.DestroyedModel = Some(DestroyedVehicle.Dropship) //the adb calls out a galaxy_gunship_destroyed but no such asset exists
|
galaxy_gunship.DestroyedModel = Some(DestroyedVehicle.Dropship) //the adb calls out a galaxy_gunship_destroyed but no such asset exists
|
||||||
|
galaxy_gunship.Subtract.Damage1 = 7
|
||||||
|
|
||||||
lodestar.Name = "lodestar"
|
lodestar.Name = "lodestar"
|
||||||
lodestar.MaxHealth = 5000
|
lodestar.MaxHealth = 5000
|
||||||
|
|
@ -5367,6 +5399,7 @@ object GlobalDefinitions {
|
||||||
lodestar.AutoPilotSpeeds = (0, 4)
|
lodestar.AutoPilotSpeeds = (0, 4)
|
||||||
lodestar.Packet = variantConverter
|
lodestar.Packet = variantConverter
|
||||||
lodestar.DestroyedModel = Some(DestroyedVehicle.Lodestar)
|
lodestar.DestroyedModel = Some(DestroyedVehicle.Lodestar)
|
||||||
|
lodestar.Subtract.Damage1 = 7
|
||||||
|
|
||||||
phantasm.Name = "phantasm"
|
phantasm.Name = "phantasm"
|
||||||
phantasm.MaxHealth = 2500
|
phantasm.MaxHealth = 2500
|
||||||
|
|
|
||||||
|
|
@ -281,6 +281,8 @@ class Player(private val core : Avatar) extends PlanetSideGameObject
|
||||||
ChangeSpecialAbility()
|
ChangeSpecialAbility()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def Subtract = exosuit.Subtract
|
||||||
|
|
||||||
def ResistanceDirectHit = exosuit.ResistanceDirectHit
|
def ResistanceDirectHit = exosuit.ResistanceDirectHit
|
||||||
|
|
||||||
def ResistanceSplash = exosuit.ResistanceSplash
|
def ResistanceSplash = exosuit.ResistanceSplash
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import scala.annotation.tailrec
|
||||||
class Tool(private val toolDef : ToolDefinition) extends Equipment
|
class Tool(private val toolDef : ToolDefinition) extends Equipment
|
||||||
with FireModeSwitch[FireModeDefinition] {
|
with FireModeSwitch[FireModeDefinition] {
|
||||||
/** index of the current fire mode on the `ToolDefinition`'s list of fire modes */
|
/** index of the current fire mode on the `ToolDefinition`'s list of fire modes */
|
||||||
private var fireModeIndex : Int = 0
|
private var fireModeIndex : Int = toolDef.DefaultFireModeIndex
|
||||||
/** current ammunition slot being used by this fire mode */
|
/** current ammunition slot being used by this fire mode */
|
||||||
private var ammoSlots : List[Tool.FireModeSlot] = List.empty
|
private var ammoSlots : List[Tool.FireModeSlot] = List.empty
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ package net.psforever.objects.ballistics
|
||||||
import net.psforever.objects.TurretDeployable
|
import net.psforever.objects.TurretDeployable
|
||||||
import net.psforever.objects.ce.ComplexDeployable
|
import net.psforever.objects.ce.ComplexDeployable
|
||||||
import net.psforever.objects.definition.{BaseDeployableDefinition, ObjectDefinition}
|
import net.psforever.objects.definition.{BaseDeployableDefinition, ObjectDefinition}
|
||||||
|
import net.psforever.objects.vital.resistance.ResistanceProfile
|
||||||
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
||||||
|
|
||||||
final case class ComplexDeployableSource(obj_def : ObjectDefinition with BaseDeployableDefinition,
|
final case class ComplexDeployableSource(obj_def : ObjectDefinition with BaseDeployableDefinition,
|
||||||
|
|
@ -22,6 +23,7 @@ final case class ComplexDeployableSource(obj_def : ObjectDefinition with BaseDep
|
||||||
def Position = position
|
def Position = position
|
||||||
def Orientation = orientation
|
def Orientation = orientation
|
||||||
def Velocity = None
|
def Velocity = None
|
||||||
|
def Modifiers = obj_def.asInstanceOf[ResistanceProfile]
|
||||||
}
|
}
|
||||||
|
|
||||||
object ComplexDeployableSource {
|
object ComplexDeployableSource {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ package net.psforever.objects.ballistics
|
||||||
import net.psforever.objects.PlanetSideGameObject
|
import net.psforever.objects.PlanetSideGameObject
|
||||||
import net.psforever.objects.ce.Deployable
|
import net.psforever.objects.ce.Deployable
|
||||||
import net.psforever.objects.definition.{BaseDeployableDefinition, ObjectDefinition}
|
import net.psforever.objects.definition.{BaseDeployableDefinition, ObjectDefinition}
|
||||||
|
import net.psforever.objects.vital.resistance.ResistanceProfile
|
||||||
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
||||||
|
|
||||||
final case class DeployableSource(obj_def : ObjectDefinition with BaseDeployableDefinition,
|
final case class DeployableSource(obj_def : ObjectDefinition with BaseDeployableDefinition,
|
||||||
|
|
@ -20,6 +21,7 @@ final case class DeployableSource(obj_def : ObjectDefinition with BaseDeployable
|
||||||
def Position = position
|
def Position = position
|
||||||
def Orientation = orientation
|
def Orientation = orientation
|
||||||
def Velocity = None
|
def Velocity = None
|
||||||
|
def Modifiers = obj_def.asInstanceOf[ResistanceProfile]
|
||||||
}
|
}
|
||||||
|
|
||||||
object DeployableSource {
|
object DeployableSource {
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,21 @@ package net.psforever.objects.ballistics
|
||||||
|
|
||||||
import net.psforever.objects.PlanetSideGameObject
|
import net.psforever.objects.PlanetSideGameObject
|
||||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||||
|
import net.psforever.objects.vital.resistance.ResistanceProfileMutators
|
||||||
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
||||||
|
|
||||||
final case class ObjectSource(obj : PlanetSideGameObject with FactionAffinity,
|
final case class ObjectSource(obj : PlanetSideGameObject with FactionAffinity,
|
||||||
faction : PlanetSideEmpire.Value,
|
faction : PlanetSideEmpire.Value,
|
||||||
position : Vector3,
|
position : Vector3,
|
||||||
orientation : Vector3,
|
orientation : Vector3,
|
||||||
velocity : Option[Vector3] = None) extends SourceEntry {
|
velocity : Option[Vector3]) extends SourceEntry {
|
||||||
override def Name = SourceEntry.NameFormat(obj.Definition.Name)
|
override def Name = SourceEntry.NameFormat(obj.Definition.Name)
|
||||||
override def Faction = faction
|
override def Faction = faction
|
||||||
def Definition = obj.Definition
|
def Definition = obj.Definition
|
||||||
def Position = position
|
def Position = position
|
||||||
def Orientation = orientation
|
def Orientation = orientation
|
||||||
def Velocity = velocity
|
def Velocity = velocity
|
||||||
|
def Modifiers = new ResistanceProfileMutators { }
|
||||||
}
|
}
|
||||||
|
|
||||||
object ObjectSource {
|
object ObjectSource {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package net.psforever.objects.ballistics
|
||||||
|
|
||||||
import net.psforever.objects.Player
|
import net.psforever.objects.Player
|
||||||
import net.psforever.objects.definition.ObjectDefinition
|
import net.psforever.objects.definition.ObjectDefinition
|
||||||
|
import net.psforever.objects.vital.resistance.ResistanceProfile
|
||||||
import net.psforever.types.{ExoSuitType, PlanetSideEmpire, Vector3}
|
import net.psforever.types.{ExoSuitType, PlanetSideEmpire, Vector3}
|
||||||
|
|
||||||
final case class PlayerSource(name : String,
|
final case class PlayerSource(name : String,
|
||||||
|
|
@ -14,7 +15,8 @@ final case class PlayerSource(name : String,
|
||||||
armor : Int,
|
armor : Int,
|
||||||
position : Vector3,
|
position : Vector3,
|
||||||
orientation : Vector3,
|
orientation : Vector3,
|
||||||
velocity : Option[Vector3] = None) extends SourceEntry {
|
velocity : Option[Vector3],
|
||||||
|
modifiers : ResistanceProfile) extends SourceEntry {
|
||||||
override def Name = name
|
override def Name = name
|
||||||
override def Faction = faction
|
override def Faction = faction
|
||||||
def Definition = obj_def
|
def Definition = obj_def
|
||||||
|
|
@ -25,11 +27,12 @@ final case class PlayerSource(name : String,
|
||||||
def Position = position
|
def Position = position
|
||||||
def Orientation = orientation
|
def Orientation = orientation
|
||||||
def Velocity = velocity
|
def Velocity = velocity
|
||||||
|
def Modifiers = modifiers
|
||||||
}
|
}
|
||||||
|
|
||||||
object PlayerSource {
|
object PlayerSource {
|
||||||
def apply(tplayer : Player) : PlayerSource = {
|
def apply(tplayer : Player) : PlayerSource = {
|
||||||
PlayerSource(tplayer.Name, tplayer.Definition, tplayer.Faction, tplayer.ExoSuit, tplayer.VehicleSeated.nonEmpty,
|
PlayerSource(tplayer.Name, tplayer.Definition, tplayer.Faction, tplayer.ExoSuit, tplayer.VehicleSeated.nonEmpty,
|
||||||
tplayer.Health, tplayer.Armor, tplayer.Position, tplayer.Orientation, tplayer.Velocity)
|
tplayer.Health, tplayer.Armor, tplayer.Position, tplayer.Orientation, tplayer.Velocity, tplayer.asInstanceOf[ResistanceProfile])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import net.psforever.objects.definition.ObjectDefinition
|
||||||
import net.psforever.objects.{PlanetSideGameObject, Player, TurretDeployable, Vehicle}
|
import net.psforever.objects.{PlanetSideGameObject, Player, TurretDeployable, Vehicle}
|
||||||
import net.psforever.objects.entity.WorldEntity
|
import net.psforever.objects.entity.WorldEntity
|
||||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||||
|
import net.psforever.objects.vital.resistance.ResistanceProfile
|
||||||
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
||||||
|
|
||||||
trait SourceEntry extends WorldEntity {
|
trait SourceEntry extends WorldEntity {
|
||||||
|
|
@ -16,6 +17,7 @@ trait SourceEntry extends WorldEntity {
|
||||||
def Position_=(pos : Vector3) = Position
|
def Position_=(pos : Vector3) = Position
|
||||||
def Orientation_=(pos : Vector3) = Position
|
def Orientation_=(pos : Vector3) = Position
|
||||||
def Velocity_=(pos : Option[Vector3]) = Velocity
|
def Velocity_=(pos : Option[Vector3]) = Velocity
|
||||||
|
def Modifiers : ResistanceProfile
|
||||||
}
|
}
|
||||||
|
|
||||||
object SourceEntry {
|
object SourceEntry {
|
||||||
|
|
@ -24,6 +26,7 @@ object SourceEntry {
|
||||||
def Position = Vector3.Zero
|
def Position = Vector3.Zero
|
||||||
def Orientation = Vector3.Zero
|
def Orientation = Vector3.Zero
|
||||||
def Velocity = Some(Vector3.Zero)
|
def Velocity = Some(Vector3.Zero)
|
||||||
|
def Modifiers = null
|
||||||
}
|
}
|
||||||
|
|
||||||
def apply(target : PlanetSideGameObject with FactionAffinity) : SourceEntry = {
|
def apply(target : PlanetSideGameObject with FactionAffinity) : SourceEntry = {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package net.psforever.objects.ballistics
|
||||||
|
|
||||||
import net.psforever.objects.Vehicle
|
import net.psforever.objects.Vehicle
|
||||||
import net.psforever.objects.definition.VehicleDefinition
|
import net.psforever.objects.definition.VehicleDefinition
|
||||||
|
import net.psforever.objects.vital.resistance.ResistanceProfile
|
||||||
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
||||||
|
|
||||||
final case class VehicleSource(obj_def : VehicleDefinition,
|
final case class VehicleSource(obj_def : VehicleDefinition,
|
||||||
|
|
@ -11,7 +12,8 @@ final case class VehicleSource(obj_def : VehicleDefinition,
|
||||||
shields : Int,
|
shields : Int,
|
||||||
position : Vector3,
|
position : Vector3,
|
||||||
orientation : Vector3,
|
orientation : Vector3,
|
||||||
velocity : Option[Vector3] = None) extends SourceEntry {
|
velocity : Option[Vector3],
|
||||||
|
modifiers : ResistanceProfile) extends SourceEntry {
|
||||||
override def Name = SourceEntry.NameFormat(obj_def.Name)
|
override def Name = SourceEntry.NameFormat(obj_def.Name)
|
||||||
override def Faction = faction
|
override def Faction = faction
|
||||||
def Definition : VehicleDefinition = obj_def
|
def Definition : VehicleDefinition = obj_def
|
||||||
|
|
@ -20,6 +22,7 @@ final case class VehicleSource(obj_def : VehicleDefinition,
|
||||||
def Position = position
|
def Position = position
|
||||||
def Orientation = orientation
|
def Orientation = orientation
|
||||||
def Velocity = velocity
|
def Velocity = velocity
|
||||||
|
def Modifiers = modifiers
|
||||||
}
|
}
|
||||||
|
|
||||||
object VehicleSource {
|
object VehicleSource {
|
||||||
|
|
@ -31,7 +34,8 @@ object VehicleSource {
|
||||||
obj.Shields,
|
obj.Shields,
|
||||||
obj.Position,
|
obj.Position,
|
||||||
obj.Orientation,
|
obj.Orientation,
|
||||||
obj.Velocity
|
obj.Velocity,
|
||||||
|
obj.Definition.asInstanceOf[ResistanceProfile]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,13 @@ import net.psforever.objects.PlanetSideGameObject
|
||||||
import net.psforever.objects.ce.{Deployable, DeployableCategory, DeployedItem}
|
import net.psforever.objects.ce.{Deployable, DeployableCategory, DeployedItem}
|
||||||
import net.psforever.objects.definition.converter.SmallDeployableConverter
|
import net.psforever.objects.definition.converter.SmallDeployableConverter
|
||||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
import net.psforever.objects.vital.{DamageResistanceModel, NoResistanceSelection, StandardDeployableDamage}
|
import net.psforever.objects.vital.resistance.ResistanceProfileMutators
|
||||||
|
import net.psforever.objects.vital.{DamageResistanceModel, NoResistanceSelection, StandardDeployableDamage, StandardResistanceProfile}
|
||||||
|
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
trait BaseDeployableDefinition extends DamageResistanceModel {
|
trait BaseDeployableDefinition extends DamageResistanceModel
|
||||||
|
with ResistanceProfileMutators {
|
||||||
private var category : DeployableCategory.Value = DeployableCategory.Boomers
|
private var category : DeployableCategory.Value = DeployableCategory.Boomers
|
||||||
private var deployTime : Long = (1 second).toMillis //ms
|
private var deployTime : Long = (1 second).toMillis //ms
|
||||||
private var maxHealth : Int = 1
|
private var maxHealth : Int = 1
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,7 @@
|
||||||
package net.psforever.objects.definition
|
package net.psforever.objects.definition
|
||||||
|
|
||||||
import net.psforever.objects.ballistics.Projectiles
|
import net.psforever.objects.ballistics.Projectiles
|
||||||
import net.psforever.objects.vital.DamageType
|
import net.psforever.objects.vital.{DamageType, StandardDamageProfile}
|
||||||
import net.psforever.objects.vital.damage.DamageProfile
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The definition that outlines the damage-dealing characteristics of any projectile.
|
* The definition that outlines the damage-dealing characteristics of any projectile.
|
||||||
|
|
@ -11,13 +10,8 @@ import net.psforever.objects.vital.damage.DamageProfile
|
||||||
* @param objectId the object's identifier number
|
* @param objectId the object's identifier number
|
||||||
*/
|
*/
|
||||||
class ProjectileDefinition(objectId : Int) extends ObjectDefinition(objectId)
|
class ProjectileDefinition(objectId : Int) extends ObjectDefinition(objectId)
|
||||||
with DamageProfile {
|
with StandardDamageProfile {
|
||||||
private val projectileType : Projectiles.Value = Projectiles(objectId) //let throw NoSuchElementException
|
private val projectileType : Projectiles.Value = Projectiles(objectId) //let throw NoSuchElementException
|
||||||
private var damage0 : Int = 0
|
|
||||||
private var damage1 : Option[Int] = None
|
|
||||||
private var damage2 : Option[Int] = None
|
|
||||||
private var damage3 : Option[Int] = None
|
|
||||||
private var damage4 : Option[Int] = None
|
|
||||||
private var acceleration : Int = 0
|
private var acceleration : Int = 0
|
||||||
private var accelerationUntil : Float = 0f
|
private var accelerationUntil : Float = 0f
|
||||||
private var damageType : DamageType.Value = DamageType.None
|
private var damageType : DamageType.Value = DamageType.None
|
||||||
|
|
@ -45,57 +39,6 @@ class ProjectileDefinition(objectId : Int) extends ObjectDefinition(objectId)
|
||||||
UseDamage1Subtract
|
UseDamage1Subtract
|
||||||
}
|
}
|
||||||
|
|
||||||
def Damage0 : Int = damage0
|
|
||||||
|
|
||||||
def Damage0_=(damage : Int) : Int = {
|
|
||||||
damage0 = damage
|
|
||||||
damage0
|
|
||||||
}
|
|
||||||
|
|
||||||
def Damage0_=(damage : Option[Int]) : Int = {
|
|
||||||
damage0 = damage match {
|
|
||||||
case Some(value) => value
|
|
||||||
case None => 0 //can not be set to None
|
|
||||||
}
|
|
||||||
Damage0
|
|
||||||
}
|
|
||||||
|
|
||||||
def Damage1 : Int = damage1.getOrElse(Damage0)
|
|
||||||
|
|
||||||
def Damage1_=(damage : Int) : Int = Damage1_=(Some(damage))
|
|
||||||
|
|
||||||
def Damage1_=(damage : Option[Int]) : Int = {
|
|
||||||
this.damage1 = damage
|
|
||||||
Damage1
|
|
||||||
}
|
|
||||||
|
|
||||||
def Damage2 : Int = damage2.getOrElse(Damage1)
|
|
||||||
|
|
||||||
def Damage2_=(damage : Int) : Int = Damage2_=(Some(damage))
|
|
||||||
|
|
||||||
def Damage2_=(damage : Option[Int]) : Int = {
|
|
||||||
this.damage2 = damage
|
|
||||||
Damage2
|
|
||||||
}
|
|
||||||
|
|
||||||
def Damage3 : Int = damage3.getOrElse(Damage2)
|
|
||||||
|
|
||||||
def Damage3_=(damage : Int) : Int = Damage3_=(Some(damage))
|
|
||||||
|
|
||||||
def Damage3_=(damage : Option[Int]) : Int = {
|
|
||||||
this.damage3 = damage
|
|
||||||
Damage3
|
|
||||||
}
|
|
||||||
|
|
||||||
def Damage4 : Int = damage4.getOrElse(Damage3)
|
|
||||||
|
|
||||||
def Damage4_=(damage : Int) : Int = Damage4_=(Some(damage))
|
|
||||||
|
|
||||||
def Damage4_=(damage : Option[Int]) : Int = {
|
|
||||||
this.damage4 = damage
|
|
||||||
Damage4
|
|
||||||
}
|
|
||||||
|
|
||||||
def Acceleration : Int = acceleration
|
def Acceleration : Int = acceleration
|
||||||
|
|
||||||
def Acceleration_=(accel : Int) : Int = {
|
def Acceleration_=(accel : Int) : Int = {
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ class ToolDefinition(objectId : Int) extends EquipmentDefinition(objectId) {
|
||||||
private val ammoTypes : mutable.ListBuffer[AmmoBoxDefinition] = new mutable.ListBuffer[AmmoBoxDefinition]
|
private val ammoTypes : mutable.ListBuffer[AmmoBoxDefinition] = new mutable.ListBuffer[AmmoBoxDefinition]
|
||||||
private val projectileTypes : mutable.ListBuffer[ProjectileDefinition] = new mutable.ListBuffer[ProjectileDefinition]
|
private val projectileTypes : mutable.ListBuffer[ProjectileDefinition] = new mutable.ListBuffer[ProjectileDefinition]
|
||||||
private val fireModes : mutable.ListBuffer[FireModeDefinition] = new mutable.ListBuffer[FireModeDefinition]
|
private val fireModes : mutable.ListBuffer[FireModeDefinition] = new mutable.ListBuffer[FireModeDefinition]
|
||||||
|
private var defaultFireModeIndex : Option[Int] = None
|
||||||
Name = "tool"
|
Name = "tool"
|
||||||
Packet = ToolDefinition.converter
|
Packet = ToolDefinition.converter
|
||||||
|
|
||||||
|
|
@ -20,6 +21,15 @@ class ToolDefinition(objectId : Int) extends EquipmentDefinition(objectId) {
|
||||||
def FireModes : mutable.ListBuffer[FireModeDefinition] = fireModes
|
def FireModes : mutable.ListBuffer[FireModeDefinition] = fireModes
|
||||||
|
|
||||||
def NextFireModeIndex(index : Int) : Int = index + 1
|
def NextFireModeIndex(index : Int) : Int = index + 1
|
||||||
|
|
||||||
|
def DefaultFireModeIndex : Int = defaultFireModeIndex.getOrElse(0)
|
||||||
|
|
||||||
|
def DefaultFireModeIndex_=(index : Int) : Int = DefaultFireModeIndex_=(Some(index))
|
||||||
|
|
||||||
|
def DefaultFireModeIndex_=(index : Option[Int]) : Int = {
|
||||||
|
defaultFireModeIndex = index
|
||||||
|
DefaultFireModeIndex
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object ToolDefinition {
|
object ToolDefinition {
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ class VehicleDefinition(objectId : Int) extends ObjectDefinition(objectId)
|
||||||
}
|
}
|
||||||
|
|
||||||
def Seats : mutable.HashMap[Int, SeatDefinition] = seats
|
def Seats : mutable.HashMap[Int, SeatDefinition] = seats
|
||||||
|
|
||||||
def Cargo : mutable.HashMap[Int, CargoDefinition] = cargo
|
def Cargo : mutable.HashMap[Int, CargoDefinition] = cargo
|
||||||
|
|
||||||
def MountPoints : mutable.HashMap[Int, Int] = mountPoints
|
def MountPoints : mutable.HashMap[Int, Int] = mountPoints
|
||||||
|
|
|
||||||
|
|
@ -226,10 +226,12 @@ class GridInventory extends Container {
|
||||||
else {
|
else {
|
||||||
val collisions : mutable.Set[InventoryItem] = mutable.Set[InventoryItem]()
|
val collisions : mutable.Set[InventoryItem] = mutable.Set[InventoryItem]()
|
||||||
var curr = actualSlot
|
var curr = actualSlot
|
||||||
|
val fixedItems = items.toMap
|
||||||
|
val fixedGrid = grid.toList
|
||||||
for(_ <- 0 until h) {
|
for(_ <- 0 until h) {
|
||||||
for(col <- 0 until w) {
|
for(col <- 0 until w) {
|
||||||
if(grid(curr + col) > -1) {
|
if(fixedGrid(curr + col) > -1) {
|
||||||
collisions += items(grid(curr + col))
|
collisions += fixedItems(fixedGrid(curr + col))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
curr += width
|
curr += width
|
||||||
|
|
|
||||||
|
|
@ -71,16 +71,15 @@ object ResourceSilo {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiate an configure a `Resource Silo` object
|
* Instantiate and configure a `Resource Silo` object
|
||||||
* @param id the unique id that will be assigned to this entity
|
* @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;
|
||||||
* not necessary for this object, but required by signature
|
* not necessary for this object, but required by signature
|
||||||
* @return the `Locker` object
|
* @return the `ResourceSilo` object
|
||||||
*/
|
*/
|
||||||
def Constructor(id : Int, context : ActorContext) : ResourceSilo = {
|
def Constructor(id : Int, context : ActorContext) : ResourceSilo = {
|
||||||
val obj = ResourceSilo()
|
val obj = ResourceSilo()
|
||||||
obj.Actor = context.actorOf(Props(classOf[ResourceSiloControl], obj), s"${obj.Definition.Name}_$id")
|
obj.Actor = context.actorOf(Props(classOf[ResourceSiloControl], obj), s"${obj.Definition.Name}_$id")
|
||||||
obj.Actor ! "startup"
|
|
||||||
obj
|
obj
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ class ResourceSiloControl(resourceSilo : ResourceSilo) extends Actor with Factio
|
||||||
sender ! ResourceSilo.ResourceSiloMessage(player, msg, resourceSilo.Use(player, msg))
|
sender ! ResourceSilo.ResourceSiloMessage(player, msg, resourceSilo.Use(player, msg))
|
||||||
case ResourceSilo.LowNtuWarning(enabled: Boolean) =>
|
case ResourceSilo.LowNtuWarning(enabled: Boolean) =>
|
||||||
resourceSilo.LowNtuWarningOn = enabled
|
resourceSilo.LowNtuWarningOn = enabled
|
||||||
log.trace(s"LowNtuWarning: Silo ${resourceSilo.GUID} low ntu warning set to ${enabled}")
|
log.trace(s"LowNtuWarning: Silo ${resourceSilo.GUID} low ntu warning set to $enabled")
|
||||||
avatarService ! AvatarServiceMessage(resourceSilo.Owner.asInstanceOf[Building].Zone.Id, AvatarAction.PlanetsideAttribute(PlanetSideGUID(resourceSilo.Owner.asInstanceOf[Building].ModelId), 47, if(resourceSilo.LowNtuWarningOn) 1 else 0))
|
avatarService ! AvatarServiceMessage(resourceSilo.Owner.asInstanceOf[Building].Zone.Id, AvatarAction.PlanetsideAttribute(PlanetSideGUID(resourceSilo.Owner.asInstanceOf[Building].ModelId), 47, if(resourceSilo.LowNtuWarningOn) 1 else 0))
|
||||||
|
|
||||||
case ResourceSilo.UpdateChargeLevel(amount: Int) =>
|
case ResourceSilo.UpdateChargeLevel(amount: Int) =>
|
||||||
|
|
@ -55,10 +55,10 @@ class ResourceSiloControl(resourceSilo : ResourceSilo) extends Actor with Factio
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val ntuBarLevel = scala.math.round((resourceSilo.ChargeLevel.toFloat / resourceSilo.MaximumCharge.toFloat) * 10).toInt
|
val ntuBarLevel = scala.math.round((resourceSilo.ChargeLevel.toFloat / resourceSilo.MaximumCharge.toFloat) * 10)
|
||||||
// Only send updated capacitor display value to all clients if it has actually changed
|
// Only send updated capacitor display value to all clients if it has actually changed
|
||||||
if(resourceSilo.CapacitorDisplay != ntuBarLevel) {
|
if(resourceSilo.CapacitorDisplay != ntuBarLevel) {
|
||||||
log.trace(s"Silo ${resourceSilo.GUID} NTU bar level has changed from ${resourceSilo.CapacitorDisplay} to ${ntuBarLevel}")
|
log.trace(s"Silo ${resourceSilo.GUID} NTU bar level has changed from ${resourceSilo.CapacitorDisplay} to $ntuBarLevel")
|
||||||
resourceSilo.CapacitorDisplay = ntuBarLevel
|
resourceSilo.CapacitorDisplay = ntuBarLevel
|
||||||
resourceSilo.Owner.Actor ! Building.SendMapUpdate(all_clients = true)
|
resourceSilo.Owner.Actor ! Building.SendMapUpdate(all_clients = true)
|
||||||
avatarService ! AvatarServiceMessage(resourceSilo.Owner.asInstanceOf[Building].Zone.Id, AvatarAction.PlanetsideAttribute(resourceSilo.GUID, 45, resourceSilo.CapacitorDisplay))
|
avatarService ! AvatarServiceMessage(resourceSilo.Owner.asInstanceOf[Building].Zone.Id, AvatarAction.PlanetsideAttribute(resourceSilo.GUID, 45, resourceSilo.CapacitorDisplay))
|
||||||
|
|
|
||||||
|
|
@ -366,12 +366,12 @@ object EquipmentTerminalDefinition {
|
||||||
(0 until tool.MaxAmmoSlot).foreach(index => {
|
(0 until tool.MaxAmmoSlot).foreach(index => {
|
||||||
val slot = tool.AmmoSlots(index)
|
val slot = tool.AmmoSlots(index)
|
||||||
slot.AmmoTypeIndex += obj.ammo(index).ammoIndex
|
slot.AmmoTypeIndex += obj.ammo(index).ammoIndex
|
||||||
slot.Box = MakeAmmoBox(ammo(index), Some(obj.ammo(index).ammo.capacity))
|
slot.Box = MakeAmmoBox(ammo(index), Some(slot.Definition.Magazine)) //Some(obj.ammo(index).ammo.capacity)
|
||||||
})
|
})
|
||||||
tool
|
tool
|
||||||
|
|
||||||
case obj : ShorthandAmmoBox =>
|
case obj : ShorthandAmmoBox =>
|
||||||
MakeAmmoBox(obj.definition, Some(obj.capacity))
|
MakeAmmoBox(obj.definition) //Some(obj.capacity)
|
||||||
|
|
||||||
case obj : ShorthandConstructionItem =>
|
case obj : ShorthandConstructionItem =>
|
||||||
MakeConstructionItem(obj.definition)
|
MakeConstructionItem(obj.definition)
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,19 @@ package net.psforever.objects.serverobject.turret
|
||||||
|
|
||||||
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 net.psforever.objects.vital.{DamageResistanceModel, StandardResistanceProfile, Vitality}
|
||||||
|
|
||||||
class FacilityTurret(tDef : TurretDefinition) extends Amenity
|
class FacilityTurret(tDef : TurretDefinition) extends Amenity
|
||||||
with WeaponTurret {
|
with WeaponTurret
|
||||||
|
with Vitality
|
||||||
|
with StandardResistanceProfile {
|
||||||
/** some turrets can be updated; they all start without updates */
|
/** some turrets can be updated; they all start without updates */
|
||||||
private var upgradePath : TurretUpgrade.Value = TurretUpgrade.None
|
private var upgradePath : TurretUpgrade.Value = TurretUpgrade.None
|
||||||
|
|
||||||
WeaponTurret.LoadDefinition(this)
|
WeaponTurret.LoadDefinition(this)
|
||||||
|
|
||||||
|
override def Health_=(toHealth : Int) = super.Health_=(math.max(1, toHealth)) //TODO properly handle destroyed facility turrets
|
||||||
|
|
||||||
def MaxHealth : Int = Definition.MaxHealth
|
def MaxHealth : Int = Definition.MaxHealth
|
||||||
|
|
||||||
def MountPoints : Map[Int, Int] = Definition.MountPoints.toMap
|
def MountPoints : Map[Int, Int] = Definition.MountPoints.toMap
|
||||||
|
|
@ -28,6 +33,8 @@ class FacilityTurret(tDef : TurretDefinition) extends Amenity
|
||||||
Upgrade
|
Upgrade
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def DamageModel = Definition.asInstanceOf[DamageResistanceModel]
|
||||||
|
|
||||||
def Definition : TurretDefinition = tDef
|
def Definition : TurretDefinition = tDef
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ package net.psforever.objects.serverobject.turret
|
||||||
import akka.actor.Actor
|
import akka.actor.Actor
|
||||||
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
|
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
|
||||||
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
|
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
|
||||||
|
import net.psforever.objects.vital.Vitality
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An `Actor` that handles messages being dispatched to a specific `MannedTurret`.<br>
|
* An `Actor` that handles messages being dispatched to a specific `MannedTurret`.<br>
|
||||||
|
|
@ -38,6 +39,18 @@ class FacilityTurretControl(turret : FacilityTurret) extends Actor
|
||||||
sender ! Mountable.MountMessages(user, Mountable.CanNotMount(turret, seat_num))
|
sender ! Mountable.MountMessages(user, Mountable.CanNotMount(turret, seat_num))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Vitality.Damage(damage_func) =>
|
||||||
|
if(turret.Health > 0) {
|
||||||
|
val originalHealth = turret.Health
|
||||||
|
damage_func(turret)
|
||||||
|
val health = turret.Health
|
||||||
|
val damageToHealth = originalHealth - health
|
||||||
|
val name = turret.Actor.toString
|
||||||
|
val slashPoint = name.lastIndexOf("/")
|
||||||
|
org.log4s.getLogger("DamageResolution").info(s"${name.substring(slashPoint+1, name.length-1)}: BEFORE=$originalHealth, AFTER=$health, CHANGE=$damageToHealth")
|
||||||
|
sender ! Vitality.DamageResolution(turret)
|
||||||
|
}
|
||||||
|
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ package net.psforever.objects.serverobject.turret
|
||||||
|
|
||||||
import net.psforever.objects.definition.{ObjectDefinition, ToolDefinition}
|
import net.psforever.objects.definition.{ObjectDefinition, ToolDefinition}
|
||||||
import net.psforever.objects.vehicles.Turrets
|
import net.psforever.objects.vehicles.Turrets
|
||||||
|
import net.psforever.objects.vital.{DamageResistanceModel, StandardResolutions, StandardVehicleDamage, StandardVehicleResistance}
|
||||||
|
import net.psforever.objects.vital.resistance.ResistanceProfileMutators
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
|
||||||
|
|
@ -10,7 +12,9 @@ import scala.collection.mutable
|
||||||
* The definition for any `MannedTurret`.
|
* The definition for any `MannedTurret`.
|
||||||
* @param objectId the object's identifier number
|
* @param objectId the object's identifier number
|
||||||
*/
|
*/
|
||||||
class TurretDefinition(private val objectId : Int) extends ObjectDefinition(objectId) {
|
class TurretDefinition(private val objectId : Int) extends ObjectDefinition(objectId)
|
||||||
|
with ResistanceProfileMutators
|
||||||
|
with DamageResistanceModel {
|
||||||
Turrets(objectId) //let throw NoSuchElementException
|
Turrets(objectId) //let throw NoSuchElementException
|
||||||
|
|
||||||
private var maxHealth : Int = 100
|
private var maxHealth : Int = 100
|
||||||
|
|
@ -25,6 +29,9 @@ class TurretDefinition(private val objectId : Int) extends ObjectDefinition(obje
|
||||||
/** creates internal ammunition reserves that can not become depleted
|
/** creates internal ammunition reserves that can not become depleted
|
||||||
* see `MannedTurret.TurretAmmoBox` for details */
|
* see `MannedTurret.TurretAmmoBox` for details */
|
||||||
private var hasReserveAmmunition : Boolean = false
|
private var hasReserveAmmunition : Boolean = false
|
||||||
|
Damage = StandardVehicleDamage
|
||||||
|
Resistance = StandardVehicleResistance
|
||||||
|
Model = StandardResolutions.FacilityTurrets
|
||||||
|
|
||||||
def MaxHealth : Int = maxHealth
|
def MaxHealth : Int = maxHealth
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,16 @@ class VehicleControl(vehicle : Vehicle) extends Actor
|
||||||
|
|
||||||
case Vitality.Damage(damage_func) =>
|
case Vitality.Damage(damage_func) =>
|
||||||
if(vehicle.Health > 0) {
|
if(vehicle.Health > 0) {
|
||||||
|
val originalHealth = vehicle.Health
|
||||||
|
val originalShields = vehicle.Shields
|
||||||
damage_func(vehicle)
|
damage_func(vehicle)
|
||||||
|
val health = vehicle.Health
|
||||||
|
val shields = vehicle.Shields
|
||||||
|
val damageToHealth = originalHealth - health
|
||||||
|
val damageToShields = originalShields - shields
|
||||||
|
val name = vehicle.Actor.toString
|
||||||
|
val slashPoint = name.lastIndexOf("/")
|
||||||
|
org.log4s.getLogger("DamageResolution").info(s"${name.substring(slashPoint+1, name.length-1)}: BEFORE=$originalHealth/$originalShields, AFTER=$health/$shields, CHANGE=$damageToHealth/$damageToShields")
|
||||||
sender ! Vitality.DamageResolution(vehicle)
|
sender ! Vitality.DamageResolution(vehicle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
// Copyright (c) 2017 PSForever
|
||||||
|
package net.psforever.objects.vital
|
||||||
|
|
||||||
|
import net.psforever.objects.vital.damage.DamageProfile
|
||||||
|
|
||||||
|
trait StandardDamageProfile extends DamageProfile {
|
||||||
|
private var damage0 : Int = 0
|
||||||
|
private var damage1 : Option[Int] = None
|
||||||
|
private var damage2 : Option[Int] = None
|
||||||
|
private var damage3 : Option[Int] = None
|
||||||
|
private var damage4 : Option[Int] = None
|
||||||
|
|
||||||
|
def Damage0 : Int = damage0
|
||||||
|
|
||||||
|
def Damage0_=(damage : Int) : Int = {
|
||||||
|
damage0 = damage
|
||||||
|
damage0
|
||||||
|
}
|
||||||
|
|
||||||
|
def Damage0_=(damage : Option[Int]) : Int = {
|
||||||
|
damage0 = damage match {
|
||||||
|
case Some(value) => value
|
||||||
|
case None => 0 //can not be set to None
|
||||||
|
}
|
||||||
|
Damage0
|
||||||
|
}
|
||||||
|
|
||||||
|
def Damage1 : Int = damage1.getOrElse(Damage0)
|
||||||
|
|
||||||
|
def Damage1_=(damage : Int) : Int = Damage1_=(Some(damage))
|
||||||
|
|
||||||
|
def Damage1_=(damage : Option[Int]) : Int = {
|
||||||
|
this.damage1 = damage
|
||||||
|
Damage1
|
||||||
|
}
|
||||||
|
|
||||||
|
def Damage2 : Int = damage2.getOrElse(Damage1)
|
||||||
|
|
||||||
|
def Damage2_=(damage : Int) : Int = Damage2_=(Some(damage))
|
||||||
|
|
||||||
|
def Damage2_=(damage : Option[Int]) : Int = {
|
||||||
|
this.damage2 = damage
|
||||||
|
Damage2
|
||||||
|
}
|
||||||
|
|
||||||
|
def Damage3 : Int = damage3.getOrElse(Damage2)
|
||||||
|
|
||||||
|
def Damage3_=(damage : Int) : Int = Damage3_=(Some(damage))
|
||||||
|
|
||||||
|
def Damage3_=(damage : Option[Int]) : Int = {
|
||||||
|
this.damage3 = damage
|
||||||
|
Damage3
|
||||||
|
}
|
||||||
|
|
||||||
|
def Damage4 : Int = damage4.getOrElse(Damage3)
|
||||||
|
|
||||||
|
def Damage4_=(damage : Int) : Int = Damage4_=(Some(damage))
|
||||||
|
|
||||||
|
def Damage4_=(damage : Option[Int]) : Int = {
|
||||||
|
this.damage4 = damage
|
||||||
|
Damage4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.vital
|
package net.psforever.objects.vital
|
||||||
|
|
||||||
import net.psforever.objects.ballistics.ResolvedProjectile
|
|
||||||
import net.psforever.objects.vital.damage._
|
import net.psforever.objects.vital.damage._
|
||||||
import net.psforever.objects.vital.damage.DamageCalculations._
|
import net.psforever.objects.vital.damage.DamageCalculations._
|
||||||
|
|
||||||
|
|
@ -66,21 +65,35 @@ object AircraftSplashDamage extends DamageCalculations(
|
||||||
DistanceFromExplosionToTarget
|
DistanceFromExplosionToTarget
|
||||||
)
|
)
|
||||||
|
|
||||||
object InfantryLashDamage extends NoDamageBase {
|
object InfantrySplashDamageDirect extends DamageCalculations(
|
||||||
override def Calculate(data : ResolvedProjectile) : Int = (InfantryHitDamage.Calculate(data) * 0.2f).toInt
|
SplashDamageWithRadialDegrade,
|
||||||
}
|
DamageWithModifiers(DamageAgainstAircraft),
|
||||||
|
NoDistance
|
||||||
|
)
|
||||||
|
|
||||||
object MaxLashDamage extends NoDamageBase {
|
object InfantryLashDamage extends DamageCalculations(
|
||||||
override def Calculate(data : ResolvedProjectile) : Int = (MaxHitDamage.Calculate(data) * 0.2f).toInt
|
LashDamage,
|
||||||
}
|
DamageWithModifiers(DamageAgainstExoSuit),
|
||||||
|
DistanceBetweenTargetandSource
|
||||||
|
)
|
||||||
|
|
||||||
object VehicleLashDamage extends NoDamageBase {
|
object MaxLashDamage extends DamageCalculations(
|
||||||
override def Calculate(data : ResolvedProjectile) : Int = (VehicleHitDamage.Calculate(data) * 0.2f).toInt
|
LashDamage,
|
||||||
}
|
DamageWithModifiers(DamageAgainstMaxSuit),
|
||||||
|
DistanceBetweenTargetandSource
|
||||||
|
)
|
||||||
|
|
||||||
object AircraftLashDamage extends NoDamageBase {
|
object VehicleLashDamage extends DamageCalculations(
|
||||||
override def Calculate(data : ResolvedProjectile) : Int = (AircraftHitDamage.Calculate(data) * 0.2f).toInt
|
LashDamage,
|
||||||
}
|
DamageWithModifiers(DamageAgainstVehicle),
|
||||||
|
DistanceBetweenTargetandSource
|
||||||
|
)
|
||||||
|
|
||||||
|
object AircraftLashDamage extends DamageCalculations(
|
||||||
|
LashDamage,
|
||||||
|
DamageWithModifiers(DamageAgainstAircraft),
|
||||||
|
DistanceBetweenTargetandSource
|
||||||
|
)
|
||||||
|
|
||||||
object NoDamageSelection extends DamageSelection {
|
object NoDamageSelection extends DamageSelection {
|
||||||
def Direct = None
|
def Direct = None
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
package net.psforever.objects.vital
|
package net.psforever.objects.vital
|
||||||
|
|
||||||
import net.psforever.objects.PlanetSideGameObject
|
import net.psforever.objects.PlanetSideGameObject
|
||||||
|
import net.psforever.objects.vital.damage.DamageProfile
|
||||||
import net.psforever.objects.vital.resistance.ResistanceProfile
|
import net.psforever.objects.vital.resistance.ResistanceProfile
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -16,6 +17,8 @@ trait StandardResistanceProfile extends ResistanceProfile {
|
||||||
assert(Definition.isInstanceOf[ResistanceProfile], s"$this object definition must extend ResistanceProfile")
|
assert(Definition.isInstanceOf[ResistanceProfile], s"$this object definition must extend ResistanceProfile")
|
||||||
private val resistDef = Definition.asInstanceOf[ResistanceProfile] //cast only once
|
private val resistDef = Definition.asInstanceOf[ResistanceProfile] //cast only once
|
||||||
|
|
||||||
|
def Subtract : DamageProfile = resistDef.Subtract
|
||||||
|
|
||||||
def ResistanceDirectHit : Int = resistDef.ResistanceDirectHit
|
def ResistanceDirectHit : Int = resistDef.ResistanceDirectHit
|
||||||
|
|
||||||
def ResistanceSplash : Int = resistDef.ResistanceDirectHit
|
def ResistanceSplash : Int = resistDef.ResistanceDirectHit
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ object InfantrySplashResistance extends ResistanceCalculations[PlayerSource](
|
||||||
|
|
||||||
object InfantryLashResistance extends ResistanceCalculations[PlayerSource](
|
object InfantryLashResistance extends ResistanceCalculations[PlayerSource](
|
||||||
ResistanceCalculations.ValidInfantryTarget,
|
ResistanceCalculations.ValidInfantryTarget,
|
||||||
ResistanceCalculations.NoResistExtractor
|
ResistanceCalculations.ExoSuitDirectExtractor
|
||||||
)
|
)
|
||||||
|
|
||||||
object InfantryAggravatedResistance extends ResistanceCalculations[PlayerSource](
|
object InfantryAggravatedResistance extends ResistanceCalculations[PlayerSource](
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,9 @@ object VehicleResolutions extends DamageResistCalculations(
|
||||||
ResolutionCalculations.VehicleApplication
|
ResolutionCalculations.VehicleApplication
|
||||||
)
|
)
|
||||||
|
|
||||||
object SimpleDeployableResolutions extends DamageResistCalculations(
|
object SimpleResolutions extends DamageResistCalculations(
|
||||||
ResolutionCalculations.VehicleDamageAfterResist,
|
ResolutionCalculations.VehicleDamageAfterResist,
|
||||||
ResolutionCalculations.SimpleDeployableApplication
|
ResolutionCalculations.SimpleApplication
|
||||||
)
|
)
|
||||||
|
|
||||||
object ComplexDeployableResolutions extends DamageResistCalculations(
|
object ComplexDeployableResolutions extends DamageResistCalculations(
|
||||||
|
|
@ -38,6 +38,7 @@ object StandardResolutions extends ResolutionSelection {
|
||||||
def Max : ResolutionCalculations.Form = MaxResolutions.Calculate
|
def Max : ResolutionCalculations.Form = MaxResolutions.Calculate
|
||||||
def Vehicle : ResolutionCalculations.Form = VehicleResolutions.Calculate
|
def Vehicle : ResolutionCalculations.Form = VehicleResolutions.Calculate
|
||||||
def Aircraft : ResolutionCalculations.Form = VehicleResolutions.Calculate
|
def Aircraft : ResolutionCalculations.Form = VehicleResolutions.Calculate
|
||||||
def SimpleDeployables : ResolutionCalculations.Form = SimpleDeployableResolutions.Calculate
|
def SimpleDeployables : ResolutionCalculations.Form = SimpleResolutions.Calculate
|
||||||
def ComplexDeployables : ResolutionCalculations.Form = ComplexDeployableResolutions.Calculate
|
def ComplexDeployables : ResolutionCalculations.Form = ComplexDeployableResolutions.Calculate
|
||||||
|
def FacilityTurrets : ResolutionCalculations.Form = SimpleResolutions.Calculate
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,16 @@ abstract class DamageCalculations(damages : DamagesType,
|
||||||
*/
|
*/
|
||||||
def Calculate(data : ResolvedProjectile) : Int = {
|
def Calculate(data : ResolvedProjectile) : Int = {
|
||||||
val projectile = data.projectile
|
val projectile = data.projectile
|
||||||
|
val profile = projectile.profile
|
||||||
|
val modifiers = if(profile.UseDamage1Subtract) {
|
||||||
|
List(projectile.fire_mode.Modifiers, data.target.Modifiers.Subtract)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
List(projectile.fire_mode.Modifiers)
|
||||||
|
}
|
||||||
damages(
|
damages(
|
||||||
projectile,
|
projectile,
|
||||||
extractor(projectile.profile, List(projectile.fire_mode.Modifiers)),
|
extractor(profile, modifiers),
|
||||||
distanceFunc(data)
|
distanceFunc(data)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -70,6 +77,17 @@ object DamageCalculations {
|
||||||
//damage calculation functions
|
//damage calculation functions
|
||||||
def NoDamage(projectile : Projectile, rawDamage : Int, distance : Float) : Int = 0
|
def NoDamage(projectile : Projectile, rawDamage : Int, distance : Float) : Int = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use an unmodified damage value.
|
||||||
|
* @param projectile information about the weapon discharge (itself);
|
||||||
|
* unused
|
||||||
|
* @param rawDamage the accumulated amount of damage
|
||||||
|
* @param distance how far the source was from the target;
|
||||||
|
* unused
|
||||||
|
* @return the rawDamage value
|
||||||
|
*/
|
||||||
|
def SameHit(projectile : Projectile, rawDamage : Int, distance : Float) : Int = rawDamage
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modify the base damage based on the degrade distance of the projectile type
|
* Modify the base damage based on the degrade distance of the projectile type
|
||||||
* and its maximum effective distance.
|
* and its maximum effective distance.
|
||||||
|
|
@ -107,7 +125,25 @@ object DamageCalculations {
|
||||||
if(distance <= radius) {
|
if(distance <= radius) {
|
||||||
val base : Float = projectile.profile.DamageAtEdge
|
val base : Float = projectile.profile.DamageAtEdge
|
||||||
val degrade : Float = (1 - base) * ((radius - distance)/radius) + base
|
val degrade : Float = (1 - base) * ((radius - distance)/radius) + base
|
||||||
rawDamage + (rawDamage * degrade).toInt
|
(rawDamage * degrade).toInt
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate a flat lash damage value.
|
||||||
|
* The target needs to be more than five meters away.
|
||||||
|
* @param projectile information about the weapon discharge (itself)
|
||||||
|
* @param rawDamage the accumulated amount of damage
|
||||||
|
* @param distance how far the source was from the target
|
||||||
|
* @return the modified damage value
|
||||||
|
*/
|
||||||
|
def LashDamage(projectile : Projectile, rawDamage : Int, distance : Float) : Int = {
|
||||||
|
val profile = projectile.profile
|
||||||
|
if(distance > 5 || distance <= profile.DistanceMax) {
|
||||||
|
(rawDamage * 0.2f) toInt
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
0
|
0
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.vital.resistance
|
package net.psforever.objects.vital.resistance
|
||||||
|
|
||||||
import net.psforever.objects.vital.DamageType
|
import net.psforever.objects.vital.damage.DamageProfile
|
||||||
|
import net.psforever.objects.vital.{DamageType, StandardDamageProfile}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The different values for four common methods of modifying incoming damage.
|
* The different values for four common methods of modifying incoming damage.
|
||||||
|
|
@ -9,6 +10,8 @@ import net.psforever.objects.vital.DamageType
|
||||||
* This is for defining pure accessor functions.
|
* This is for defining pure accessor functions.
|
||||||
*/
|
*/
|
||||||
trait ResistanceProfile {
|
trait ResistanceProfile {
|
||||||
|
def Subtract : DamageProfile
|
||||||
|
|
||||||
def ResistanceDirectHit : Int
|
def ResistanceDirectHit : Int
|
||||||
|
|
||||||
def ResistanceSplash : Int
|
def ResistanceSplash : Int
|
||||||
|
|
@ -34,11 +37,25 @@ trait ResistanceProfile {
|
||||||
* This is for defining both accessor and mutator functions.
|
* This is for defining both accessor and mutator functions.
|
||||||
*/
|
*/
|
||||||
trait ResistanceProfileMutators extends ResistanceProfile {
|
trait ResistanceProfileMutators extends ResistanceProfile {
|
||||||
|
private var subtract : DamageProfile = new StandardDamageProfile {
|
||||||
|
//subtract numbers are always negative modifiers
|
||||||
|
override def Damage0_=(damage : Int) : Int = super.Damage0_=( if(damage < 1) damage else -damage)
|
||||||
|
|
||||||
|
override def Damage1_=(damage : Int) : Int = super.Damage1_=( if(damage < 1) damage else -damage)
|
||||||
|
|
||||||
|
override def Damage2_=(damage : Int) : Int = super.Damage2_=( if(damage < 1) damage else -damage)
|
||||||
|
|
||||||
|
override def Damage3_=(damage : Int) : Int = super.Damage3_=( if(damage < 1) damage else -damage)
|
||||||
|
|
||||||
|
override def Damage4_=(damage : Int) : Int = super.Damage4_=( if(damage < 1) damage else -damage)
|
||||||
|
}
|
||||||
private var resistanceDirectHit : Int = 0
|
private var resistanceDirectHit : Int = 0
|
||||||
private var resistanceSplash : Int = 0
|
private var resistanceSplash : Int = 0
|
||||||
private var resistanceAggravated : Int = 0
|
private var resistanceAggravated : Int = 0
|
||||||
private var radiationShielding : Float = 0f
|
private var radiationShielding : Float = 0f
|
||||||
|
|
||||||
|
def Subtract : DamageProfile = subtract
|
||||||
|
|
||||||
def ResistanceDirectHit : Int = resistanceDirectHit
|
def ResistanceDirectHit : Int = resistanceDirectHit
|
||||||
|
|
||||||
def ResistanceDirectHit_=(resist : Int) : Int = {
|
def ResistanceDirectHit_=(resist : Int) : Int = {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ package net.psforever.objects.vital.resolution
|
||||||
import net.psforever.objects.{Player, TurretDeployable, Vehicle}
|
import net.psforever.objects.{Player, TurretDeployable, Vehicle}
|
||||||
import net.psforever.objects.ballistics.{PlayerSource, ResolvedProjectile}
|
import net.psforever.objects.ballistics.{PlayerSource, ResolvedProjectile}
|
||||||
import net.psforever.objects.ce.{ComplexDeployable, SimpleDeployable}
|
import net.psforever.objects.ce.{ComplexDeployable, SimpleDeployable}
|
||||||
|
import net.psforever.objects.serverobject.turret.FacilityTurret
|
||||||
import net.psforever.objects.vital.projectile.ProjectileCalculations
|
import net.psforever.objects.vital.projectile.ProjectileCalculations
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -159,12 +160,17 @@ object ResolutionCalculations {
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
def SimpleDeployableApplication(damage : Int, data : ResolvedProjectile)(target : Any) : Unit = target match {
|
def SimpleApplication(damage : Int, data : ResolvedProjectile)(target : Any) : Unit = target match {
|
||||||
case ce : SimpleDeployable =>
|
case ce : SimpleDeployable =>
|
||||||
if(ce.Health > 0) {
|
if(ce.Health > 0) {
|
||||||
ce.Health -= damage
|
ce.Health -= damage
|
||||||
ce.History(data)
|
ce.History(data)
|
||||||
}
|
}
|
||||||
|
case turret : FacilityTurret =>
|
||||||
|
if(turret.Health > 0) {
|
||||||
|
turret.Health -= damage
|
||||||
|
turret.History(data)
|
||||||
|
}
|
||||||
case _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import net.psforever.objects.guid.actor.UniqueNumberSystem
|
||||||
import net.psforever.objects.guid.selector.RandomSelector
|
import net.psforever.objects.guid.selector.RandomSelector
|
||||||
import net.psforever.objects.guid.source.LimitedNumberSource
|
import net.psforever.objects.guid.source.LimitedNumberSource
|
||||||
import net.psforever.objects.inventory.Container
|
import net.psforever.objects.inventory.Container
|
||||||
|
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
|
||||||
import net.psforever.objects.serverobject.structures.{Amenity, Building}
|
import net.psforever.objects.serverobject.structures.{Amenity, Building}
|
||||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||||
import net.psforever.objects.serverobject.turret.FacilityTurret
|
import net.psforever.objects.serverobject.turret.FacilityTurret
|
||||||
|
|
@ -358,6 +359,13 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
||||||
case (None, _) | (_, None) => ; //let ZoneActor's sanity check catch this error
|
case (None, _) | (_, None) => ; //let ZoneActor's sanity check catch this error
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
//ntu management (eventually move to a generic building startup function)
|
||||||
|
buildings.values
|
||||||
|
.flatMap(_.Amenities.filter(_.Definition == GlobalDefinitions.resource_silo))
|
||||||
|
.collect {
|
||||||
|
case silo : ResourceSilo =>
|
||||||
|
silo.Actor ! "startup"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def CreateSpawnGroups() : Unit = {
|
private def CreateSpawnGroups() : Unit = {
|
||||||
|
|
|
||||||
|
|
@ -2,33 +2,45 @@
|
||||||
package net.psforever.packet.game
|
package net.psforever.packet.game
|
||||||
|
|
||||||
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
||||||
import net.psforever.types.Vector3
|
import net.psforever.types.{SpawnGroup, Vector3}
|
||||||
import scodec.Codec
|
import scodec.Codec
|
||||||
import scodec.codecs._
|
import scodec.codecs._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The purpose of the `BindPlayerMessage` packet.<br>
|
||||||
|
* <br>
|
||||||
|
* `Bind` and `Unbind` are generally manual actions performed by the player.
|
||||||
|
* `Available` is applied to automatic Advanced Mobile Spawn points and other "Bound" points at the time of redeployment.
|
||||||
|
* `Lost` and `Unavailable` remove the status of being bound and have slightly different connotations.
|
||||||
|
* Each generates a different a events chat message if logging it turned on.
|
||||||
|
*/
|
||||||
|
object BindStatus extends Enumeration(1) {
|
||||||
|
type Type = Value
|
||||||
|
|
||||||
|
val
|
||||||
|
Bind,
|
||||||
|
Unbind,
|
||||||
|
Lost,
|
||||||
|
Available,
|
||||||
|
Unavailable
|
||||||
|
= Value
|
||||||
|
|
||||||
|
implicit val codec = PacketHelpers.createEnumerationCodec(this, uint8)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A packet dispatched to maintain a manually-set respawn location.<br>
|
* A packet dispatched to maintain a manually-set respawn location.<br>
|
||||||
* <br>
|
* <br>
|
||||||
* The packet establishes the player's ability to spawn in an arbitrary location that is not a normal local option.
|
* The packet establishes the player's ability to spawn in an arbitrary location that is not a normal local option.
|
||||||
* This process is called "binding."
|
* This process is called "binding one's matrix."
|
||||||
* In addition to player establishing the binding, the packet updates as conditions of the respawn location changes.<br>
|
* In addition to player establishing the binding, the packet updates as conditions of the respawn location changes.<br>
|
||||||
* <br>
|
* <br>
|
||||||
* If `logging` is turned on, packets will display different messages depending on context.
|
* If `logging` is turned on, packets will display different messages depending on context.
|
||||||
|
* The bind descriptor will be used to flavor the events chat message.
|
||||||
* As long as the event is marked to be logged, when the packet is received, a message is displayed in the events window.
|
* As long as the event is marked to be logged, when the packet is received, a message is displayed in the events window.
|
||||||
* If the logged action is applicable, the matrixing sound effect will be played too.
|
* If the logged action is applicable, the matrixing sound effect will be played too.
|
||||||
* Not displaying events is occasionally warranted for aesthetics.
|
* Not displaying events is occasionally warranted for aesthetics.
|
||||||
* The game will always note if this is your first time binding.<br>
|
* The game will always note if this is your first time binding regardless of the state of this flag.<br>
|
||||||
* <br>
|
|
||||||
* One common occurrence of this packet is during zone transport.
|
|
||||||
* Specifically, a packet is dispatched after unloading the current zone but before beginning loading in the new zone.
|
|
||||||
* It is preceded by all of the `ObjectDeleteMessage` packets and itself precedes the `LoadMapMessage` packet.<br>
|
|
||||||
* <br>
|
|
||||||
* Actions:<br>
|
|
||||||
* `1` - bound to respawn point<br>
|
|
||||||
* `2` - general unbound / unbinding from respawn point<br>
|
|
||||||
* `3` - respawn point lost<br>
|
|
||||||
* `4` - bound spawn point became available<br>
|
|
||||||
* `5` - bound spawn point became unavailable (different from 3)<br>
|
|
||||||
* <br>
|
* <br>
|
||||||
* Bind Descriptors:<br>
|
* Bind Descriptors:<br>
|
||||||
* `@amp_station`<br>
|
* `@amp_station`<br>
|
||||||
|
|
@ -41,22 +53,28 @@ import scodec.codecs._
|
||||||
* Exploration:<br>
|
* Exploration:<br>
|
||||||
* Find other bind descriptors.
|
* Find other bind descriptors.
|
||||||
* @param action the purpose of the packet
|
* @param action the purpose of the packet
|
||||||
* @param bindDesc a description of the respawn binding point
|
* @param bind_desc a text description of the respawn binding point
|
||||||
* @param unk1 na; usually set `true` if there is more data in the packet ...
|
* @param unk1 na;
|
||||||
|
* usually set `true` if there is more data in the packet ...
|
||||||
* @param logging true, to report on bind point change visible in the events window;
|
* @param logging true, to report on bind point change visible in the events window;
|
||||||
* false, to render spawn change silent;
|
* false, to render spawn change silent;
|
||||||
* a first time event notification will always show
|
* some first time notifications will always display regardless of this flag
|
||||||
* @param unk2 na; if a value, it is usually 40 (hex`28`)
|
* @param spawn_group the kind of spawn request that will be made;
|
||||||
* @param unk3 na
|
* affects the type of icon displayed;
|
||||||
|
* will coincide with the value of `unk2` in `SpawnRequestMessage` when the spawn option is selected
|
||||||
|
* @param zone_number the number of the zone in which to display this spawn option;
|
||||||
|
* if `zone_number` is not the current zone, and the action is positive,
|
||||||
|
* a small map of the alternate zone with selectable spawn point will become visible
|
||||||
* @param unk4 na
|
* @param unk4 na
|
||||||
* @param pos a position associated with the binding
|
* @param pos coordinates for any displayed deployment map icon;
|
||||||
|
* `x` and `y` determine the position
|
||||||
*/
|
*/
|
||||||
final case class BindPlayerMessage(action : Int,
|
final case class BindPlayerMessage(action : BindStatus.Value,
|
||||||
bindDesc : String,
|
bind_desc : String,
|
||||||
unk1 : Boolean,
|
unk1 : Boolean,
|
||||||
logging : Boolean,
|
logging : Boolean,
|
||||||
unk2 : Int,
|
spawn_group : SpawnGroup.Value,
|
||||||
unk3 : Long,
|
zone_number : Long,
|
||||||
unk4 : Long,
|
unk4 : Long,
|
||||||
pos : Vector3)
|
pos : Vector3)
|
||||||
extends PlanetSideGamePacket {
|
extends PlanetSideGamePacket {
|
||||||
|
|
@ -68,20 +86,18 @@ final case class BindPlayerMessage(action : Int,
|
||||||
object BindPlayerMessage extends Marshallable[BindPlayerMessage] {
|
object BindPlayerMessage extends Marshallable[BindPlayerMessage] {
|
||||||
/**
|
/**
|
||||||
* A common variant of this packet.
|
* A common variant of this packet.
|
||||||
* `16028004000000000000000000000000000000`
|
|
||||||
*/
|
*/
|
||||||
val STANDARD = BindPlayerMessage(2, "", false, false, 2, 0, 0, Vector3(0, 0, 0))
|
val Standard = BindPlayerMessage(BindStatus.Unbind, "", false, false, SpawnGroup.BoundAMS, 0, 0, Vector3.Zero)
|
||||||
|
|
||||||
|
private val spawnGroupCodec = PacketHelpers.createEnumerationCodec(SpawnGroup, uint4)
|
||||||
|
|
||||||
//TODO: there are two ignore(1) in this packet; are they in a good position?
|
|
||||||
implicit val codec : Codec[BindPlayerMessage] = (
|
implicit val codec : Codec[BindPlayerMessage] = (
|
||||||
("action" | uint8L) ::
|
("action" | BindStatus.codec) ::
|
||||||
("bindDesc" | PacketHelpers.encodedString) ::
|
("bind_desc" | PacketHelpers.encodedString) ::
|
||||||
("unk1" | bool) ::
|
("unk1" | bool) ::
|
||||||
("logging" | bool) ::
|
("logging" | bool) ::
|
||||||
ignore(1) ::
|
("spawn_group" | spawnGroupCodec) ::
|
||||||
("unk2" | uint4L) ::
|
("zone_number" | uint32L) ::
|
||||||
ignore(1) ::
|
|
||||||
("unk3" | uint32L) ::
|
|
||||||
("unk4" | uint32L) ::
|
("unk4" | uint32L) ::
|
||||||
("pos" | Vector3.codec_pos)
|
("pos" | Vector3.codec_pos)
|
||||||
).as[BindPlayerMessage]
|
).as[BindPlayerMessage]
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.packet.game
|
package net.psforever.packet.game
|
||||||
|
|
||||||
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
|
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
||||||
|
import net.psforever.types.SpawnGroup
|
||||||
import scodec.Codec
|
import scodec.Codec
|
||||||
import scodec.codecs._
|
import scodec.codecs._
|
||||||
|
|
||||||
|
|
@ -9,20 +10,16 @@ import scodec.codecs._
|
||||||
* na
|
* na
|
||||||
* @param unk1 when defined, na;
|
* @param unk1 when defined, na;
|
||||||
* non-zero when selecting the sanctuary option from a non-sanctuary continent deployment map
|
* non-zero when selecting the sanctuary option from a non-sanctuary continent deployment map
|
||||||
* @param unk2 when defined, indicates type of spawn point by destination;
|
* @param spawn_type the type of spawn point destination
|
||||||
* 0 is nothing;
|
|
||||||
* 2 is ams;
|
|
||||||
* 6 is towers;
|
|
||||||
* 7 is facilities
|
|
||||||
* @param unk3 na
|
* @param unk3 na
|
||||||
* @param unk4 na
|
* @param unk4 na
|
||||||
* @param unk5 when defined, the continent number
|
* @param zone_number when defined, the continent number
|
||||||
*/
|
*/
|
||||||
final case class SpawnRequestMessage(unk1 : Int,
|
final case class SpawnRequestMessage(unk1 : Int,
|
||||||
unk2 : Long,
|
spawn_type : SpawnGroup.Value,
|
||||||
unk3 : Int,
|
unk3 : Int,
|
||||||
unk4 : Int,
|
unk4 : Int,
|
||||||
unk5 : Int)
|
zone_number : Int)
|
||||||
extends PlanetSideGamePacket {
|
extends PlanetSideGamePacket {
|
||||||
type Packet = SpawnRequestMessage
|
type Packet = SpawnRequestMessage
|
||||||
def opcode = GamePacketOpcode.SpawnRequestMessage
|
def opcode = GamePacketOpcode.SpawnRequestMessage
|
||||||
|
|
@ -30,11 +27,13 @@ final case class SpawnRequestMessage(unk1 : Int,
|
||||||
}
|
}
|
||||||
|
|
||||||
object SpawnRequestMessage extends Marshallable[SpawnRequestMessage] {
|
object SpawnRequestMessage extends Marshallable[SpawnRequestMessage] {
|
||||||
|
private val spawnGroupCodec = PacketHelpers.createLongEnumerationCodec(SpawnGroup, uint32L)
|
||||||
|
|
||||||
implicit val codec : Codec[SpawnRequestMessage] = (
|
implicit val codec : Codec[SpawnRequestMessage] = (
|
||||||
("unk1" | uint16L) ::
|
("unk1" | uint16L) ::
|
||||||
("unk2" | uint32L) ::
|
("spawn_type" | spawnGroupCodec) ::
|
||||||
("unk3" | uint16L) ::
|
("unk3" | uint16L) ::
|
||||||
("unk4" | uint16L) ::
|
("unk4" | uint16L) ::
|
||||||
("unk5" | uintL(10))
|
("zone_number" | uintL(10))
|
||||||
).as[SpawnRequestMessage]
|
).as[SpawnRequestMessage]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
39
common/src/main/scala/net/psforever/types/SpawnGroup.scala
Normal file
39
common/src/main/scala/net/psforever/types/SpawnGroup.scala
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
// Copyright (c) 2017 PSForever
|
||||||
|
package net.psforever.types
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The spawn group.<br>
|
||||||
|
* <br>
|
||||||
|
* The groups `Sanctuary`, `Tower`, and ,`Facility` are typically hard-defined by the client.
|
||||||
|
* The groups `AMS` and the `Bound*` spawns can only be displayed on the deployment map
|
||||||
|
* by sending a manual `BindPlayerMessage` packet to the client,
|
||||||
|
* and the designated spawn group identifier is returned to the server if the spawn point that is created is selected.
|
||||||
|
* The sanctuary spawn is also used as a fallback for an unknown spawn point
|
||||||
|
* as going back to one's own sanctuary counts as a "safe spawn."<br>
|
||||||
|
* <br>
|
||||||
|
* The `Sanctuary` spawn is commonly accessible on a smaller map (of the sanctuary continent)
|
||||||
|
* off to one side of the greater deployment map.
|
||||||
|
* It does not generate an icon when manually set.
|
||||||
|
* The icons produced by the normal and the bound tower and facility groups are not detailed.
|
||||||
|
* The ones that are not designated as "bound" also do not display icons when manually set.
|
||||||
|
* The AMS spawn group icons have an overhead AMS glyph and are smaller in radius, identical otherwise.
|
||||||
|
*/
|
||||||
|
object SpawnGroup extends Enumeration {
|
||||||
|
type Type = Value
|
||||||
|
|
||||||
|
val
|
||||||
|
Sanctuary,
|
||||||
|
BoundAMS,
|
||||||
|
AMS,
|
||||||
|
Unknown3,
|
||||||
|
BoundTower, //unused?
|
||||||
|
BoundFacility,
|
||||||
|
Tower,
|
||||||
|
Facility,
|
||||||
|
Unknown8,
|
||||||
|
Unknown9,
|
||||||
|
Unknown10,
|
||||||
|
Unknown11,
|
||||||
|
Unknown12
|
||||||
|
= Value
|
||||||
|
}
|
||||||
|
|
@ -198,7 +198,7 @@ class VehicleService extends Actor {
|
||||||
import net.psforever.objects.vehicles.UtilityType
|
import net.psforever.objects.vehicles.UtilityType
|
||||||
import net.psforever.objects.GlobalDefinitions
|
import net.psforever.objects.GlobalDefinitions
|
||||||
zone.Vehicles
|
zone.Vehicles
|
||||||
.filter(veh => veh.Definition == GlobalDefinitions.ams && veh.DeploymentState == DriveState.Deployed)
|
.filter(veh => veh.Health > 0 && veh.Definition == GlobalDefinitions.ams && veh.DeploymentState == DriveState.Deployed)
|
||||||
.flatMap(veh => veh.Utilities.values.filter(util => util.UtilType == UtilityType.ams_respawn_tube) )
|
.flatMap(veh => veh.Utilities.values.filter(util => util.UtilType == UtilityType.ams_respawn_tube) )
|
||||||
.map(util => util().asInstanceOf[SpawnTube])
|
.map(util => util().asInstanceOf[SpawnTube])
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,7 @@ class VehicleRemover extends RemoverActor {
|
||||||
val zoneId = entry.zone.Id
|
val zoneId = entry.zone.Id
|
||||||
vehicle.Actor ! Vehicle.PrepareForDeletion
|
vehicle.Actor ! Vehicle.PrepareForDeletion
|
||||||
//kick out all passengers
|
//kick out all passengers
|
||||||
vehicle.Definition.MountPoints.values.foreach(mount => {
|
vehicle.Seats.values.foreach(seat => {
|
||||||
val seat = vehicle.Seat(mount).get
|
|
||||||
seat.Occupant match {
|
seat.Occupant match {
|
||||||
case Some(tplayer) =>
|
case Some(tplayer) =>
|
||||||
seat.Occupant = None
|
seat.Occupant = None
|
||||||
|
|
|
||||||
|
|
@ -4,27 +4,42 @@ package game
|
||||||
import org.specs2.mutable._
|
import org.specs2.mutable._
|
||||||
import net.psforever.packet._
|
import net.psforever.packet._
|
||||||
import net.psforever.packet.game._
|
import net.psforever.packet.game._
|
||||||
import net.psforever.types.Vector3
|
import net.psforever.types.{SpawnGroup, Vector3}
|
||||||
import scodec.bits._
|
import scodec.bits._
|
||||||
|
|
||||||
class BindPlayerMessageTest extends Specification {
|
class BindPlayerMessageTest extends Specification {
|
||||||
|
val string_standard = hex"16028004000000000000000000000000000000"
|
||||||
val string_ams = hex"16 05 8440616D73 08 28000000 00000000 00000 00000 0000"
|
val string_ams = hex"16 05 8440616D73 08 28000000 00000000 00000 00000 0000"
|
||||||
val string_tech = hex"16 01 8b40746563685f706c616e74 d4 28000000 38000000 00064 012b1 a044"
|
val string_tech = hex"16 01 8b40746563685f706c616e74 d4 28000000 38000000 00064 012b1 a044"
|
||||||
|
val string_akkan = hex"16048440616d7388100000001400000214e171a8e33024"
|
||||||
|
|
||||||
|
"decode (standard)" in {
|
||||||
|
PacketCoding.DecodePacket(string_standard).require match {
|
||||||
|
case BindPlayerMessage(action, bindDesc, unk1, logging, unk2, unk3, unk4, pos) =>
|
||||||
|
action mustEqual BindStatus.Unbind
|
||||||
|
bindDesc mustEqual ""
|
||||||
|
unk1 mustEqual false
|
||||||
|
logging mustEqual false
|
||||||
|
unk2 mustEqual SpawnGroup.BoundAMS
|
||||||
|
unk3 mustEqual 0
|
||||||
|
unk4 mustEqual 0
|
||||||
|
pos mustEqual Vector3.Zero
|
||||||
|
case _ =>
|
||||||
|
ko
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
"decode (ams)" in {
|
"decode (ams)" in {
|
||||||
PacketCoding.DecodePacket(string_ams).require match {
|
PacketCoding.DecodePacket(string_ams).require match {
|
||||||
case BindPlayerMessage(action, bindDesc, unk1, logging, unk2, unk3, unk4, pos) =>
|
case BindPlayerMessage(action, bindDesc, unk1, logging, unk2, unk3, unk4, pos) =>
|
||||||
action mustEqual 5
|
action mustEqual BindStatus.Unavailable
|
||||||
bindDesc.length mustEqual 4
|
|
||||||
bindDesc mustEqual "@ams"
|
bindDesc mustEqual "@ams"
|
||||||
unk1 mustEqual false
|
unk1 mustEqual false
|
||||||
logging mustEqual false
|
logging mustEqual false
|
||||||
unk2 mustEqual 4
|
unk2 mustEqual SpawnGroup.AMS
|
||||||
unk3 mustEqual 40
|
unk3 mustEqual 10
|
||||||
unk4 mustEqual 0
|
unk4 mustEqual 0
|
||||||
pos.x mustEqual 0f
|
pos mustEqual Vector3.Zero
|
||||||
pos.y mustEqual 0f
|
|
||||||
pos.z mustEqual 0f
|
|
||||||
case _ =>
|
case _ =>
|
||||||
ko
|
ko
|
||||||
}
|
}
|
||||||
|
|
@ -33,40 +48,60 @@ class BindPlayerMessageTest extends Specification {
|
||||||
"decode (tech)" in {
|
"decode (tech)" in {
|
||||||
PacketCoding.DecodePacket(string_tech).require match {
|
PacketCoding.DecodePacket(string_tech).require match {
|
||||||
case BindPlayerMessage(action, bindDesc, unk1, logging, unk2, unk3, unk4, pos) =>
|
case BindPlayerMessage(action, bindDesc, unk1, logging, unk2, unk3, unk4, pos) =>
|
||||||
action mustEqual 1
|
action mustEqual BindStatus.Bind
|
||||||
bindDesc.length mustEqual 11
|
|
||||||
bindDesc mustEqual "@tech_plant"
|
bindDesc mustEqual "@tech_plant"
|
||||||
unk1 mustEqual true
|
unk1 mustEqual true
|
||||||
logging mustEqual true
|
logging mustEqual true
|
||||||
unk2 mustEqual 10
|
unk2 mustEqual SpawnGroup.BoundFacility
|
||||||
unk3 mustEqual 40
|
unk3 mustEqual 10
|
||||||
unk4 mustEqual 56
|
unk4 mustEqual 14
|
||||||
pos.x mustEqual 2060.0f
|
pos mustEqual Vector3(4610.0f, 6292, 69.625f)
|
||||||
pos.y mustEqual 598.0078f
|
|
||||||
pos.z mustEqual 274.5f
|
|
||||||
case _ =>
|
case _ =>
|
||||||
ko
|
ko
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"decode (akkan)" in {
|
||||||
|
PacketCoding.DecodePacket(string_akkan).require match {
|
||||||
|
case BindPlayerMessage(action, bindDesc, unk1, logging, unk2, unk3, unk4, pos) =>
|
||||||
|
action mustEqual BindStatus.Available
|
||||||
|
bindDesc mustEqual "@ams"
|
||||||
|
unk1 mustEqual true
|
||||||
|
logging mustEqual false
|
||||||
|
unk2 mustEqual SpawnGroup.AMS
|
||||||
|
unk3 mustEqual 4
|
||||||
|
unk4 mustEqual 5
|
||||||
|
pos mustEqual Vector3(2673.039f, 4423.547f, 39.1875f)
|
||||||
|
case _ =>
|
||||||
|
ko
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"encode (standard)" in {
|
||||||
|
val msg = BindPlayerMessage.Standard
|
||||||
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
|
pkt mustEqual string_standard
|
||||||
|
}
|
||||||
|
|
||||||
"encode (ams)" in {
|
"encode (ams)" in {
|
||||||
val msg = BindPlayerMessage(5, "@ams", false, false, 4, 40, 0, Vector3(0, 0, 0))
|
val msg = BindPlayerMessage(BindStatus.Unavailable, "@ams", false, false, SpawnGroup.AMS, 10, 0, Vector3.Zero)
|
||||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
pkt mustEqual string_ams
|
pkt mustEqual string_ams
|
||||||
}
|
}
|
||||||
|
|
||||||
"encode (tech)" in {
|
"encode (tech)" in {
|
||||||
val msg = BindPlayerMessage(1, "@tech_plant", true, true, 10, 40, 56, Vector3(2060.0f, 598.0078f, 274.5f))
|
val msg = BindPlayerMessage(BindStatus.Bind, "@tech_plant", true, true, SpawnGroup.BoundFacility, 10, 14, Vector3(4610.0f, 6292, 69.625f))
|
||||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
pkt mustEqual string_tech
|
pkt mustEqual string_tech
|
||||||
}
|
}
|
||||||
|
|
||||||
"standard" in {
|
"encode (akkan)" in {
|
||||||
val msg = BindPlayerMessage.STANDARD
|
val msg = BindPlayerMessage(BindStatus.Available, "@ams", true, false, SpawnGroup.AMS, 4, 5, Vector3(2673.039f, 4423.547f, 39.1875f))
|
||||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
pkt mustEqual hex"16028004000000000000000000000000000000"
|
pkt mustEqual string_akkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ package game
|
||||||
import org.specs2.mutable._
|
import org.specs2.mutable._
|
||||||
import net.psforever.packet._
|
import net.psforever.packet._
|
||||||
import net.psforever.packet.game._
|
import net.psforever.packet.game._
|
||||||
|
import net.psforever.types.SpawnGroup
|
||||||
import scodec.bits._
|
import scodec.bits._
|
||||||
|
|
||||||
class SpawnRequestMessageTest extends Specification {
|
class SpawnRequestMessageTest extends Specification {
|
||||||
|
|
@ -13,7 +14,7 @@ class SpawnRequestMessageTest extends Specification {
|
||||||
PacketCoding.DecodePacket(string).require match {
|
PacketCoding.DecodePacket(string).require match {
|
||||||
case SpawnRequestMessage(unk1,unk2,unk3,unk4,unk5) =>
|
case SpawnRequestMessage(unk1,unk2,unk3,unk4,unk5) =>
|
||||||
unk1 mustEqual 0
|
unk1 mustEqual 0
|
||||||
unk2 mustEqual 7
|
unk2 mustEqual SpawnGroup.Facility
|
||||||
unk3 mustEqual 0
|
unk3 mustEqual 0
|
||||||
unk4 mustEqual 0
|
unk4 mustEqual 0
|
||||||
unk5 mustEqual 2
|
unk5 mustEqual 2
|
||||||
|
|
@ -23,7 +24,7 @@ class SpawnRequestMessageTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
"encode" in {
|
"encode" in {
|
||||||
val msg = SpawnRequestMessage(0, 7, 0, 0, 2)
|
val msg = SpawnRequestMessage(0, SpawnGroup.Facility, 0, 0, 2)
|
||||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
pkt mustEqual string
|
pkt mustEqual string
|
||||||
|
|
|
||||||
|
|
@ -106,12 +106,12 @@ class DamageCalculationsTests extends Specification {
|
||||||
|
|
||||||
"calculate splash damage from components (near)" in {
|
"calculate splash damage from components (near)" in {
|
||||||
val result = DamageWithModifiers(DamageAgainstVehicle)(proj_prof, List(wep_prof))
|
val result = DamageWithModifiers(DamageAgainstVehicle)(proj_prof, List(wep_prof))
|
||||||
SplashDamageWithRadialDegrade(projectile, result, 0) mustEqual 264
|
SplashDamageWithRadialDegrade(projectile, result, 0) mustEqual 132
|
||||||
}
|
}
|
||||||
|
|
||||||
"calculate splash damage from components (medium)" in {
|
"calculate splash damage from components (medium)" in {
|
||||||
val result = DamageWithModifiers(DamageAgainstVehicle)(proj_prof, List(wep_prof))
|
val result = DamageWithModifiers(DamageAgainstVehicle)(proj_prof, List(wep_prof))
|
||||||
SplashDamageWithRadialDegrade(projectile, result, 5) mustEqual 145
|
SplashDamageWithRadialDegrade(projectile, result, 5) mustEqual 13
|
||||||
}
|
}
|
||||||
|
|
||||||
"calculate splash damage from components (far)" in {
|
"calculate splash damage from components (far)" in {
|
||||||
|
|
@ -341,7 +341,7 @@ class DamageModelTests extends Specification {
|
||||||
val func : (Any)=>Unit = resprojectile.damage_model.Calculate(resprojectile, ProjectileResolution.Splash)
|
val func : (Any)=>Unit = resprojectile.damage_model.Calculate(resprojectile, ProjectileResolution.Splash)
|
||||||
|
|
||||||
func(tplayer)
|
func(tplayer)
|
||||||
tplayer.Health mustEqual 81
|
tplayer.Health mustEqual 98
|
||||||
tplayer.Armor mustEqual 35
|
tplayer.Armor mustEqual 35
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -410,7 +410,7 @@ class DamageModelTests extends Specification {
|
||||||
val func : (Any)=>Unit = resprojectile.damage_model.Calculate(resprojectile, ProjectileResolution.Splash)
|
val func : (Any)=>Unit = resprojectile.damage_model.Calculate(resprojectile, ProjectileResolution.Splash)
|
||||||
|
|
||||||
func(vehicle)
|
func(vehicle)
|
||||||
vehicle.Health mustEqual 632
|
vehicle.Health mustEqual 641
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,7 @@ class EquipmentTest extends Specification {
|
||||||
obj.Size = EquipmentSize.Rifle
|
obj.Size = EquipmentSize.Rifle
|
||||||
obj.AmmoTypes += GlobalDefinitions.shotgun_shell
|
obj.AmmoTypes += GlobalDefinitions.shotgun_shell
|
||||||
obj.AmmoTypes += GlobalDefinitions.shotgun_shell_AP
|
obj.AmmoTypes += GlobalDefinitions.shotgun_shell_AP
|
||||||
|
obj.AmmoTypes += GlobalDefinitions.shotgun_shell_AP
|
||||||
obj.FireModes += new FireModeDefinition
|
obj.FireModes += new FireModeDefinition
|
||||||
obj.FireModes.head.AmmoTypeIndices += 0
|
obj.FireModes.head.AmmoTypeIndices += 0
|
||||||
obj.FireModes.head.AmmoTypeIndices += 1
|
obj.FireModes.head.AmmoTypeIndices += 1
|
||||||
|
|
@ -163,6 +164,29 @@ class EquipmentTest extends Specification {
|
||||||
obj.AmmoType mustEqual Ammo.hellfire_ammo
|
obj.AmmoType mustEqual Ammo.hellfire_ammo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"default fire mode (dual magazine feed)" in {
|
||||||
|
val obj = ToolDefinition(1076)
|
||||||
|
obj.AmmoTypes += GlobalDefinitions.shotgun_shell
|
||||||
|
obj.AmmoTypes += GlobalDefinitions.shotgun_shell_AP
|
||||||
|
obj.ProjectileTypes += GlobalDefinitions.shotgun_shell_projectile
|
||||||
|
obj.ProjectileTypes += GlobalDefinitions.shotgun_shell_AP_projectile
|
||||||
|
obj.FireModes += new FireModeDefinition
|
||||||
|
obj.FireModes.head.AmmoTypeIndices += 0
|
||||||
|
obj.FireModes.head.AmmoSlotIndex = 0
|
||||||
|
obj.FireModes += new FireModeDefinition
|
||||||
|
obj.FireModes(1).AmmoTypeIndices += 1
|
||||||
|
obj.FireModes(1).AmmoSlotIndex = 1
|
||||||
|
|
||||||
|
val tool0 = Tool(obj)
|
||||||
|
tool0.FireModeIndex mustEqual 0
|
||||||
|
tool0.ProjectileType mustEqual GlobalDefinitions.shotgun_shell_projectile.ProjectileType
|
||||||
|
|
||||||
|
obj.DefaultFireModeIndex = 1
|
||||||
|
val tool1 = Tool(obj)
|
||||||
|
tool1.FireModeIndex mustEqual 1
|
||||||
|
tool1.ProjectileType mustEqual GlobalDefinitions.shotgun_shell_AP_projectile.ProjectileType
|
||||||
|
}
|
||||||
|
|
||||||
"multiple fire modes" in {
|
"multiple fire modes" in {
|
||||||
//explanation: sample_weapon has two fire modes; each fire mode has a different ammunition type
|
//explanation: sample_weapon has two fire modes; each fire mode has a different ammunition type
|
||||||
val obj : Tool = Tool(punisher)
|
val obj : Tool = Tool(punisher)
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import java.util.concurrent.atomic.AtomicInteger
|
||||||
import akka.actor.{Actor, ActorRef, Cancellable, MDCContextAware}
|
import akka.actor.{Actor, ActorRef, Cancellable, MDCContextAware}
|
||||||
import net.psforever.packet._
|
import net.psforever.packet._
|
||||||
import net.psforever.packet.control._
|
import net.psforever.packet.control._
|
||||||
import net.psforever.packet.game.{BattleDiagramAction, ObjectDetachMessage, _}
|
import net.psforever.packet.game._
|
||||||
import scodec.Attempt.{Failure, Successful}
|
import scodec.Attempt.{Failure, Successful}
|
||||||
import scodec.bits._
|
import scodec.bits._
|
||||||
import org.log4s.{Logger, MDC}
|
import org.log4s.{Logger, MDC}
|
||||||
|
|
@ -68,6 +68,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
import WorldSessionActor._
|
import WorldSessionActor._
|
||||||
|
|
||||||
private[this] val log = org.log4s.getLogger
|
private[this] val log = org.log4s.getLogger
|
||||||
|
private[this] val damageLog = org.log4s.getLogger("DamageResolution")
|
||||||
var sessionId : Long = 0
|
var sessionId : Long = 0
|
||||||
var leftRef : ActorRef = ActorRef.noSender
|
var leftRef : ActorRef = ActorRef.noSender
|
||||||
var rightRef : ActorRef = ActorRef.noSender
|
var rightRef : ActorRef = ActorRef.noSender
|
||||||
|
|
@ -81,7 +82,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
var player : Player = null
|
var player : Player = null
|
||||||
var avatar : Avatar = null
|
var avatar : Avatar = null
|
||||||
var progressBarValue : Option[Float] = None
|
var progressBarValue : Option[Float] = None
|
||||||
var shooting : Option[PlanetSideGUID] = None
|
var shooting : Option[PlanetSideGUID] = None //ChangeFireStateMessage_Start
|
||||||
|
var prefire : Option[PlanetSideGUID] = None //if WeaponFireMessage precedes ChangeFireStateMessage_Start
|
||||||
var accessedContainer : Option[PlanetSideGameObject with Container] = None
|
var accessedContainer : Option[PlanetSideGameObject with Container] = None
|
||||||
var flying : Boolean = false
|
var flying : Boolean = false
|
||||||
var speed : Float = 1.0f
|
var speed : Float = 1.0f
|
||||||
|
|
@ -98,6 +100,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
val projectiles : Array[Option[Projectile]] = Array.fill[Option[Projectile]](Projectile.RangeUID - Projectile.BaseUID)(None)
|
val projectiles : Array[Option[Projectile]] = Array.fill[Option[Projectile]](Projectile.RangeUID - Projectile.BaseUID)(None)
|
||||||
var drawDeloyableIcon : PlanetSideGameObject with Deployable => Unit = RedrawDeployableIcons
|
var drawDeloyableIcon : PlanetSideGameObject with Deployable => Unit = RedrawDeployableIcons
|
||||||
var recentTeleportAttempt : Long = 0
|
var recentTeleportAttempt : Long = 0
|
||||||
|
var lastTerminalOrderFulfillment : Boolean = true
|
||||||
|
|
||||||
var amsSpawnPoint : Option[SpawnTube] = None
|
var amsSpawnPoint : Option[SpawnTube] = None
|
||||||
var clientKeepAlive : Cancellable = DefaultCancellable.obj
|
var clientKeepAlive : Cancellable = DefaultCancellable.obj
|
||||||
|
|
@ -115,8 +118,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
* @param b `true` or `false` (or `null`)
|
* @param b `true` or `false` (or `null`)
|
||||||
* @return 1 for `true`; 0 for `false`
|
* @return 1 for `true`; 0 for `false`
|
||||||
*/
|
*/
|
||||||
implicit def boolToInt(b : Boolean) : Int = if(b) 1
|
implicit def boolToInt(b : Boolean) : Int = if(b) 1 else 0
|
||||||
else 0
|
|
||||||
|
|
||||||
override def postStop() = {
|
override def postStop() = {
|
||||||
//TODO normally, player avatar persists a minute or so after disconnect; we are subject to the SessionReaper
|
//TODO normally, player avatar persists a minute or so after disconnect; we are subject to the SessionReaper
|
||||||
|
|
@ -128,7 +130,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
vehicleService ! Service.Leave()
|
vehicleService ! Service.Leave()
|
||||||
avatarService ! Service.Leave()
|
avatarService ! Service.Leave()
|
||||||
galaxyService ! Service.Leave()
|
galaxyService ! Service.Leave()
|
||||||
cluster ! Service.Leave()
|
|
||||||
LivePlayerList.Remove(sessionId)
|
LivePlayerList.Remove(sessionId)
|
||||||
if(player != null && player.HasGUID) {
|
if(player != null && player.HasGUID) {
|
||||||
val player_guid = player.GUID
|
val player_guid = player.GUID
|
||||||
|
|
@ -378,7 +379,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
case VehicleSpawnPad.ServerVehicleOverrideStart(vehicle, pad) =>
|
case VehicleSpawnPad.ServerVehicleOverrideStart(vehicle, pad) =>
|
||||||
val vdef = vehicle.Definition
|
val vdef = vehicle.Definition
|
||||||
if(vehicle.Seats(0).isOccupied) {
|
if(vehicle.Seats(0).isOccupied) {
|
||||||
sendResponse(ObjectDetachMessage(pad.GUID, vehicle.GUID, pad.Position + Vector3(0, 0, 0.5f), pad.Orientation.z))
|
sendResponse(ObjectDetachMessage(pad.GUID, vehicle.GUID, pad.Position + Vector3.z(0.5f), pad.Orientation.z))
|
||||||
}
|
}
|
||||||
ServerVehicleOverride(vehicle, vdef.AutoPilotSpeed1, GlobalDefinitions.isFlightVehicle(vdef) : Int)
|
ServerVehicleOverride(vehicle, vdef.AutoPilotSpeed1, GlobalDefinitions.isFlightVehicle(vdef) : Int)
|
||||||
|
|
||||||
|
|
@ -879,6 +880,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
AnnounceDestroyDeployable(target, None)
|
AnnounceDestroyDeployable(target, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Vitality.DamageResolution(target : FacilityTurret) =>
|
||||||
|
HandleFacilityTurretDamageResolution(target)
|
||||||
|
|
||||||
case Vitality.DamageResolution(target : PlanetSideGameObject) =>
|
case Vitality.DamageResolution(target : PlanetSideGameObject) =>
|
||||||
log.warn(s"Vital target ${target.Definition.Name} damage resolution not supported using this method")
|
log.warn(s"Vital target ${target.Definition.Name} damage resolution not supported using this method")
|
||||||
|
|
||||||
|
|
@ -947,9 +951,15 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
|
|
||||||
case AvatarResponse.DamageResolution(target, resolution_function) =>
|
case AvatarResponse.DamageResolution(target, resolution_function) =>
|
||||||
if(player.isAlive) {
|
if(player.isAlive) {
|
||||||
|
val originalHealth = player.Health
|
||||||
|
val originalArmor = player.Armor
|
||||||
resolution_function(target)
|
resolution_function(target)
|
||||||
val health = player.Health
|
val health = player.Health
|
||||||
val armor = player.Armor
|
val armor = player.Armor
|
||||||
|
val damageToHealth = originalHealth - health
|
||||||
|
val damageToArmor = originalArmor - armor
|
||||||
|
damageLog.info(s"${player.Name}-infantry: BEFORE=$originalHealth/$originalArmor, AFTER=$health/$armor, CHANGE=$damageToHealth/$damageToArmor")
|
||||||
|
if(damageToHealth != 0 || damageToArmor != 0) {
|
||||||
val playerGUID = player.GUID
|
val playerGUID = player.GUID
|
||||||
sendResponse(PlanetsideAttributeMessage(playerGUID, 0, health))
|
sendResponse(PlanetsideAttributeMessage(playerGUID, 0, health))
|
||||||
sendResponse(PlanetsideAttributeMessage(playerGUID, 4, armor))
|
sendResponse(PlanetsideAttributeMessage(playerGUID, 4, armor))
|
||||||
|
|
@ -958,6 +968,25 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
if(health == 0 && player.isAlive) {
|
if(health == 0 && player.isAlive) {
|
||||||
KillPlayer(player)
|
KillPlayer(player)
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
//first damage entry -> most recent damage source -> killing blow
|
||||||
|
target.History.find(p => p.isInstanceOf[DamagingActivity]) match {
|
||||||
|
case Some(data : DamageFromProjectile) =>
|
||||||
|
data.data.projectile.owner match {
|
||||||
|
case pSource : PlayerSource =>
|
||||||
|
continent.LivePlayers.find(_.Name == pSource.Name) match {
|
||||||
|
case Some(tplayer) =>
|
||||||
|
sendResponse(HitHint(tplayer.GUID, player.GUID))
|
||||||
|
case None => ;
|
||||||
|
}
|
||||||
|
case vSource : SourceEntry =>
|
||||||
|
sendResponse(DamageWithPositionMessage(damageToHealth + damageToArmor, vSource.Position))
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case AvatarResponse.Destroy(victim, killer, weapon, pos) =>
|
case AvatarResponse.Destroy(victim, killer, weapon, pos) =>
|
||||||
|
|
@ -978,11 +1007,13 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
}
|
}
|
||||||
|
|
||||||
case AvatarResponse.HitHint(source_guid) =>
|
case AvatarResponse.HitHint(source_guid) =>
|
||||||
|
if(player.isAlive) {
|
||||||
sendResponse(HitHint(source_guid, guid))
|
sendResponse(HitHint(source_guid, guid))
|
||||||
|
}
|
||||||
|
|
||||||
case AvatarResponse.KilledWhileInVehicle() =>
|
case AvatarResponse.KilledWhileInVehicle() =>
|
||||||
if(player.isAlive && player.VehicleSeated.nonEmpty) {
|
if(player.isAlive && player.VehicleSeated.nonEmpty) {
|
||||||
(continent.GUID(player.VehicleSeated.get) match {
|
(continent.GUID(player.VehicleSeated) match {
|
||||||
case Some(obj : Vehicle) =>
|
case Some(obj : Vehicle) =>
|
||||||
if(obj.Health == 0) Some(obj)
|
if(obj.Health == 0) Some(obj)
|
||||||
else None
|
else None
|
||||||
|
|
@ -990,7 +1021,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
if(obj.Health == 0) Some(obj)
|
if(obj.Health == 0) Some(obj)
|
||||||
else None
|
else None
|
||||||
case Some(obj : FacilityTurret) =>
|
case Some(obj : FacilityTurret) =>
|
||||||
if(obj.Health == 0) Some(obj)
|
if(obj.Health == 1) Some(obj) //TODO proper turret death at 0 health
|
||||||
else None
|
else None
|
||||||
case _ =>
|
case _ =>
|
||||||
None
|
None
|
||||||
|
|
@ -999,10 +1030,12 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
obj.LastShot match {
|
obj.LastShot match {
|
||||||
case Some(cause) =>
|
case Some(cause) =>
|
||||||
player.History(cause)
|
player.History(cause)
|
||||||
|
KillPlayer(player)
|
||||||
case None => ;
|
case None => ;
|
||||||
}
|
}
|
||||||
KillPlayer(player)
|
case _ =>
|
||||||
case _ => ;
|
log.warn(s"${player.Name} was seated in a vehicle and should have been killed, but was not; suicidal fallback")
|
||||||
|
Suicide(player)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1409,38 +1442,34 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
*/
|
*/
|
||||||
def HandleTerminalMessage(tplayer : Player, msg : ItemTransactionMessage, order : Terminal.Exchange) : Unit = {
|
def HandleTerminalMessage(tplayer : Player, msg : ItemTransactionMessage, order : Terminal.Exchange) : Unit = {
|
||||||
order match {
|
order match {
|
||||||
case Terminal.BuyExosuit(exosuit, subtype) => //refresh armor points
|
case Terminal.BuyExosuit(exosuit, subtype) =>
|
||||||
tplayer.History(HealFromExoSuitChange(PlayerSource(tplayer), exosuit))
|
//TODO check exo-suit permissions
|
||||||
if(tplayer.ExoSuit == exosuit) {
|
val originalSuit = tplayer.ExoSuit
|
||||||
if(exosuit == ExoSuitType.MAX) {
|
val originalSubtype = Loadout.DetermineSubtype(tplayer)
|
||||||
//special MAX case - clear any special state
|
if(originalSuit != exosuit || originalSubtype != subtype) {
|
||||||
player.UsingSpecial = SpecialExoSuitDefinition.Mode.Normal
|
|
||||||
player.ExoSuit = exosuit
|
|
||||||
if(Loadout.DetermineSubtype(tplayer) != subtype) {
|
|
||||||
//special MAX case - suit switching to a different MAX suit; we need to change the main weapon
|
|
||||||
sendResponse(ArmorChangedMessage(tplayer.GUID, exosuit, subtype))
|
|
||||||
avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.ArmorChanged(tplayer.GUID, exosuit, subtype))
|
|
||||||
val arms = tplayer.Slot(0).Equipment.get
|
|
||||||
val putTask = PutEquipmentInSlot(tplayer, Tool(GlobalDefinitions.MAXArms(subtype, tplayer.Faction)), 0)
|
|
||||||
taskResolver ! DelayedObjectHeld(tplayer, 0, List(TaskResolver.GiveTask(putTask.task, putTask.subs :+ RemoveEquipmentFromSlot(tplayer, arms, 0))))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//outside of the MAX condition above, we should seldom reach this point through conventional methods
|
|
||||||
tplayer.Armor = tplayer.MaxArmor
|
|
||||||
sendResponse(PlanetsideAttributeMessage(tplayer.GUID, 4, tplayer.Armor))
|
|
||||||
avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.PlanetsideAttribute(tplayer.GUID, 4, tplayer.Armor))
|
|
||||||
sendResponse(ItemTransactionResultMessage(msg.terminal_guid, TransactionType.Buy, true))
|
sendResponse(ItemTransactionResultMessage(msg.terminal_guid, TransactionType.Buy, true))
|
||||||
|
//prepare lists of valid objects
|
||||||
|
val beforeInventory = tplayer.Inventory.Clear()
|
||||||
|
val beforeHolsters = clearHolsters(tplayer.Holsters().iterator)
|
||||||
|
//change suit (clear inventory and change holster sizes; holsters must be empty before this point)
|
||||||
|
val originalArmor = tplayer.Armor
|
||||||
|
tplayer.ExoSuit = exosuit //changes the value of MaxArmor to reflect the new exo-suit
|
||||||
|
val toMaxArmor = tplayer.MaxArmor
|
||||||
|
if(originalSuit != exosuit || originalSubtype != subtype || originalArmor > toMaxArmor) {
|
||||||
|
tplayer.History(HealFromExoSuitChange(PlayerSource(tplayer), exosuit))
|
||||||
|
tplayer.Armor = toMaxArmor
|
||||||
|
sendResponse(PlanetsideAttributeMessage(tplayer.GUID, 4, toMaxArmor))
|
||||||
|
avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.PlanetsideAttribute(tplayer.GUID, 4, toMaxArmor))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//load a complete new exo-suit and shuffle the inventory around
|
tplayer.Armor = originalArmor
|
||||||
val originalSuit = tplayer.ExoSuit
|
}
|
||||||
//save inventory before it gets cleared (empty holsters)
|
//ensure arm is down, even if it needs to go back up
|
||||||
val dropPred = DropPredicate(tplayer)
|
if(tplayer.DrawnSlot != Player.HandsDownSlot) {
|
||||||
val (dropHolsters, beforeHolsters) = clearHolsters(tplayer.Holsters().iterator).partition(dropPred)
|
tplayer.DrawnSlot = Player.HandsDownSlot
|
||||||
val (dropInventory, beforeInventory) = tplayer.Inventory.Clear().partition(dropPred)
|
sendResponse(ObjectHeldMessage(tplayer.GUID, Player.HandsDownSlot, true))
|
||||||
//change suit (clear inventory and change holster sizes; note: holsters must be empty before this point)
|
avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.ObjectHeld(tplayer.GUID, tplayer.LastDrawnSlot))
|
||||||
tplayer.ExoSuit = exosuit
|
}
|
||||||
tplayer.Armor = tplayer.MaxArmor
|
|
||||||
//delete everything not dropped
|
//delete everything not dropped
|
||||||
(beforeHolsters ++ beforeInventory).foreach({ elem =>
|
(beforeHolsters ++ beforeInventory).foreach({ elem =>
|
||||||
sendResponse(ObjectDeleteMessage(elem.obj.GUID, 0))
|
sendResponse(ObjectDeleteMessage(elem.obj.GUID, 0))
|
||||||
|
|
@ -1451,31 +1480,25 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
//report change
|
//report change
|
||||||
sendResponse(ArmorChangedMessage(tplayer.GUID, exosuit, subtype))
|
sendResponse(ArmorChangedMessage(tplayer.GUID, exosuit, subtype))
|
||||||
avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.ArmorChanged(tplayer.GUID, exosuit, subtype))
|
avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.ArmorChanged(tplayer.GUID, exosuit, subtype))
|
||||||
sendResponse(PlanetsideAttributeMessage(tplayer.GUID, 4, tplayer.Armor))
|
//sterilize holsters
|
||||||
avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.PlanetsideAttribute(tplayer.GUID, 4, tplayer.Armor))
|
val normalHolsters = if(originalSuit == ExoSuitType.MAX) {
|
||||||
val finalInventory = if(exosuit == ExoSuitType.MAX) {
|
|
||||||
//MAX weapon to be placed in first pistol slot; slot to be drawn
|
|
||||||
taskResolver ! DelayedObjectHeld(tplayer, 0, List(PutEquipmentInSlot(tplayer, Tool(GlobalDefinitions.MAXArms(subtype, tplayer.Faction)), 0)))
|
|
||||||
//fill melee slot
|
|
||||||
fillEmptyHolsters(List(tplayer.Slot(4)).iterator, beforeHolsters) ++ beforeInventory
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//remove potential MAX weapon
|
|
||||||
tplayer.DrawnSlot = Player.HandsDownSlot
|
|
||||||
sendResponse(ObjectHeldMessage(tplayer.GUID, Player.HandsDownSlot, true))
|
|
||||||
val normalWeapons = if(originalSuit == ExoSuitType.MAX) {
|
|
||||||
val (maxWeapons, normalWeapons) = beforeHolsters.partition(elem => elem.obj.Size == EquipmentSize.Max)
|
val (maxWeapons, normalWeapons) = beforeHolsters.partition(elem => elem.obj.Size == EquipmentSize.Max)
|
||||||
maxWeapons.foreach(entry => {
|
maxWeapons.foreach(entry => { taskResolver ! GUIDTask.UnregisterEquipment(entry.obj)(continent.GUID) })
|
||||||
taskResolver ! GUIDTask.UnregisterEquipment(entry.obj)(continent.GUID)
|
|
||||||
})
|
|
||||||
avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.ObjectHeld(player.GUID, player.LastDrawnSlot))
|
|
||||||
normalWeapons
|
normalWeapons
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
beforeHolsters
|
beforeHolsters
|
||||||
}
|
}
|
||||||
//fill holsters
|
//populate holsters
|
||||||
val (afterHolsters, toInventory) = normalWeapons.partition(elem => elem.obj.Size == tplayer.Slot(elem.start).Size)
|
val finalInventory = if(exosuit == ExoSuitType.MAX) {
|
||||||
|
taskResolver ! DelayedObjectHeld(tplayer, 0, List(PutEquipmentInSlot(tplayer, Tool(GlobalDefinitions.MAXArms(subtype, tplayer.Faction)), 0)))
|
||||||
|
fillEmptyHolsters(List(tplayer.Slot(4)).iterator, normalHolsters) ++ beforeInventory
|
||||||
|
}
|
||||||
|
else if(originalSuit == exosuit) { //note - this will rarely be the situation
|
||||||
|
fillEmptyHolsters(tplayer.Holsters().iterator, normalHolsters)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val (afterHolsters, toInventory) = normalHolsters.partition(elem => elem.obj.Size == tplayer.Slot(elem.start).Size)
|
||||||
afterHolsters.foreach({ elem => tplayer.Slot(elem.start).Equipment = elem.obj })
|
afterHolsters.foreach({ elem => tplayer.Slot(elem.start).Equipment = elem.obj })
|
||||||
fillEmptyHolsters(tplayer.Holsters().iterator, toInventory ++ beforeInventory)
|
fillEmptyHolsters(tplayer.Holsters().iterator, toInventory ++ beforeInventory)
|
||||||
}
|
}
|
||||||
|
|
@ -1511,7 +1534,12 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
case None => ;
|
case None => ;
|
||||||
}
|
}
|
||||||
//put items back into inventory
|
//put items back into inventory
|
||||||
val (stow, drop) = GridInventory.recoverInventory(finalInventory, tplayer.Inventory)
|
val (stow, drop) = if(originalSuit == exosuit) {
|
||||||
|
(finalInventory, Nil)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
GridInventory.recoverInventory(finalInventory, tplayer.Inventory)
|
||||||
|
}
|
||||||
stow.foreach(elem => {
|
stow.foreach(elem => {
|
||||||
tplayer.Inventory.Insert(elem.start, elem.obj)
|
tplayer.Inventory.Insert(elem.start, elem.obj)
|
||||||
val obj = elem.obj
|
val obj = elem.obj
|
||||||
|
|
@ -1525,14 +1553,21 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
//drop items on ground
|
val (finalDroppedItems, retiredItems) = drop.map(item => InventoryItem(item, -1)).partition(DropPredicate(tplayer))
|
||||||
|
//drop special items on ground
|
||||||
val pos = tplayer.Position
|
val pos = tplayer.Position
|
||||||
val orient = Vector3(0, 0, tplayer.Orientation.z)
|
val orient = Vector3.z(tplayer.Orientation.z)
|
||||||
((dropHolsters ++ dropInventory).map(_.obj) ++ drop).foreach(obj => {
|
finalDroppedItems.foreach(entry => {
|
||||||
//TODO make a sound when dropping stuff
|
//TODO make a sound when dropping stuff
|
||||||
continent.Ground ! Zone.Ground.DropItem(obj, pos, orient)
|
continent.Ground ! Zone.Ground.DropItem(entry.obj, pos, orient)
|
||||||
})
|
})
|
||||||
sendResponse(ItemTransactionResultMessage(msg.terminal_guid, TransactionType.Buy, true))
|
//deconstruct normal items
|
||||||
|
retiredItems.foreach({ entry =>
|
||||||
|
taskResolver ! GUIDTask.UnregisterEquipment(entry.obj)(continent.GUID)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sendResponse(ItemTransactionResultMessage(msg.terminal_guid, TransactionType.Buy, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
case Terminal.BuyEquipment(item) =>
|
case Terminal.BuyEquipment(item) =>
|
||||||
|
|
@ -1556,26 +1591,38 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
}
|
}
|
||||||
|
|
||||||
case Terminal.InfantryLoadout(exosuit, subtype, holsters, inventory) =>
|
case Terminal.InfantryLoadout(exosuit, subtype, holsters, inventory) =>
|
||||||
//TODO optimizations against replacing Equipment with the exact same Equipment and potentially for recycling existing Equipment
|
|
||||||
log.info(s"$tplayer wants to change equipment loadout to their option #${msg.unk1 + 1}")
|
log.info(s"$tplayer wants to change equipment loadout to their option #${msg.unk1 + 1}")
|
||||||
|
//TODO check exo-suit permissions
|
||||||
sendResponse(ItemTransactionResultMessage(msg.terminal_guid, TransactionType.Loadout, true))
|
sendResponse(ItemTransactionResultMessage(msg.terminal_guid, TransactionType.Loadout, true))
|
||||||
tplayer.History(HealFromExoSuitChange(PlayerSource(tplayer), exosuit))
|
//prepare lists of valid objects
|
||||||
//ensure arm is down
|
val beforeFreeHand = tplayer.FreeHand.Equipment
|
||||||
tplayer.DrawnSlot = Player.HandsDownSlot
|
|
||||||
sendResponse(ObjectHeldMessage(tplayer.GUID, Player.HandsDownSlot, true))
|
|
||||||
avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.ObjectHeld(tplayer.GUID, Player.HandsDownSlot))
|
|
||||||
//load
|
|
||||||
val dropPred = DropPredicate(tplayer)
|
val dropPred = DropPredicate(tplayer)
|
||||||
val (dropHolsters, beforeHolsters) = clearHolsters(tplayer.Holsters().iterator).partition(dropPred)
|
val (dropHolsters, beforeHolsters) = clearHolsters(tplayer.Holsters().iterator).partition(dropPred)
|
||||||
val (dropInventory, beforeInventory) = tplayer.Inventory.Clear().partition(dropPred)
|
val (dropInventory, beforeInventory) = tplayer.Inventory.Clear().partition(dropPred)
|
||||||
val (_, afterHolsters) = holsters.partition(dropPred)
|
val (_, afterHolsters) = holsters.partition(dropPred) //dropped items are forgotten
|
||||||
//dropped items are lost
|
val (_, afterInventory) = inventory.partition(dropPred) //dropped items are forgotten
|
||||||
val (_, afterInventory) = inventory.partition(dropPred)
|
//change suit (clear inventory and change holster sizes; holsters must be empty before this point)
|
||||||
//dropped items are lost
|
tplayer.FreeHand.Equipment = None //terminal and inventory will close, so prematurely dropping should be fine
|
||||||
val beforeFreeHand = tplayer.FreeHand.Equipment
|
val originalSuit = player.ExoSuit
|
||||||
//change suit (clear inventory and change holster sizes; note: holsters must be empty before this point)
|
val originalSubtype = Loadout.DetermineSubtype(tplayer)
|
||||||
|
val originalArmor = player.Armor
|
||||||
tplayer.ExoSuit = exosuit
|
tplayer.ExoSuit = exosuit
|
||||||
tplayer.Armor = tplayer.MaxArmor
|
val toMaxArmor = tplayer.MaxArmor
|
||||||
|
if(originalSuit != exosuit || originalSubtype != subtype || originalArmor > toMaxArmor) {
|
||||||
|
tplayer.History(HealFromExoSuitChange(PlayerSource(tplayer), exosuit))
|
||||||
|
tplayer.Armor = toMaxArmor
|
||||||
|
sendResponse(PlanetsideAttributeMessage(tplayer.GUID, 4, toMaxArmor))
|
||||||
|
avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.PlanetsideAttribute(tplayer.GUID, 4, toMaxArmor))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tplayer.Armor = originalArmor
|
||||||
|
}
|
||||||
|
//ensure arm is down, even if it needs to go back up
|
||||||
|
if(tplayer.DrawnSlot != Player.HandsDownSlot) {
|
||||||
|
tplayer.DrawnSlot = Player.HandsDownSlot
|
||||||
|
sendResponse(ObjectHeldMessage(tplayer.GUID, Player.HandsDownSlot, true))
|
||||||
|
avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.ObjectHeld(tplayer.GUID, tplayer.LastDrawnSlot))
|
||||||
|
}
|
||||||
//delete everything (not dropped)
|
//delete everything (not dropped)
|
||||||
beforeHolsters.foreach({ elem =>
|
beforeHolsters.foreach({ elem =>
|
||||||
avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.ObjectDelete(tplayer.GUID, elem.obj.GUID))
|
avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.ObjectDelete(tplayer.GUID, elem.obj.GUID))
|
||||||
|
|
@ -1587,29 +1634,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
//report change
|
//report change
|
||||||
sendResponse(ArmorChangedMessage(tplayer.GUID, exosuit, subtype))
|
sendResponse(ArmorChangedMessage(tplayer.GUID, exosuit, subtype))
|
||||||
avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.ArmorChanged(tplayer.GUID, exosuit, subtype))
|
avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.ArmorChanged(tplayer.GUID, exosuit, subtype))
|
||||||
sendResponse(PlanetsideAttributeMessage(tplayer.GUID, 4, tplayer.Armor))
|
|
||||||
avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.PlanetsideAttribute(tplayer.GUID, 4, tplayer.Armor))
|
|
||||||
//re-draw equipment held in free hand
|
|
||||||
beforeFreeHand match {
|
|
||||||
case Some(item) =>
|
|
||||||
tplayer.FreeHand.Equipment = beforeFreeHand
|
|
||||||
val definition = item.Definition
|
|
||||||
sendResponse(
|
|
||||||
ObjectCreateDetailedMessage(
|
|
||||||
definition.ObjectId,
|
|
||||||
item.GUID,
|
|
||||||
ObjectCreateMessageParent(tplayer.GUID, Player.FreeHandSlot),
|
|
||||||
definition.Packet.DetailedConstructorData(item).get
|
|
||||||
)
|
|
||||||
)
|
|
||||||
case None => ;
|
|
||||||
}
|
|
||||||
//draw holsters
|
|
||||||
if(exosuit == ExoSuitType.MAX) {
|
if(exosuit == ExoSuitType.MAX) {
|
||||||
tplayer.DrawnSlot = 0
|
val (maxWeapons, otherWeapons) = afterHolsters.partition(entry => { entry.obj.Size == EquipmentSize.Max })
|
||||||
val (maxWeapons, otherWeapons) = afterHolsters.partition(entry => {
|
|
||||||
entry.obj.Size == EquipmentSize.Max
|
|
||||||
})
|
|
||||||
taskResolver ! DelayedObjectHeld(tplayer, 0, List(PutEquipmentInSlot(tplayer, maxWeapons.head.obj, 0)))
|
taskResolver ! DelayedObjectHeld(tplayer, 0, List(PutEquipmentInSlot(tplayer, maxWeapons.head.obj, 0)))
|
||||||
otherWeapons
|
otherWeapons
|
||||||
}
|
}
|
||||||
|
|
@ -1624,9 +1650,12 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
})
|
})
|
||||||
//drop stuff on ground
|
//drop stuff on ground
|
||||||
val pos = tplayer.Position
|
val pos = tplayer.Position
|
||||||
val orient = Vector3(0, 0, tplayer.Orientation.z)
|
val orient = Vector3.z(tplayer.Orientation.z)
|
||||||
((dropHolsters ++ dropInventory).map(_.obj)).foreach(obj => {
|
((beforeFreeHand match {
|
||||||
continent.Ground ! Zone.Ground.DropItem(obj, pos, orient)
|
case Some(item) => List(InventoryItem(item, -1)) //add the item previously in free hand, if any
|
||||||
|
case None => Nil
|
||||||
|
}) ++ dropHolsters ++ dropInventory).foreach(entry => {
|
||||||
|
continent.Ground ! Zone.Ground.DropItem(entry.obj, pos, orient)
|
||||||
})
|
})
|
||||||
|
|
||||||
case Terminal.VehicleLoadout(definition, weapons, inventory) =>
|
case Terminal.VehicleLoadout(definition, weapons, inventory) =>
|
||||||
|
|
@ -1855,6 +1884,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
log.warn(s"${tplayer.Name} made a request but the terminal rejected the $order")
|
log.warn(s"${tplayer.Name} made a request but the terminal rejected the $order")
|
||||||
sendResponse(ItemTransactionResultMessage(msg.terminal_guid, msg.transaction_type, false))
|
sendResponse(ItemTransactionResultMessage(msg.terminal_guid, msg.transaction_type, false))
|
||||||
}
|
}
|
||||||
|
lastTerminalOrderFulfillment = true
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1899,7 +1929,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
}
|
}
|
||||||
|
|
||||||
case VehicleResponse.HitHint(source_guid) =>
|
case VehicleResponse.HitHint(source_guid) =>
|
||||||
|
if(player.isAlive) {
|
||||||
sendResponse(HitHint(source_guid, player.GUID))
|
sendResponse(HitHint(source_guid, player.GUID))
|
||||||
|
}
|
||||||
|
|
||||||
case VehicleResponse.InventoryState(obj, parent_guid, start, con_data) =>
|
case VehicleResponse.InventoryState(obj, parent_guid, start, con_data) =>
|
||||||
if(tplayer_guid != guid) {
|
if(tplayer_guid != guid) {
|
||||||
|
|
@ -1994,7 +2026,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
sendResponse(msg)
|
sendResponse(msg)
|
||||||
|
|
||||||
case VehicleResponse.UpdateAmsSpawnPoint(list) =>
|
case VehicleResponse.UpdateAmsSpawnPoint(list) =>
|
||||||
if(player.isBackpack) {
|
|
||||||
//dismiss old ams spawn point
|
//dismiss old ams spawn point
|
||||||
ClearCurrentAmsSpawnPoint()
|
ClearCurrentAmsSpawnPoint()
|
||||||
//draw new ams spawn point
|
//draw new ams spawn point
|
||||||
|
|
@ -2003,16 +2034,10 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
.sortBy(tube => Vector3.DistanceSquared(tube.Position, player.Position))
|
.sortBy(tube => Vector3.DistanceSquared(tube.Position, player.Position))
|
||||||
.headOption match {
|
.headOption match {
|
||||||
case Some(tube) =>
|
case Some(tube) =>
|
||||||
sendResponse(
|
sendResponse(BindPlayerMessage(BindStatus.Available, "@ams", true, false, SpawnGroup.AMS, continent.Number, 5, tube.Position))
|
||||||
BattleplanMessage(41378949, "ams", continent.Number, List(BattleDiagramAction(DiagramActionCode.StartDrawing)))
|
|
||||||
)
|
|
||||||
sendResponse(
|
|
||||||
BattleplanMessage(41378949, "ams", continent.Number, List(BattleDiagramAction.drawString(tube.Position.x, tube.Position.y, 3, 0, "AMS")))
|
|
||||||
)
|
|
||||||
amsSpawnPoint = Some(tube)
|
amsSpawnPoint = Some(tube)
|
||||||
case None => ;
|
case None => ;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
@ -2147,6 +2172,13 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
val wep = slot.Equipment.get
|
val wep = slot.Equipment.get
|
||||||
avatarService ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, wep.GUID))
|
avatarService ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, wep.GUID))
|
||||||
})
|
})
|
||||||
|
target.CargoHolds.values.foreach(hold => {
|
||||||
|
hold.Occupant match {
|
||||||
|
case Some(cargo) =>
|
||||||
|
|
||||||
|
case None => ;
|
||||||
|
}
|
||||||
|
})
|
||||||
target.Definition match {
|
target.Definition match {
|
||||||
case GlobalDefinitions.ams =>
|
case GlobalDefinitions.ams =>
|
||||||
target.Actor ! Deployment.TryDeploymentChange(DriveState.Undeploying)
|
target.Actor ! Deployment.TryDeploymentChange(DriveState.Undeploying)
|
||||||
|
|
@ -2199,6 +2231,48 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
avatarService ! AvatarServiceMessage(continentId, AvatarAction.PlanetsideAttribute(guid, 0, health))
|
avatarService ! AvatarServiceMessage(continentId, AvatarAction.PlanetsideAttribute(guid, 0, health))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def HandleFacilityTurretDamageResolution(target : FacilityTurret) : Unit = {
|
||||||
|
val targetGUID = target.GUID
|
||||||
|
val playerGUID = player.GUID
|
||||||
|
val continentId = continent.Id
|
||||||
|
val players = target.Seats.values.filter(seat => {
|
||||||
|
seat.isOccupied && seat.Occupant.get.isAlive
|
||||||
|
})
|
||||||
|
if(target.Health > 1) { //TODO turret "death" at 0, as is proper
|
||||||
|
//alert occupants to damage source
|
||||||
|
players.foreach(seat => {
|
||||||
|
val tplayer = seat.Occupant.get
|
||||||
|
avatarService ! AvatarServiceMessage(tplayer.Name, AvatarAction.HitHint(playerGUID, tplayer.GUID))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//alert to vehicle death (hence, occupants' deaths)
|
||||||
|
players.foreach(seat => {
|
||||||
|
val tplayer = seat.Occupant.get
|
||||||
|
val tplayerGUID = tplayer.GUID
|
||||||
|
avatarService ! AvatarServiceMessage(tplayer.Name, AvatarAction.KilledWhileInVehicle(tplayerGUID))
|
||||||
|
avatarService ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(tplayerGUID, tplayerGUID)) //dead player still sees self
|
||||||
|
})
|
||||||
|
//turret wreckage has no weapons
|
||||||
|
// target.Weapons.values
|
||||||
|
// .filter {
|
||||||
|
// _.Equipment.nonEmpty
|
||||||
|
// }
|
||||||
|
// .foreach(slot => {
|
||||||
|
// val wep = slot.Equipment.get
|
||||||
|
// avatarService ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, wep.GUID))
|
||||||
|
// })
|
||||||
|
// avatarService ! AvatarServiceMessage(continentId, AvatarAction.Destroy(targetGUID, playerGUID, playerGUID, player.Position))
|
||||||
|
target.Health = 1
|
||||||
|
vehicleService ! VehicleServiceMessage(continentId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, target.MaxHealth)) //TODO not necessary
|
||||||
|
if(target.Upgrade != TurretUpgrade.None) {
|
||||||
|
vehicleService ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.ClearSpecific(List(target), continent))
|
||||||
|
vehicleService ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.AddTask(target, continent, TurretUpgrade.None))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vehicleService ! VehicleServiceMessage(continentId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, target.Health))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* na
|
* na
|
||||||
* @param tplayer na
|
* @param tplayer na
|
||||||
|
|
@ -2462,15 +2536,15 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
//player.Position = Vector3(4262.211f ,4067.0625f ,262.35938f) //z6, Akna.tower
|
//player.Position = Vector3(4262.211f ,4067.0625f ,262.35938f) //z6, Akna.tower
|
||||||
//player.Orientation = Vector3(0f, 0f, 132.1875f)
|
//player.Orientation = Vector3(0f, 0f, 132.1875f)
|
||||||
// player.ExoSuit = ExoSuitType.MAX //TODO strange issue; divide number above by 10 when uncommenting
|
// player.ExoSuit = ExoSuitType.MAX //TODO strange issue; divide number above by 10 when uncommenting
|
||||||
player.Slot(0).Equipment = ConstructionItem(ace) //Tool(GlobalDefinitions.StandardPistol(player.Faction))
|
player.Slot(0).Equipment = Tool(GlobalDefinitions.StandardPistol(player.Faction))
|
||||||
player.Slot(2).Equipment = ConstructionItem(advanced_ace) //punisher //suppressor
|
player.Slot(2).Equipment = Tool(suppressor)
|
||||||
player.Slot(4).Equipment = Tool(GlobalDefinitions.StandardMelee(player.Faction))
|
player.Slot(4).Equipment = Tool(GlobalDefinitions.StandardMelee(player.Faction))
|
||||||
player.Slot(6).Equipment = ConstructionItem(ace) //bullet_9mm
|
player.Slot(6).Equipment = AmmoBox(bullet_9mm)
|
||||||
player.Slot(9).Equipment = ConstructionItem(ace) //bullet_9mm
|
player.Slot(9).Equipment = AmmoBox(bullet_9mm)
|
||||||
player.Slot(12).Equipment = ConstructionItem(ace) //bullet_9mm
|
player.Slot(12).Equipment = AmmoBox(bullet_9mm)
|
||||||
player.Slot(33).Equipment = Tool(suppressor) //AmmoBox(bullet_9mm_AP)
|
player.Slot(33).Equipment = AmmoBox(bullet_9mm_AP)
|
||||||
//player.Slot(36).Equipment = AmmoBox(GlobalDefinitions.StandardPistolAmmo(player.Faction))
|
player.Slot(36).Equipment = AmmoBox(GlobalDefinitions.StandardPistolAmmo(player.Faction))
|
||||||
//player.Slot(39).Equipment = SimpleItem(remote_electronics_kit)
|
player.Slot(39).Equipment = SimpleItem(remote_electronics_kit)
|
||||||
player.Locker.Inventory += 0 -> SimpleItem(remote_electronics_kit)
|
player.Locker.Inventory += 0 -> SimpleItem(remote_electronics_kit)
|
||||||
//TODO end temp player character auto-loading
|
//TODO end temp player character auto-loading
|
||||||
self ! ListAccountCharacters
|
self ! ListAccountCharacters
|
||||||
|
|
@ -2478,97 +2552,44 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
clientKeepAlive.cancel
|
clientKeepAlive.cancel
|
||||||
clientKeepAlive = context.system.scheduler.schedule(0 seconds, 500 milliseconds, self, PokeClient())
|
clientKeepAlive = context.system.scheduler.schedule(0 seconds, 500 milliseconds, self, PokeClient())
|
||||||
|
|
||||||
case msg @ DismountVehicleCargoMsg(player_guid, vehicle_guid, bailed, requestedByPassenger, kicked) =>
|
|
||||||
log.info(msg.toString)
|
|
||||||
|
|
||||||
// Ignore dismount requests by passengers of the vehicle in the cargo bay for now
|
|
||||||
// todo: allow passengers of vehicle in cargo bay to bail, but not bail the cargo vehicle itself
|
|
||||||
if(!requestedByPassenger) {
|
|
||||||
StartBundlingPackets()
|
|
||||||
val vehicle = continent.GUID(vehicle_guid).get.asInstanceOf[Vehicle]
|
|
||||||
val cargo_vehicle = continent.GUID(vehicle.MountedIn.get).get.asInstanceOf[Vehicle]
|
|
||||||
// todo: change this to work with multiple cargo holds for potential custom vehicles in the future
|
|
||||||
val cargo_mountpoint = cargo_vehicle.Definition.Cargo.head._1
|
|
||||||
|
|
||||||
val cargoStatusMessage = CargoMountPointStatusMessage(cargo_vehicle.GUID, PlanetSideGUID(0), PlanetSideGUID(0), vehicle_guid, cargo_mountpoint, CargoStatus.InProgress, 0)
|
|
||||||
log.info(cargoStatusMessage.toString)
|
|
||||||
// Dismount vehicle on UI and disable "shield" effect on lodestar
|
|
||||||
sendResponse(cargoStatusMessage)
|
|
||||||
|
|
||||||
|
|
||||||
// Detach vehicle from cargo vehicle
|
|
||||||
val dismount_position = if (bailed || kicked) {
|
|
||||||
// If we're bailing drop the vehicle below the cargo vehicle
|
|
||||||
//todo: once the server has a concept of height from the floor we should probably ensure vehicles aren't dropped below the world
|
|
||||||
Vector3(cargo_vehicle.Position.x, cargo_vehicle.Position.y, cargo_vehicle.Position.z - 1f)
|
|
||||||
} else if (cargo_vehicle.Definition == GlobalDefinitions.dropship) {
|
|
||||||
// As the galaxy cargo bay is offset backwards from the center of the vehicle (unlike the lodestar) we need to set the position backwards slightly
|
|
||||||
Vector3(cargo_vehicle.Position.x, cargo_vehicle.Position.y - 7f, cargo_vehicle.Position.z + 2f)
|
|
||||||
} else {
|
|
||||||
Vector3(cargo_vehicle.Position.x, cargo_vehicle.Position.y, cargo_vehicle.Position.z + 2f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a flag if the vehicle should mount/dismount sideways
|
|
||||||
//todo: BFRs will likely also need this set
|
|
||||||
val sideways = vehicle.Definition == GlobalDefinitions.router
|
|
||||||
|
|
||||||
val rotation = if(sideways) {
|
|
||||||
// dismount router "sideways" in a lodestar
|
|
||||||
cargo_vehicle.Orientation.z - 90f
|
|
||||||
} else {
|
|
||||||
cargo_vehicle.Orientation.z
|
|
||||||
}
|
|
||||||
|
|
||||||
val detachMessage = ObjectDetachMessage(cargo_vehicle.GUID, vehicle_guid, dismount_position, cargo_vehicle.Orientation.x, cargo_vehicle.Orientation.y, rotation)
|
|
||||||
log.info(detachMessage.toString)
|
|
||||||
sendResponse(detachMessage)
|
|
||||||
|
|
||||||
// Update display to show current vehicle health & shields correctly
|
|
||||||
log.warn(s"vehicle health: ${vehicle.Health} shields: ${vehicle.Shields}")
|
|
||||||
vehicleService ! VehicleServiceMessage(s"${vehicle.Actor}", VehicleAction.SendResponse(PlanetSideGUID(0), PlanetsideAttributeMessage(vehicle_guid, 0, vehicle.Health)))
|
|
||||||
vehicleService ! VehicleServiceMessage(s"${vehicle.Actor}", VehicleAction.SendResponse(PlanetSideGUID(0), PlanetsideAttributeMessage(vehicle_guid, 68, vehicle.Shields)))
|
|
||||||
|
|
||||||
vehicle.MountedIn = None
|
|
||||||
cargo_vehicle.CargoHold(cargo_mountpoint).get.Occupant = None
|
|
||||||
|
|
||||||
if (!bailed) {
|
|
||||||
// Automatically drive the vehicle backwards out of the cargo bay
|
|
||||||
if (!sideways) {
|
|
||||||
ServerVehicleLockReverse()
|
|
||||||
} else {
|
|
||||||
ServerVehicleLockStrafeLeft()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//todo: proper vehicle bailing. It works currently but when collision damage is implemented the vehicle will take damage if not in a bail state. Need to confirm how this is done with further research
|
|
||||||
}
|
|
||||||
|
|
||||||
import scala.concurrent.duration._
|
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
|
||||||
// Start a timer to check every second if the vehicle has moved far enough away to be considered dismounted, and then close the cargo door
|
|
||||||
cargoDismountTimer = context.system.scheduler.scheduleOnce(250 milliseconds, self, CheckCargoDismount(vehicle_guid, cargo_vehicle.GUID, cargo_mountpoint, iteration = 0))
|
|
||||||
|
|
||||||
StopBundlingPackets()
|
|
||||||
|
|
||||||
// Sync to other clients
|
|
||||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.SendResponse(player.GUID, cargoStatusMessage))
|
|
||||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.SendResponse(player.GUID, detachMessage))
|
|
||||||
}
|
|
||||||
case msg @ MountVehicleCargoMsg(player_guid, vehicle_guid, cargo_vehicle_guid, unk4) =>
|
case msg @ MountVehicleCargoMsg(player_guid, vehicle_guid, cargo_vehicle_guid, unk4) =>
|
||||||
log.info(msg.toString)
|
log.info(msg.toString)
|
||||||
|
(continent.GUID(vehicle_guid), continent.GUID(cargo_vehicle_guid)) match {
|
||||||
val cargo_vehicle = continent.GUID(cargo_vehicle_guid).get.asInstanceOf[Vehicle]
|
case (Some(_ : Vehicle), Some(carrier : Vehicle)) =>
|
||||||
val cargo_mountpoint = cargo_vehicle.Definition.Cargo.head._1
|
carrier.Definition.Cargo.headOption match {
|
||||||
|
case Some((mountPoint, _)) => //begin the mount process - open the cargo door
|
||||||
// Begin the mount process - open the cargo door
|
val reply = CargoMountPointStatusMessage(cargo_vehicle_guid, PlanetSideGUID(0), vehicle_guid, PlanetSideGUID(0), mountPoint, CargoStatus.InProgress, 0)
|
||||||
val reply = CargoMountPointStatusMessage(cargo_vehicle_guid, PlanetSideGUID(0), vehicle_guid, PlanetSideGUID(0), cargo_mountpoint, CargoStatus.InProgress, 0)
|
log.debug(reply.toString)
|
||||||
log.warn(reply.toString)
|
|
||||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.SendResponse(player.GUID, reply))
|
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.SendResponse(player.GUID, reply))
|
||||||
sendResponse(reply)
|
sendResponse(reply)
|
||||||
|
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
// Start timer to check every second if the vehicle is close enough to mount, or far enough away to cancel the mounting
|
// Start timer to check every second if the vehicle is close enough to mount, or far enough away to cancel the mounting
|
||||||
cargoMountTimer = context.system.scheduler.scheduleOnce(1 second, self, CheckCargoMounting(vehicle_guid, cargo_vehicle_guid, cargo_mountpoint, iteration = 0))
|
cargoMountTimer = context.system.scheduler.scheduleOnce(1 second, self, CheckCargoMounting(vehicle_guid, cargo_vehicle_guid, mountPoint, iteration = 0))
|
||||||
|
case None =>
|
||||||
|
log.warn(s"MountVehicleCargoMsg: target carrier vehicle (${carrier.Definition.Name}) does not have a cargo hold")
|
||||||
|
}
|
||||||
|
case(None, _) | (Some(_), None) =>
|
||||||
|
log.warn(s"MountVehicleCargoMsg: one or more of the target vehicles do not exist - $cargo_vehicle_guid or $vehicle_guid")
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
case msg @ DismountVehicleCargoMsg(player_guid, vehicle_guid, bailed, requestedByPassenger, kicked) =>
|
||||||
|
log.info(msg.toString)
|
||||||
|
if(!requestedByPassenger) {
|
||||||
|
continent.GUID(vehicle_guid) match {
|
||||||
|
case Some(cargo : Vehicle) =>
|
||||||
|
continent.GUID(cargo.MountedIn) match {
|
||||||
|
case Some(ferry : Vehicle) =>
|
||||||
|
HandleDismountVehicleCargo(player_guid, vehicle_guid, cargo, ferry.GUID, ferry, bailed, requestedByPassenger, kicked)
|
||||||
|
case _ =>
|
||||||
|
log.warn(s"DismountVehicleCargoMsg: target ${cargo.Definition.Name} does not know what treats it as cargo")
|
||||||
|
}
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case msg @ CharacterCreateRequestMessage(name, head, voice, gender, empire) =>
|
case msg @ CharacterCreateRequestMessage(name, head, voice, gender, empire) =>
|
||||||
log.info("Handling " + msg)
|
log.info("Handling " + msg)
|
||||||
sendResponse(ActionResultMessage.Pass)
|
sendResponse(ActionResultMessage.Pass)
|
||||||
|
|
@ -2843,9 +2864,29 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
player.FacingYawUpper = yaw_upper
|
player.FacingYawUpper = yaw_upper
|
||||||
player.Crouching = is_crouching
|
player.Crouching = is_crouching
|
||||||
player.Jumping = is_jumping
|
player.Jumping = is_jumping
|
||||||
|
|
||||||
if(vel.isDefined && usingMedicalTerminal.isDefined) {
|
if(vel.isDefined && usingMedicalTerminal.isDefined) {
|
||||||
StopUsingProximityUnit(continent.GUID(usingMedicalTerminal.get).get.asInstanceOf[ProximityTerminal])
|
StopUsingProximityUnit(continent.GUID(usingMedicalTerminal.get).get.asInstanceOf[ProximityTerminal])
|
||||||
}
|
}
|
||||||
|
accessedContainer match {
|
||||||
|
case Some(veh : Vehicle) =>
|
||||||
|
if(vel.isDefined || Vector3.DistanceSquared(player.Position, veh.Position) > 100) {
|
||||||
|
val guid = player.GUID
|
||||||
|
sendResponse(UnuseItemMessage(guid, veh.GUID))
|
||||||
|
sendResponse(UnuseItemMessage(guid, guid))
|
||||||
|
veh.AccessingTrunk = None
|
||||||
|
UnAccessContents(veh)
|
||||||
|
accessedContainer = None
|
||||||
|
}
|
||||||
|
case Some(container) => //just in case
|
||||||
|
if(vel.isDefined) {
|
||||||
|
val guid = player.GUID
|
||||||
|
sendResponse(UnuseItemMessage(guid, container.GUID))
|
||||||
|
sendResponse(UnuseItemMessage(guid, guid))
|
||||||
|
accessedContainer = None
|
||||||
|
}
|
||||||
|
case None => ;
|
||||||
|
}
|
||||||
val wepInHand : Boolean = player.Slot(player.DrawnSlot).Equipment match {
|
val wepInHand : Boolean = player.Slot(player.DrawnSlot).Equipment match {
|
||||||
case Some(item) => item.Definition == GlobalDefinitions.bolt_driver
|
case Some(item) => item.Definition == GlobalDefinitions.bolt_driver
|
||||||
case None => false
|
case None => false
|
||||||
|
|
@ -2933,10 +2974,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
context.system.scheduler.scheduleOnce(50 milliseconds, self, UnregisterCorpseOnVehicleDisembark(player))
|
context.system.scheduler.scheduleOnce(50 milliseconds, self, UnregisterCorpseOnVehicleDisembark(player))
|
||||||
}
|
}
|
||||||
|
|
||||||
case msg @ SpawnRequestMessage(u1, u2, u3, u4, u5) =>
|
case msg @ SpawnRequestMessage(u1, spawn_type, u3, u4, zone_number) =>
|
||||||
log.info(s"SpawnRequestMessage: $msg")
|
log.info(s"SpawnRequestMessage: $msg")
|
||||||
//TODO just focus on u5 and u2 for now
|
cluster ! Zone.Lattice.RequestSpawnPoint(zone_number.toInt, player, spawn_type.id.toInt)
|
||||||
cluster ! Zone.Lattice.RequestSpawnPoint(u5.toInt, player, u2.toInt)
|
|
||||||
|
|
||||||
case msg @ SetChatFilterMessage(send_channel, origin, whitelist) =>
|
case msg @ SetChatFilterMessage(send_channel, origin, whitelist) =>
|
||||||
//log.info("SetChatFilters: " + msg)
|
//log.info("SetChatFilters: " + msg)
|
||||||
|
|
@ -3098,11 +3138,17 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
if(shooting.isEmpty) {
|
if(shooting.isEmpty) {
|
||||||
FindEquipment match {
|
FindEquipment match {
|
||||||
case Some(tool : Tool) =>
|
case Some(tool : Tool) =>
|
||||||
if(tool.Magazine > 0) {
|
if(tool.Magazine > 0 || prefire.contains(item_guid)) {
|
||||||
|
prefire = None
|
||||||
shooting = Some(item_guid)
|
shooting = Some(item_guid)
|
||||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Start(player.GUID, item_guid))
|
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Start(player.GUID, item_guid))
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
log.warn(s"ChangeFireState_Start: ${tool.Definition.Name} magazine is empty before trying to shoot bullet")
|
||||||
|
EmptyMagazine(item_guid, tool)
|
||||||
|
}
|
||||||
case Some(_) => //permissible, for now
|
case Some(_) => //permissible, for now
|
||||||
|
prefire = None
|
||||||
shooting = Some(item_guid)
|
shooting = Some(item_guid)
|
||||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Start(player.GUID, item_guid))
|
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Start(player.GUID, item_guid))
|
||||||
case None =>
|
case None =>
|
||||||
|
|
@ -3112,6 +3158,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
|
|
||||||
case msg @ ChangeFireStateMessage_Stop(item_guid) =>
|
case msg @ ChangeFireStateMessage_Stop(item_guid) =>
|
||||||
log.info("ChangeFireState_Stop: " + msg)
|
log.info("ChangeFireState_Stop: " + msg)
|
||||||
|
prefire = None
|
||||||
val weapon : Option[Equipment] = if(shooting.contains(item_guid)) {
|
val weapon : Option[Equipment] = if(shooting.contains(item_guid)) {
|
||||||
shooting = None
|
shooting = None
|
||||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Stop(player.GUID, item_guid))
|
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Stop(player.GUID, item_guid))
|
||||||
|
|
@ -3715,7 +3762,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
if(owned) {
|
if(owned) {
|
||||||
if(tdef.isInstanceOf[MatrixTerminalDefinition]) {
|
if(tdef.isInstanceOf[MatrixTerminalDefinition]) {
|
||||||
//TODO matrix spawn point; for now, just blindly bind to show work (and hope nothing breaks)
|
//TODO matrix spawn point; for now, just blindly bind to show work (and hope nothing breaks)
|
||||||
sendResponse(BindPlayerMessage(1, "@ams", true, true, 0, 0, 0, terminal.Position))
|
sendResponse(BindPlayerMessage(BindStatus.Bind, "", true, true, SpawnGroup.Sanctuary, 0, 0, terminal.Position))
|
||||||
}
|
}
|
||||||
else if(tdef.isInstanceOf[RepairRearmSiloDefinition]) {
|
else if(tdef.isInstanceOf[RepairRearmSiloDefinition]) {
|
||||||
FindLocalVehicle match {
|
FindLocalVehicle match {
|
||||||
|
|
@ -3915,12 +3962,15 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case msg @ ItemTransactionMessage(terminal_guid, _, _, _, _, _) =>
|
case msg @ ItemTransactionMessage(terminal_guid, transaction_type, _, _, _, _) =>
|
||||||
log.info("ItemTransaction: " + msg)
|
log.info("ItemTransaction: " + msg)
|
||||||
continent.GUID(terminal_guid) match {
|
continent.GUID(terminal_guid) match {
|
||||||
case Some(term : Terminal) =>
|
case Some(term : Terminal) =>
|
||||||
log.info(s"ItemTransaction: ${term.Definition.Name} found")
|
log.info(s"ItemTransaction: ${term.Definition.Name} found")
|
||||||
|
if(lastTerminalOrderFulfillment) {
|
||||||
|
lastTerminalOrderFulfillment = false
|
||||||
term.Actor ! Terminal.Request(player, msg)
|
term.Actor ! Terminal.Request(player, msg)
|
||||||
|
}
|
||||||
case Some(obj : PlanetSideGameObject) =>
|
case Some(obj : PlanetSideGameObject) =>
|
||||||
log.error(s"ItemTransaction: $obj is not a terminal")
|
log.error(s"ItemTransaction: $obj is not a terminal")
|
||||||
case _ =>
|
case _ =>
|
||||||
|
|
@ -3984,14 +4034,11 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
FindContainedWeapon match {
|
FindContainedWeapon match {
|
||||||
case (Some(obj), Some(tool : Tool)) =>
|
case (Some(obj), Some(tool : Tool)) =>
|
||||||
if(tool.Magazine <= 0) { //safety: enforce ammunition depletion
|
if(tool.Magazine <= 0) { //safety: enforce ammunition depletion
|
||||||
tool.Magazine = 0
|
prefire = None
|
||||||
sendResponse(InventoryStateMessage(tool.AmmoSlot.Box.GUID, weapon_guid, 0))
|
EmptyMagazine(weapon_guid, tool)
|
||||||
sendResponse(ChangeFireStateMessage_Stop(weapon_guid))
|
|
||||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Stop(player.GUID, weapon_guid))
|
|
||||||
sendResponse(WeaponDryFireMessage(weapon_guid))
|
|
||||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.WeaponDryFire(player.GUID, weapon_guid))
|
|
||||||
}
|
}
|
||||||
else { //shooting
|
else { //shooting
|
||||||
|
prefire = shooting.orElse(Some(weapon_guid))
|
||||||
tool.Discharge
|
tool.Discharge
|
||||||
val projectileIndex = projectile_guid.guid - Projectile.BaseUID
|
val projectileIndex = projectile_guid.guid - Projectile.BaseUID
|
||||||
val projectilePlace = projectiles(projectileIndex)
|
val projectilePlace = projectiles(projectileIndex)
|
||||||
|
|
@ -3999,7 +4046,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
case Some(projectile) => !projectile.isResolved
|
case Some(projectile) => !projectile.isResolved
|
||||||
case None => false
|
case None => false
|
||||||
}) {
|
}) {
|
||||||
log.warn(s"WeaponFireMessage: former projectile ${projectile_guid.guid} was not resolved properly; overwriting anyway")
|
log.trace(s"WeaponFireMessage: overwriting unresolved projectile ${projectile_guid.guid}")
|
||||||
}
|
}
|
||||||
val (angle, attribution) = obj match {
|
val (angle, attribution) = obj match {
|
||||||
case p : Player =>
|
case p : Player =>
|
||||||
|
|
@ -4023,12 +4070,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
(hit_info match {
|
(hit_info match {
|
||||||
case Some(hitInfo) =>
|
case Some(hitInfo) =>
|
||||||
continent.GUID(hitInfo.hitobject_guid) match {
|
continent.GUID(hitInfo.hitobject_guid) match {
|
||||||
case Some(obj : Player) =>
|
case Some(target : PlanetSideGameObject with FactionAffinity with Vitality) =>
|
||||||
Some((obj, hitInfo.shot_origin, hitInfo.hit_pos))
|
Some((target, hitInfo.shot_origin, hitInfo.hit_pos))
|
||||||
case Some(obj : Vehicle) =>
|
|
||||||
Some((obj, hitInfo.shot_origin, hitInfo.hit_pos))
|
|
||||||
case Some(obj : PlanetSideGameObject with Deployable) =>
|
|
||||||
Some((obj, hitInfo.shot_origin, hitInfo.hit_pos))
|
|
||||||
case _ =>
|
case _ =>
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -4048,7 +4091,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
log.info(s"Splash: $msg")
|
log.info(s"Splash: $msg")
|
||||||
continent.GUID(direct_victim_uid) match {
|
continent.GUID(direct_victim_uid) match {
|
||||||
case Some(target : PlanetSideGameObject with FactionAffinity with Vitality) =>
|
case Some(target : PlanetSideGameObject with FactionAffinity with Vitality) =>
|
||||||
ResolveProjectileEntry(projectile_guid, ProjectileResolution.Hit, target, explosion_pos) match {
|
ResolveProjectileEntry(projectile_guid, ProjectileResolution.Splash, target, target.Position) match {
|
||||||
case Some(projectile) =>
|
case Some(projectile) =>
|
||||||
HandleDealingDamage(target, projectile)
|
HandleDealingDamage(target, projectile)
|
||||||
case None => ;
|
case None => ;
|
||||||
|
|
@ -4058,7 +4101,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
targets.foreach(elem => {
|
targets.foreach(elem => {
|
||||||
continent.GUID(elem.uid) match {
|
continent.GUID(elem.uid) match {
|
||||||
case Some(target : PlanetSideGameObject with FactionAffinity with Vitality) =>
|
case Some(target : PlanetSideGameObject with FactionAffinity with Vitality) =>
|
||||||
ResolveProjectileEntry(projectile_guid, ProjectileResolution.Splash, target, target.Position) match {
|
ResolveProjectileEntry(projectile_guid, ProjectileResolution.Splash, target, explosion_pos) match {
|
||||||
case Some(projectile) =>
|
case Some(projectile) =>
|
||||||
HandleDealingDamage(target, projectile)
|
HandleDealingDamage(target, projectile)
|
||||||
case None => ;
|
case None => ;
|
||||||
|
|
@ -4273,12 +4316,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
log.info("FriendsRequest: "+msg)
|
log.info("FriendsRequest: "+msg)
|
||||||
|
|
||||||
case msg @ HitHint(source_guid, player_guid) =>
|
case msg @ HitHint(source_guid, player_guid) =>
|
||||||
log.info(s"HitHint: $msg")
|
log.trace(s"HitHint: $msg") //HitHint is manually distributed for proper operation
|
||||||
continent.GUID(player_guid) match {
|
|
||||||
case Some(obj : Player) =>
|
|
||||||
avatarService ! AvatarServiceMessage(obj.Name, AvatarAction.HitHint(source_guid, player_guid))
|
|
||||||
case _ => ;
|
|
||||||
}
|
|
||||||
|
|
||||||
case msg @ TargetingImplantRequest(list) =>
|
case msg @ TargetingImplantRequest(list) =>
|
||||||
log.info("TargetingImplantRequest: "+msg)
|
log.info("TargetingImplantRequest: "+msg)
|
||||||
|
|
@ -4289,7 +4327,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
case default => log.error(s"Unhandled GamePacket $pkt")
|
case default => log.error(s"Unhandled GamePacket $pkt")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterate over a group of `EquipmentSlot`s, some of which may be occupied with an item.
|
* Iterate over a group of `EquipmentSlot`s, some of which may be occupied with an item.
|
||||||
* Remove any encountered items and add them to an output `List`.
|
* Remove any encountered items and add them to an output `List`.
|
||||||
|
|
@ -5343,8 +5380,12 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
case obj : Vehicle =>
|
case obj : Vehicle =>
|
||||||
vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.UnstowEquipment(player_guid, item2_guid))
|
vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.UnstowEquipment(player_guid, item2_guid))
|
||||||
case obj : Player =>
|
case obj : Player =>
|
||||||
if(obj.isBackpack || destination.VisibleSlots.contains(dest)) { //corpse being looted, or item was in hands
|
if(obj.isBackpack || destination.VisibleSlots.contains(dest)) { //corpse being looted, or item was accessible
|
||||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, item2_guid))
|
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, item2_guid))
|
||||||
|
//put hand down locally
|
||||||
|
if(dest == player.DrawnSlot) {
|
||||||
|
player.DrawnSlot = Player.HandsDownSlot
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
@ -5794,10 +5835,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
|
|
||||||
def ClearCurrentAmsSpawnPoint() : Unit = {
|
def ClearCurrentAmsSpawnPoint() : Unit = {
|
||||||
amsSpawnPoint match {
|
amsSpawnPoint match {
|
||||||
case Some(_) =>
|
case Some(tube) =>
|
||||||
sendResponse(
|
sendResponse(BindPlayerMessage(BindStatus.Unavailable, "@ams", true, false, SpawnGroup.AMS, continent.Number, 0, Vector3.Zero))
|
||||||
BattleplanMessage(41378949, "ams", continent.Number, List(BattleDiagramAction(DiagramActionCode.StopDrawing)))
|
|
||||||
)
|
|
||||||
amsSpawnPoint = None
|
amsSpawnPoint = None
|
||||||
case None => ;
|
case None => ;
|
||||||
}
|
}
|
||||||
|
|
@ -6013,6 +6052,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
def PlayerActionsToCancel() : Unit = {
|
def PlayerActionsToCancel() : Unit = {
|
||||||
progressBarUpdate.cancel
|
progressBarUpdate.cancel
|
||||||
progressBarValue = None
|
progressBarValue = None
|
||||||
|
lastTerminalOrderFulfillment = true
|
||||||
accessedContainer match {
|
accessedContainer match {
|
||||||
case Some(obj : Vehicle) =>
|
case Some(obj : Vehicle) =>
|
||||||
if(obj.AccessingTrunk.contains(player.GUID)) {
|
if(obj.AccessingTrunk.contains(player.GUID)) {
|
||||||
|
|
@ -6030,6 +6070,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
case Some(guid) =>
|
case Some(guid) =>
|
||||||
sendResponse(ChangeFireStateMessage_Stop(guid))
|
sendResponse(ChangeFireStateMessage_Stop(guid))
|
||||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Stop(player.GUID, guid))
|
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Stop(player.GUID, guid))
|
||||||
|
prefire = None
|
||||||
shooting = None
|
shooting = None
|
||||||
case None => ;
|
case None => ;
|
||||||
}
|
}
|
||||||
|
|
@ -6051,8 +6092,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
def AvatarCreate() : Unit = {
|
def AvatarCreate() : Unit = {
|
||||||
player.VehicleSeated = None //TODO temp, until vehicle gating; unseat player else constructor data is messed up
|
player.VehicleSeated = None //TODO temp, until vehicle gating; unseat player else constructor data is messed up
|
||||||
player.Spawn
|
player.Spawn
|
||||||
player.Health = 50 //TODO temp
|
player.Health = 100
|
||||||
player.Armor = 25
|
player.Armor = 50
|
||||||
val packet = player.Definition.Packet
|
val packet = player.Definition.Packet
|
||||||
val dcdata = packet.DetailedConstructorData(player).get
|
val dcdata = packet.DetailedConstructorData(player).get
|
||||||
val player_guid = player.GUID
|
val player_guid = player.GUID
|
||||||
|
|
@ -6555,6 +6596,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
case obj : Deployable =>
|
case obj : Deployable =>
|
||||||
//damage is synchronized on `LSA` (results returned to and distributed from this `WSA`)
|
//damage is synchronized on `LSA` (results returned to and distributed from this `WSA`)
|
||||||
localService ! Vitality.DamageOn(obj, func)
|
localService ! Vitality.DamageOn(obj, func)
|
||||||
|
case obj : FacilityTurret =>
|
||||||
|
//damage is synchronized on the turret actor (results returned to and distributed from this `WSA`)
|
||||||
|
obj.Actor ! Vitality.Damage(func)
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7419,7 +7463,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
val sguid = src.GUID
|
val sguid = src.GUID
|
||||||
val dguid = dest.GUID
|
val dguid = dest.GUID
|
||||||
StartBundlingPackets()
|
StartBundlingPackets()
|
||||||
sendResponse(PlayerStateShiftMessage(ShiftState(0, dest.Position, player.Orientation.z, player.Velocity)))
|
sendResponse(PlayerStateShiftMessage(ShiftState(0, dest.Position, player.Orientation.z)))
|
||||||
UseRouterTelepadEffect(pguid, sguid, dguid)
|
UseRouterTelepadEffect(pguid, sguid, dguid)
|
||||||
StopBundlingPackets()
|
StopBundlingPackets()
|
||||||
// vehicleService ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(router), continent))
|
// vehicleService ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(router), continent))
|
||||||
|
|
@ -7473,6 +7517,100 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For a certain weapon that cna load ammunition, enforce that its magazine is empty.
|
||||||
|
* @param weapon_guid the weapon
|
||||||
|
*/
|
||||||
|
def EmptyMagazine(weapon_guid : PlanetSideGUID) : Unit = {
|
||||||
|
continent.GUID(weapon_guid) match {
|
||||||
|
case Some(tool : Tool) =>
|
||||||
|
EmptyMagazine(weapon_guid, tool)
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For a certain weapon that cna load ammunition, enforce that its magazine is empty.
|
||||||
|
* Punctuate that emptiness with a ceasation of weapons fire and a dry fire sound effect.
|
||||||
|
* @param weapon_guid the weapon (GUID)
|
||||||
|
* @param tool the weapon (object)
|
||||||
|
*/
|
||||||
|
def EmptyMagazine(weapon_guid : PlanetSideGUID, tool : Tool) : Unit = {
|
||||||
|
tool.Magazine = 0
|
||||||
|
sendResponse(InventoryStateMessage(tool.AmmoSlot.Box.GUID, weapon_guid, 0))
|
||||||
|
sendResponse(ChangeFireStateMessage_Stop(weapon_guid))
|
||||||
|
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Stop(player.GUID, weapon_guid))
|
||||||
|
sendResponse(WeaponDryFireMessage(weapon_guid))
|
||||||
|
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.WeaponDryFire(player.GUID, weapon_guid))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* na
|
||||||
|
* @param player_guid the player that ...
|
||||||
|
* @param cargoGUID the globally unique number for the vehicle being ferried
|
||||||
|
* @param cargo the vehicle being ferried
|
||||||
|
* @param carrierGUID the globally unique number for the vehicle doing the ferrying
|
||||||
|
* @param carrier the vehicle doing the ferrying
|
||||||
|
* @param bailed the ferried vehicle is bailing from the cargo hold
|
||||||
|
* @param requestedByPassenger the ferried vehicle is being politely disembarked from the cargo hold
|
||||||
|
* @param kicked the ferried vehicle is being kicked out of the cargo hold
|
||||||
|
*/
|
||||||
|
def HandleDismountVehicleCargo(player_guid : PlanetSideGUID, cargoGUID : PlanetSideGUID, cargo : Vehicle, carrierGUID : PlanetSideGUID, carrier : Vehicle, bailed : Boolean, requestedByPassenger : Boolean, kicked : Boolean) : Unit = {
|
||||||
|
carrier.CargoHolds.find({case((_, hold)) => hold.Occupant.contains(cargo)}) match {
|
||||||
|
case Some((mountPoint, hold)) =>
|
||||||
|
StartBundlingPackets()
|
||||||
|
val cargoStatusMessage = CargoMountPointStatusMessage(cargoGUID, PlanetSideGUID(0), PlanetSideGUID(0), carrierGUID, mountPoint, CargoStatus.InProgress, 0)
|
||||||
|
log.debug(cargoStatusMessage.toString)
|
||||||
|
sendResponse(cargoStatusMessage) //dismount vehicle on UI and disable "shield" effect on lodestar
|
||||||
|
val dismount_position = if(bailed || kicked) { //if we're bailing drop the vehicle below the cargo vehicle
|
||||||
|
//TODO: ensure vehicles aren't dropped below the world
|
||||||
|
cargo.Position - Vector3.z(1)
|
||||||
|
}
|
||||||
|
else if(cargo.Definition == GlobalDefinitions.dropship) { //the galaxy cargo bay is offset backwards from the center of the vehicle
|
||||||
|
Vector3(cargo.Position.x, cargo.Position.y - 7f, cargo.Position.z + 2f)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cargo.Position + Vector3.z(2)
|
||||||
|
}
|
||||||
|
//TODO: BFRs will likely also need this set
|
||||||
|
val sideways = cargo.Definition == GlobalDefinitions.router
|
||||||
|
val rotation = if(sideways) {
|
||||||
|
(cargo.Orientation.z - 90) % 360 //dismount router "sideways" in a lodestar
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cargo.Orientation.z
|
||||||
|
}
|
||||||
|
val detachMessage = ObjectDetachMessage(carrierGUID, cargoGUID, dismount_position, carrier.Orientation.x, carrier.Orientation.y, rotation)
|
||||||
|
log.debug(detachMessage.toString)
|
||||||
|
sendResponse(detachMessage)
|
||||||
|
vehicleService ! VehicleServiceMessage(s"${cargo.Actor}", VehicleAction.SendResponse(PlanetSideGUID(0), PlanetsideAttributeMessage(cargoGUID, 0, cargo.Health)))
|
||||||
|
vehicleService ! VehicleServiceMessage(s"${cargo.Actor}", VehicleAction.SendResponse(PlanetSideGUID(0), PlanetsideAttributeMessage(cargoGUID, 68, cargo.Shields)))
|
||||||
|
cargo.MountedIn = None
|
||||||
|
hold.Occupant = None
|
||||||
|
if(!bailed) {
|
||||||
|
// Automatically drive the vehicle backwards out of the cargo bay
|
||||||
|
if(!sideways) {
|
||||||
|
ServerVehicleLockReverse()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ServerVehicleLockStrafeLeft()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//todo: proper vehicle bailing. It works currently but when collision damage is implemented the vehicle will take damage if not in a bail state. Need to confirm how this is done with further research
|
||||||
|
}
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
|
// Start a timer to check every second if the vehicle has moved far enough away to be considered dismounted, and then close the cargo door
|
||||||
|
cargoDismountTimer = context.system.scheduler.scheduleOnce(250 milliseconds, self, CheckCargoDismount(cargoGUID, carrierGUID, mountPoint, iteration = 0))
|
||||||
|
StopBundlingPackets()
|
||||||
|
//sync to other clients
|
||||||
|
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.SendResponse(player.GUID, cargoStatusMessage))
|
||||||
|
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.SendResponse(player.GUID, detachMessage))
|
||||||
|
case None => ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def failWithError(error : String) = {
|
def failWithError(error : String) = {
|
||||||
log.error(error)
|
log.error(error)
|
||||||
sendResponse(ConnectionClose())
|
sendResponse(ConnectionClose())
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue