From aec9c15bdd26f311721649747e7706a75ea95f24 Mon Sep 17 00:00:00 2001 From: Mazo Date: Thu, 31 Oct 2019 02:43:40 +0000 Subject: [PATCH] Advanced medical + other bits (#287) * Allow medical applicator to revive players * Allow dead players to be repaired * Refactoring medapp + bank usage * Make bank + medapp use charges from magazine * Don't try to heal/repair other players with MaxHealth/MaxArmor <= 0 * Ignore tool use on SpawnTube objects (for example; don't deconstruct from using a medical applicator on a spawn tube) --- .../scala/net/psforever/objects/Player.scala | 9 +- .../packet/game/AvatarDeadStateMessage.scala | 2 +- .../scala/services/avatar/AvatarService.scala | 12 ++ .../avatar/AvatarServiceMessage.scala | 3 + .../avatar/AvatarServiceResponse.scala | 3 + .../src/main/scala/WorldSessionActor.scala | 149 ++++++++---------- 6 files changed, 92 insertions(+), 86 deletions(-) diff --git a/common/src/main/scala/net/psforever/objects/Player.scala b/common/src/main/scala/net/psforever/objects/Player.scala index 09e261c2..aadc5008 100644 --- a/common/src/main/scala/net/psforever/objects/Player.scala +++ b/common/src/main/scala/net/psforever/objects/Player.scala @@ -99,6 +99,11 @@ class Player(private val core : Avatar) extends PlanetSideGameObject false } + def Revive : Boolean = { + alive = true + true + } + def Release : Boolean = { if(!isAlive) { backpack = true @@ -112,7 +117,7 @@ class Player(private val core : Avatar) extends PlanetSideGameObject def Health : Int = health def Health_=(assignHealth : Int) : Int = { - health = if(isAlive) { math.min(math.max(0, assignHealth), MaxHealth) } else { 0 } + health = math.min(math.max(0, assignHealth), MaxHealth) Health } @@ -140,7 +145,7 @@ class Player(private val core : Avatar) extends PlanetSideGameObject def Armor : Int = armor def Armor_=(assignArmor : Int) : Int = { - armor = if(isAlive) { math.min(math.max(0, assignArmor), MaxArmor) } else { 0 } + armor = math.min(math.max(0, assignArmor), MaxArmor) Armor } diff --git a/common/src/main/scala/net/psforever/packet/game/AvatarDeadStateMessage.scala b/common/src/main/scala/net/psforever/packet/game/AvatarDeadStateMessage.scala index 5e17f544..ecec3b63 100644 --- a/common/src/main/scala/net/psforever/packet/game/AvatarDeadStateMessage.scala +++ b/common/src/main/scala/net/psforever/packet/game/AvatarDeadStateMessage.scala @@ -92,7 +92,7 @@ object AvatarDeadStateMessage extends Marshallable[AvatarDeadStateMessage] { ("timer_max" | uint32L) :: ("timer" | uint32L) :: ("pos" | Vector3.codec_pos) :: - ("unk4" | factionLongCodec) :: + ("faction" | factionLongCodec) :: ("unk5" | bool) ).as[AvatarDeadStateMessage] } diff --git a/common/src/main/scala/services/avatar/AvatarService.scala b/common/src/main/scala/services/avatar/AvatarService.scala index 0e5bf3e0..4249a0d7 100644 --- a/common/src/main/scala/services/avatar/AvatarService.scala +++ b/common/src/main/scala/services/avatar/AvatarService.scala @@ -139,6 +139,10 @@ class AvatarService extends Actor { AvatarEvents.publish( AvatarServiceResponse(s"/$forChannel/Avatar", guid, AvatarResponse.PlanetsideAttribute(attribute_type, attribute_value)) ) + case AvatarAction.PlanetsideAttributeToAll(guid, attribute_type, attribute_value) => + AvatarEvents.publish( + AvatarServiceResponse(s"/$forChannel/Avatar", guid, AvatarResponse.PlanetsideAttributeToAll(attribute_type, attribute_value)) + ) case AvatarAction.PlanetsideAttributeSelf(guid, attribute_type, attribute_value) => AvatarEvents.publish( AvatarServiceResponse(s"/$forChannel/Avatar", guid, AvatarResponse.PlanetsideAttributeSelf(attribute_type, attribute_value)) @@ -192,6 +196,14 @@ class AvatarService extends Actor { AvatarEvents.publish( AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.SendResponse(msg)) ) + case AvatarAction.SendResponseTargeted(target_guid, msg) => + AvatarEvents.publish( + AvatarServiceResponse(s"/$forChannel/Avatar", target_guid, AvatarResponse.SendResponseTargeted(target_guid, msg)) + ) + case AvatarAction.Revive(target_guid) => + AvatarEvents.publish( + AvatarServiceResponse(s"/$forChannel/Avatar", target_guid, AvatarResponse.Revive(target_guid)) + ) case _ => ; } diff --git a/common/src/main/scala/services/avatar/AvatarServiceMessage.scala b/common/src/main/scala/services/avatar/AvatarServiceMessage.scala index 3c89ab06..636d56de 100644 --- a/common/src/main/scala/services/avatar/AvatarServiceMessage.scala +++ b/common/src/main/scala/services/avatar/AvatarServiceMessage.scala @@ -43,17 +43,20 @@ object AvatarAction { final case class ObjectDelete(player_guid : PlanetSideGUID, item_guid : PlanetSideGUID, unk : Int = 0) extends Action final case class ObjectHeld(player_guid : PlanetSideGUID, slot : Int) extends Action final case class PlanetsideAttribute(player_guid : PlanetSideGUID, attribute_type : Int, attribute_value : Long) extends Action + final case class PlanetsideAttributeToAll(player_guid : PlanetSideGUID, attribute_type : Int, attribute_value : Long) extends Action final case class PlanetsideAttributeSelf(player_guid : PlanetSideGUID, attribute_type : Int, attribute_value : Long) extends Action final case class PlayerState(player_guid : PlanetSideGUID, pos : Vector3, vel : Option[Vector3], facingYaw : Float, facingPitch : Float, facingYawUpper : Float, timestamp : Int, is_crouching : Boolean, is_jumping : Boolean, jump_thrust : Boolean, is_cloaked : Boolean, spectator : Boolean, weaponInHand : Boolean) extends Action final case class PickupItem(player_guid : PlanetSideGUID, zone : Zone, target : PlanetSideGameObject with Container, slot : Int, item : Equipment, unk : Int = 0) extends Action final case class PutDownFDU(player_guid : PlanetSideGUID) extends Action final case class Release(player : Player, zone : Zone, time : Option[FiniteDuration] = None) extends Action + final case class Revive(target_guid: PlanetSideGUID) extends Action final case class Reload(player_guid : PlanetSideGUID, weapon_guid : PlanetSideGUID) extends Action final case class SetEmpire(player_guid : PlanetSideGUID, object_guid : PlanetSideGUID, faction : PlanetSideEmpire.Value) extends Action final case class StowEquipment(player_guid : PlanetSideGUID, target_guid : PlanetSideGUID, slot : Int, item : Equipment) extends Action final case class WeaponDryFire(player_guid : PlanetSideGUID, weapon_guid : PlanetSideGUID) extends Action final case class SendResponse(player_guid: PlanetSideGUID, msg: PlanetSideGamePacket) extends Action + final case class SendResponseTargeted(target_guid: PlanetSideGUID, msg: PlanetSideGamePacket) extends Action // final case class PlayerStateShift(killer : PlanetSideGUID, victim : PlanetSideGUID) extends Action // final case class DestroyDisplay(killer : PlanetSideGUID, victim : PlanetSideGUID) extends Action diff --git a/common/src/main/scala/services/avatar/AvatarServiceResponse.scala b/common/src/main/scala/services/avatar/AvatarServiceResponse.scala index 5ce1c402..40481db8 100644 --- a/common/src/main/scala/services/avatar/AvatarServiceResponse.scala +++ b/common/src/main/scala/services/avatar/AvatarServiceResponse.scala @@ -36,15 +36,18 @@ object AvatarResponse { final case class ObjectDelete(item_guid : PlanetSideGUID, unk : Int) extends Response final case class ObjectHeld(slot : Int) extends Response final case class PlanetsideAttribute(attribute_type : Int, attribute_value : Long) extends Response + final case class PlanetsideAttributeToAll(attribute_type : Int, attribute_value : Long) extends Response final case class PlanetsideAttributeSelf(attribute_type : Int, attribute_value : Long) extends Response final case class PlayerState(pos : Vector3, vel : Option[Vector3], facingYaw : Float, facingPitch : Float, facingYawUpper : Float, timestamp : Int, is_crouching : Boolean, is_jumping : Boolean, jump_thrust : Boolean, is_cloaked : Boolean, spectator : Boolean, weaponInHand : Boolean) extends Response final case class PutDownFDU(target_guid : PlanetSideGUID) extends Response final case class Release(player : Player) extends Response final case class Reload(weapon_guid : PlanetSideGUID) extends Response + final case class Revive(target_guid: PlanetSideGUID) extends Response final case class SetEmpire(object_guid : PlanetSideGUID, faction : PlanetSideEmpire.Value) extends Response final case class StowEquipment(target_guid : PlanetSideGUID, slot : Int, item : Equipment) extends Response final case class WeaponDryFire(weapon_guid : PlanetSideGUID) extends Response final case class SendResponse(msg: PlanetSideGamePacket) extends Response + final case class SendResponseTargeted(target_guid : PlanetSideGUID, msg: PlanetSideGamePacket) extends Response // final case class PlayerStateShift(itemID : PlanetSideGUID) extends Response } diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala index 4ef67f99..ceebb292 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -1234,6 +1234,18 @@ class WorldSessionActor extends Actor with MDCContextAware { case AvatarResponse.SendResponse(msg) => sendResponse(msg) + case AvatarResponse.SendResponseTargeted(target_guid, msg) => + if(tplayer_guid == target_guid) { + sendResponse(msg) + } + + case AvatarResponse.Revive(target_guid) => + if(tplayer_guid == target_guid) { + deadState = DeadState.Alive + reviveTimer.cancel + sendResponse(AvatarDeadStateMessage(DeadState.Alive, 0, 0, player.Position, player.Faction, true)) + } + case AvatarResponse.ArmorChanged(suit, subtype) => if(tplayer_guid != guid) { sendResponse(ArmorChangedMessage(guid, suit, subtype)) @@ -1405,6 +1417,9 @@ class WorldSessionActor extends Actor with MDCContextAware { sendResponse(PlanetsideAttributeMessage(guid, attribute_type, attribute_value)) } + case AvatarResponse.PlanetsideAttributeToAll(attribute_type, attribute_value) => + sendResponse(PlanetsideAttributeMessage(guid, attribute_type, attribute_value)) + case AvatarResponse.PlanetsideAttributeSelf(attribute_type, attribute_value) => if (tplayer_guid == guid) { sendResponse(PlanetsideAttributeMessage(guid, attribute_type, attribute_value)) @@ -4853,89 +4868,54 @@ class WorldSessionActor extends Actor with MDCContextAware { log.warn(s"UseItem: anticipated a Kit $item_used_guid, but can't find it") } } - else if (itemType == 121 && unk3) { + else if (itemType == ObjectClass.avatar && unk3) { FindWeapon match { case Some(tool: Tool) => - if (tool.Definition.ObjectId == 132) { - // TODO : bank ? + if (tool.Definition == GlobalDefinitions.bank) { continent.GUID(object_guid) match { case Some(tplayer: Player) => - if (player.GUID != tplayer.GUID && Vector3.Distance(player.Position, tplayer.Position) < 5 && player.Faction == tplayer.Faction && player.Velocity.isEmpty) { - if (tplayer.MaxArmor - tplayer.Armor <= 15) { - tplayer.Armor = tplayer.MaxArmor - // sendResponse(QuantityUpdateMessage(PlanetSideGUID(8214),ammo_quantity_left)) - val RepairPercent: Int = tplayer.Armor * 100 / tplayer.MaxArmor - sendResponse(RepairMessage(object_guid, RepairPercent)) - avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.PlanetsideAttributeSelf(tplayer.GUID, 4, tplayer.Armor)) - avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.PlanetsideAttribute(tplayer.GUID, 4, tplayer.Armor)) - } - if (tplayer.MaxArmor - tplayer.Armor > 15) { - tplayer.Armor += 15 - // sendResponse(QuantityUpdateMessage(PlanetSideGUID(8214),ammo_quantity_left)) - val RepairPercent: Int = tplayer.Armor * 100 / tplayer.MaxArmor - sendResponse(RepairMessage(object_guid, RepairPercent)) - avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.PlanetsideAttributeSelf(tplayer.GUID, 4, tplayer.Armor)) - avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.PlanetsideAttribute(tplayer.GUID, 4, tplayer.Armor)) - } - } else if (player.GUID == object_guid && player.Velocity.isEmpty) { - if (player.MaxArmor - player.Armor <= 15) { - player.Armor = player.MaxArmor - // sendResponse(QuantityUpdateMessage(PlanetSideGUID(8214),ammo_quantity_left)) -// sendResponse(RepairMessage(object_guid, player.Armor)) // Todo is that needed ? - sendResponse(PlanetsideAttributeMessage(player.GUID, 4, player.Armor)) - avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.PlanetsideAttribute(player.GUID, 4, player.Armor)) - } - if (player.MaxArmor - player.Armor > 15) { - player.Armor += 15 - // sendResponse(QuantityUpdateMessage(PlanetSideGUID(8214),ammo_quantity_left)) -// sendResponse(RepairMessage(object_guid, player.Armor)) // Todo is that needed ? - sendResponse(PlanetsideAttributeMessage(player.GUID, 4, player.Armor)) - avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.PlanetsideAttribute(player.GUID, 4, player.Armor)) - } - } - case _ => ; - } - } else if (tool.Definition.ObjectId == 531) { - // TODO : med app ? - continent.GUID(object_guid) match { - case Some(tplayer: Player) => - if (player.GUID != tplayer.GUID && Vector3.Distance(player.Position, tplayer.Position) < 5 && player.Faction == tplayer.Faction && player.Velocity.isEmpty) { - if (tplayer.MaxHealth - tplayer.Health <= 10) { - tplayer.Health = tplayer.MaxHealth - // sendResponse(QuantityUpdateMessage(PlanetSideGUID(8214),ammo_quantity_left)) - val RepairPercent: Int = tplayer.Health * 100 / tplayer.MaxHealth - sendResponse(RepairMessage(object_guid, RepairPercent)) - avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.PlanetsideAttributeSelf(tplayer.GUID, 0, tplayer.Health)) - avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.PlanetsideAttribute(tplayer.GUID, 0, tplayer.Health)) - } - if (tplayer.MaxHealth - tplayer.Health > 10) { - tplayer.Health += 10 - // sendResponse(QuantityUpdateMessage(PlanetSideGUID(8214),ammo_quantity_left)) - val RepairPercent: Int = tplayer.Health * 100 / tplayer.MaxHealth - sendResponse(RepairMessage(object_guid, RepairPercent)) - avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.PlanetsideAttributeSelf(tplayer.GUID, 0, tplayer.Health)) - avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.PlanetsideAttribute(tplayer.GUID, 0, tplayer.Health)) - } - } - case _ => ; - } - if (player.GUID == object_guid && player.Velocity.isEmpty) { - if (player.MaxHealth - player.Health <= 10) { - player.Health = player.MaxHealth - // sendResponse(QuantityUpdateMessage(PlanetSideGUID(8214),ammo_quantity_left)) -// sendResponse(RepairMessage(object_guid, player.Health)) // Todo is that needed ? - sendResponse(PlanetsideAttributeMessage(player.GUID, 0, player.Health)) - avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.PlanetsideAttribute(player.GUID, 0, player.Health)) - } - if (player.MaxHealth - player.Health > 10) { - player.Health += 10 - // sendResponse(QuantityUpdateMessage(PlanetSideGUID(8214),ammo_quantity_left)) -// sendResponse(RepairMessage(object_guid, player.Health)) // Todo is that needed ? - sendResponse(PlanetsideAttributeMessage(player.GUID, 0, player.Health)) - avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.PlanetsideAttribute(player.GUID, 0, player.Health)) - } - } + if (player.GUID != tplayer.GUID && Vector3.Distance(player.Position, tplayer.Position) < 5 && player.Faction == tplayer.Faction && player.Velocity.isEmpty && tplayer.MaxArmor > 0) { + tplayer.Armor += 15 + tool.Discharge + sendResponse(InventoryStateMessage(tool.AmmoSlot.Box.GUID, obj.GUID, tool.Magazine)) + val RepairPercent: Int = tplayer.Armor * 100 / tplayer.MaxArmor + sendResponse(RepairMessage(object_guid, RepairPercent)) + avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.PlanetsideAttributeToAll(tplayer.GUID, 4, tplayer.Armor)) + } else if (player.GUID == tplayer.GUID && player.Velocity.isEmpty && tplayer.MaxArmor > 0) { + player.Armor += 15 + tool.Discharge + sendResponse(InventoryStateMessage(tool.AmmoSlot.Box.GUID, obj.GUID, tool.Magazine)) + avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.PlanetsideAttributeToAll(player.GUID, 4, player.Armor)) + } + case _ => ; + } + } else if (tool.Definition == GlobalDefinitions.medicalapplicator) { + continent.GUID(object_guid) match { + case Some(tplayer: Player) => + if (player.GUID != tplayer.GUID && Vector3.Distance(player.Position, tplayer.Position) < 5 && player.Faction == tplayer.Faction && player.Velocity.isEmpty && tplayer.MaxHealth > 0) { + tplayer.Health += 10 + tool.Discharge + sendResponse(InventoryStateMessage(tool.AmmoSlot.Box.GUID, obj.GUID, tool.Magazine)) + val repairPercent: Int = tplayer.Health * 100 / tplayer.MaxHealth + sendResponse(RepairMessage(object_guid, repairPercent)) + + if(!tplayer.isAlive && tplayer.Health == tplayer.MaxHealth) { + tplayer.Revive + avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.Revive(tplayer.GUID)) + } + + if(tplayer.isAlive) { + avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.PlanetsideAttributeToAll(tplayer.GUID, 0, tplayer.Health)) + } + } else if (player.GUID == tplayer.GUID && player.Velocity.isEmpty && tplayer.MaxHealth > 0) { + player.Health += 10 + tool.Discharge + sendResponse(InventoryStateMessage(tool.AmmoSlot.Box.GUID, obj.GUID, tool.Magazine)) + avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.PlanetsideAttributeToAll(player.GUID, 0, player.Health)) + } + case _ => ; + } } case None => ; } @@ -5160,11 +5140,14 @@ class WorldSessionActor extends Actor with MDCContextAware { } } case Some(obj : SpawnTube) => - //deconstruction - PlayerActionsToCancel() - CancelAllProximityUnits() - continent.Population ! Zone.Population.Release(avatar) - GoToDeploymentMap() + if(item_used_guid == PlanetSideGUID(0)) { // Ensure that we're not trying to use a tool on the spawn tube, e.g. medical applicator + //deconstruction + PlayerActionsToCancel() + CancelAllProximityUnits() + continent.Population ! Zone.Population.Release(avatar) + GoToDeploymentMap() + } + case Some(obj : TelepadDeployable) => continent.GUID(obj.Router) match {