No Stamina No Life (#1310)

* reverse order of protocol so that the avatar state (normal, csr) is checked first and then it calls back up to the specific avatar to perform the action

* reusing prior logic

* changed progress of damage inherit from 4->3->2->1->0 to [4,3,2]->1, 1->0
This commit is contained in:
Fate-JH 2025-10-02 01:30:55 -04:00 committed by GitHub
parent d5db167c35
commit abb71e9f53
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 54 additions and 18 deletions

View file

@ -10,6 +10,7 @@ import net.psforever.objects.PlanetSideGameObject
import net.psforever.objects.inventory.Container import net.psforever.objects.inventory.Container
import net.psforever.objects.serverobject.containable.ContainableBehavior import net.psforever.objects.serverobject.containable.ContainableBehavior
import net.psforever.objects.serverobject.mount.Mountable import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.vital.RevivingActivity
import net.psforever.packet.game.{AvatarImplantMessage, CreateShortcutMessage, ImplantAction} import net.psforever.packet.game.{AvatarImplantMessage, CreateShortcutMessage, ImplantAction}
import net.psforever.services.avatar.AvatarServiceResponse import net.psforever.services.avatar.AvatarServiceResponse
import net.psforever.types.ImplantType import net.psforever.types.ImplantType
@ -474,7 +475,7 @@ class AvatarHandlerLogic(val ops: SessionAvatarHandlers, implicit val context: A
player.FreeHand.Equipment.foreach(DropEquipmentFromInventory(player)(_)) player.FreeHand.Equipment.foreach(DropEquipmentFromInventory(player)(_))
AvatarActor.updateToolDischargeFor(avatar) AvatarActor.updateToolDischargeFor(avatar)
AvatarActor.savePlayerLocation(player) AvatarActor.savePlayerLocation(player)
ops.revive(player.GUID) ops.revive()
avatarActor ! AvatarActor.InitializeImplants avatarActor ! AvatarActor.InitializeImplants
//render //render
CustomerServiceRepresentativeMode.renderPlayer(sessionLogic, continent, player) CustomerServiceRepresentativeMode.renderPlayer(sessionLogic, continent, player)
@ -484,7 +485,17 @@ class AvatarHandlerLogic(val ops: SessionAvatarHandlers, implicit val context: A
case AvatarResponse.Revive(revivalTargetGuid) case AvatarResponse.Revive(revivalTargetGuid)
if resolvedPlayerGuid == revivalTargetGuid => if resolvedPlayerGuid == revivalTargetGuid =>
ops.revive(revivalTargetGuid) ops.revive()
player.Actor ! Player.Revive
player.History
.findLast { _.isInstanceOf[RevivingActivity] }
.map {
case activity: RevivingActivity
if System.currentTimeMillis() - activity.time < 5000L =>
val reviveMessage = s"@YouHaveBeenMessage^revived~^${activity.user.unique.name}~"
sendResponse(ChatMsg(ChatMessageType.UNK_227, reviveMessage))
None
}
/* uncommon messages (utility, or once in a while) */ /* uncommon messages (utility, or once in a while) */
case AvatarResponse.ChangeAmmo(weapon_guid, weapon_slot, previous_guid, ammo_id, ammo_guid, ammo_data) case AvatarResponse.ChangeAmmo(weapon_guid, weapon_slot, previous_guid, ammo_id, ammo_guid, ammo_data)

View file

@ -9,6 +9,7 @@ import net.psforever.objects.{Default, PlanetSideGameObject}
import net.psforever.objects.serverobject.containable.ContainableBehavior import net.psforever.objects.serverobject.containable.ContainableBehavior
import net.psforever.objects.serverobject.mount.Mountable import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.sourcing.PlayerSource import net.psforever.objects.sourcing.PlayerSource
import net.psforever.objects.vital.RevivingActivity
import net.psforever.objects.vital.interaction.Adversarial import net.psforever.objects.vital.interaction.Adversarial
import net.psforever.packet.game.{AvatarImplantMessage, CreateShortcutMessage, ImplantAction, PlanetsideStringAttributeMessage} import net.psforever.packet.game.{AvatarImplantMessage, CreateShortcutMessage, ImplantAction, PlanetsideStringAttributeMessage}
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
@ -592,7 +593,17 @@ class AvatarHandlerLogic(val ops: SessionAvatarHandlers, implicit val context: A
case AvatarResponse.Revive(revivalTargetGuid) case AvatarResponse.Revive(revivalTargetGuid)
if resolvedPlayerGuid == revivalTargetGuid => if resolvedPlayerGuid == revivalTargetGuid =>
log.info(s"No time for rest, ${player.Name}. Back on your feet!") log.info(s"No time for rest, ${player.Name}. Back on your feet!")
ops.revive(revivalTargetGuid) ops.revive()
player.Actor ! Player.Revive
player.History
.findLast { _.isInstanceOf[RevivingActivity] }
.map {
case activity: RevivingActivity
if System.currentTimeMillis() - activity.time < 5000L =>
val reviveMessage = s"@YouHaveBeenMessage^revived~^${activity.user.unique.name}~"
sendResponse(ChatMsg(ChatMessageType.UNK_227, reviveMessage))
None
}
/* uncommon messages (utility, or once in a while) */ /* uncommon messages (utility, or once in a while) */
case AvatarResponse.ChangeAmmo(weapon_guid, weapon_slot, previous_guid, ammo_id, ammo_guid, ammo_data) case AvatarResponse.ChangeAmmo(weapon_guid, weapon_slot, previous_guid, ammo_id, ammo_guid, ammo_data)

View file

@ -201,20 +201,12 @@ class SessionAvatarHandlers(
) )
} }
def revive(revivalTargetGuid: PlanetSideGUID): Unit = { def revive(): Unit = {
val spawn = sessionLogic.zoning.spawn val spawn = sessionLogic.zoning.spawn
spawn.reviveTimer.cancel() spawn.reviveTimer.cancel()
spawn.reviveTimer = Default.Cancellable spawn.reviveTimer = Default.Cancellable
spawn.respawnTimer.cancel() spawn.respawnTimer.cancel()
spawn.respawnTimer = Default.Cancellable spawn.respawnTimer = Default.Cancellable
player.Revive
val health = player.Health
sendResponse(PlanetsideAttributeMessage(revivalTargetGuid, attribute_type=0, health))
sendResponse(AvatarDeadStateMessage(DeadState.Alive, timer_max=0, timer=0, player.Position, player.Faction, unk5=true))
continent.AvatarEvents ! AvatarServiceMessage(
continent.id,
AvatarAction.PlanetsideAttributeToAll(revivalTargetGuid, attribute_type=0, health)
)
} }
def killedWhileMounted(obj: PlanetSideGameObject with Mountable, playerGuid: PlanetSideGUID): Unit = { def killedWhileMounted(obj: PlanetSideGameObject with Mountable, playerGuid: PlanetSideGUID): Unit = {

View file

@ -629,6 +629,8 @@ object Player {
} }
} }
case object Revive
def apply(core: Avatar): Player = { def apply(core: Avatar): Player = {
new Player(core) new Player(core)
} }

View file

@ -70,18 +70,18 @@ object Players {
val name = target.Name val name = target.Name
val medicName = medic.Name val medicName = medic.Name
log.info(s"$medicName had revived $name") log.info(s"$medicName had revived $name")
//give credit even if the player does not revive
target.LogActivity(RevivingActivity(PlayerSource(target), PlayerSource(medic), target.MaxHealth, item.Definition)) target.LogActivity(RevivingActivity(PlayerSource(target), PlayerSource(medic), target.MaxHealth, item.Definition))
val magazine = item.Discharge(Some(25)) val magazine = item.Discharge(Some(25))
target.Zone.AvatarEvents ! AvatarServiceMessage( PlayerControl.sendResponse(
target.Zone,
medicName, medicName,
AvatarAction.SendResponse( AvatarAction.SendResponse(
Service.defaultPlayerGUID, Service.defaultPlayerGUID,
InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine) InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine)
) )
) )
target.Zone.AvatarEvents ! AvatarServiceMessage(name, AvatarAction.Revive(target.GUID)) PlayerControl.sendResponse(target.Zone, name, AvatarAction.Revive(target.GUID))
val reviveMessage = s"@YouHaveBeenMessage^revived~^$medicName~"
PlayerControl.sendResponse(target.Zone, name, ChatMsg(ChatMessageType.UNK_227, reviveMessage))
} }
/** /**

View file

@ -116,6 +116,19 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
case Player.Die(None) => case Player.Die(None) =>
suicide() suicide()
case Player.Revive
if player.Health == 0 && !player.isBackpack =>
player.Revive
val revivalTargetGuid = player.GUID
val health = player.Health
val zone = player.Zone
val zoneId = zone.id
sendResponse(zone, zoneId, PlanetsideAttributeMessage(revivalTargetGuid, attribute_type=0, health))
sendResponse(zone, zoneId, AvatarDeadStateMessage(DeadState.Alive, timer_max=0, timer=0, player.Position, player.Faction, unk5=true))
sendResponse(zone, zoneId, AvatarAction.PlanetsideAttributeToAll(revivalTargetGuid, attribute_type=0, health))
avatarActor ! AvatarActor.InitializeImplants
avatarActor ! AvatarActor.SuspendStaminaRegeneration(Duration(1, "second"))
case CommonMessages.Use(user, Some(item: Tool)) case CommonMessages.Use(user, Some(item: Tool))
if item.Definition == GlobalDefinitions.medicalapplicator && player.isAlive => if item.Definition == GlobalDefinitions.medicalapplicator && player.isAlive =>
//heal //heal
@ -982,6 +995,9 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
super.CancelJammeredStatus(target) super.CancelJammeredStatus(target)
//uninitialize implants //uninitialize implants
avatarActor ! AvatarActor.DeinitializeImplants avatarActor ! AvatarActor.DeinitializeImplants
//no stamina
avatarActor ! AvatarActor.SuspendStaminaRegeneration(Duration(1, "day"))
avatarActor ! AvatarActor.ConsumeStamina(player.avatar.maxStamina)
//log historical event //log historical event
target.LogActivity(cause) target.LogActivity(cause)
@ -1222,6 +1238,10 @@ object PlayerControl {
zone.AvatarEvents ! AvatarServiceMessage(channel, AvatarAction.SendResponse(Service.defaultPlayerGUID, msg)) zone.AvatarEvents ! AvatarServiceMessage(channel, AvatarAction.SendResponse(Service.defaultPlayerGUID, msg))
} }
def sendResponse(zone: Zone, channel: String, msg: AvatarAction.Action): Unit = {
zone.AvatarEvents ! AvatarServiceMessage(channel, msg)
}
def maxRestriction(player: Player, slot: Int): Boolean = { def maxRestriction(player: Player, slot: Int): Boolean = {
if (player.ExoSuit == ExoSuitType.MAX) { if (player.ExoSuit == ExoSuitType.MAX) {
slot != 0 slot != 0

View file

@ -48,7 +48,7 @@ trait StandardDamageProfile extends DamageProfile {
Damage2 Damage2
} }
def Damage3: Int = damage3.getOrElse(Damage2) def Damage3: Int = damage3.getOrElse(Damage1)
def Damage3_=(damage: Int): Int = Damage3_=(Some(damage)) def Damage3_=(damage: Int): Int = Damage3_=(Some(damage))
@ -57,7 +57,7 @@ trait StandardDamageProfile extends DamageProfile {
Damage3 Damage3
} }
def Damage4: Int = damage4.getOrElse(Damage3) def Damage4: Int = damage4.getOrElse(Damage1)
def Damage4_=(damage: Int): Int = Damage4_=(Some(damage)) def Damage4_=(damage: Int): Int = Damage4_=(Some(damage))