mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-01-19 18:44:45 +00:00
commit
abf7135e64
|
|
@ -13,7 +13,9 @@ import net.psforever.objects.equipment.{Equipment, EquipmentSlot}
|
|||
import net.psforever.objects.inventory.InventoryItem
|
||||
import net.psforever.objects.loadouts.{InfantryLoadout, Loadout, VehicleLoadout}
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.ballistics.PlayerSource
|
||||
import net.psforever.objects.locker.LockerContainer
|
||||
import net.psforever.objects.vital.HealFromImplant
|
||||
import net.psforever.packet.game.objectcreate.ObjectClass
|
||||
import net.psforever.packet.game._
|
||||
import net.psforever.types._
|
||||
|
|
@ -764,7 +766,7 @@ class AvatarActor(
|
|||
if (!implant.initialized) {
|
||||
log.warn(s"requested activation of uninitialized implant $implantType")
|
||||
} else if (
|
||||
!consumeStamina(implant.definition.ActivationStaminaCost) ||
|
||||
!consumeThisMuchStamina(implant.definition.ActivationStaminaCost) ||
|
||||
avatar.stamina < implant.definition.StaminaCost
|
||||
) {
|
||||
// not enough stamina to activate
|
||||
|
|
@ -799,7 +801,33 @@ class AvatarActor(
|
|||
// TODO costInterval should be an option ^
|
||||
if (interval.toMillis > 0) {
|
||||
implantTimers(slot) = context.system.scheduler.scheduleWithFixedDelay(interval, interval)(() => {
|
||||
if (!consumeStamina(implant.definition.StaminaCost)) {
|
||||
val player = session.get.player
|
||||
if (implantType match {
|
||||
case ImplantType.AdvancedRegen =>
|
||||
//for every 1hp: 2sp (running), 1.5sp (standing), 1sp (crouched)
|
||||
// to simulate '1.5sp (standing)', find if 0.0...1.0 * 100 is an even number
|
||||
val cost = implant.definition.StaminaCost -
|
||||
(if (player.Crouching || (!player.isMoving && (math.random() * 100) % 2 == 1)) 1 else 0)
|
||||
val aliveAndWounded = player.isAlive && player.Health < player.MaxHealth
|
||||
if (aliveAndWounded && consumeThisMuchStamina(cost)) {
|
||||
//heal
|
||||
val originalHealth = player.Health
|
||||
val zone = player.Zone
|
||||
val events = zone.AvatarEvents
|
||||
val guid = player.GUID
|
||||
val newHealth = player.Health = originalHealth + 1
|
||||
player.History(HealFromImplant(PlayerSource(player), 1, implantType))
|
||||
events ! AvatarServiceMessage(
|
||||
zone.id,
|
||||
AvatarAction.PlanetsideAttributeToAll(guid, 0, newHealth)
|
||||
)
|
||||
false
|
||||
} else {
|
||||
!aliveAndWounded
|
||||
}
|
||||
case _ =>
|
||||
!player.isAlive || !consumeThisMuchStamina(implant.definition.StaminaCost)
|
||||
}) {
|
||||
context.self ! DeactivateImplant(implantType)
|
||||
}
|
||||
})
|
||||
|
|
@ -867,7 +895,7 @@ class AvatarActor(
|
|||
|
||||
case ConsumeStamina(stamina) =>
|
||||
if (stamina > 0) {
|
||||
consumeStamina(stamina)
|
||||
consumeThisMuchStamina(stamina)
|
||||
} else {
|
||||
log.warn(s"consumed stamina must be larger than 0, but is: $stamina")
|
||||
}
|
||||
|
|
@ -1021,34 +1049,50 @@ class AvatarActor(
|
|||
p.future
|
||||
}
|
||||
|
||||
/** Consumes given stamina and returns false if current stamina was too low to consume the full amount */
|
||||
def consumeStamina(stamina: Int): Boolean = {
|
||||
if (stamina == 0) return true
|
||||
if (!session.get.player.HasGUID) return false
|
||||
val consumed = (avatar.stamina - stamina) >= 0
|
||||
val totalStamina = math.max(0, avatar.stamina - stamina)
|
||||
val fatigued = if (!avatar.fatigued && totalStamina == 0) {
|
||||
context.self ! DeactivateActiveImplants()
|
||||
/**
|
||||
* Drain at most a given amount of stamina from the player's pool of stamina.
|
||||
* If the player's reserves become zero in the act, inform the player that he is fatigued
|
||||
* meaning that he will only be able to walk, all implants will deactivate,
|
||||
* and all exertion that require stamina use will become impossible until a threshold of stamina is regained.
|
||||
* @param stamina an amount to drain
|
||||
* @return `true`, as long as the amount of stamina can be drained in total;
|
||||
* `false`, otherwise
|
||||
*/
|
||||
def consumeThisMuchStamina(stamina: Int): Boolean = {
|
||||
if (stamina < 1) {
|
||||
true
|
||||
} else {
|
||||
totalStamina == 0
|
||||
}
|
||||
if (!avatar.fatigued && fatigued) {
|
||||
avatar.implants.zipWithIndex.foreach {
|
||||
case (Some(implant), slot) =>
|
||||
if (implant.active) {
|
||||
deactivateImplant(implant.definition.implantType)
|
||||
val resultingStamina = avatar.stamina - stamina
|
||||
val totalStamina = math.max(0, resultingStamina)
|
||||
val alreadyFatigued = avatar.fatigued
|
||||
val becomeFatigued = !alreadyFatigued && totalStamina == 0
|
||||
avatar = avatar.copy(stamina = totalStamina, fatigued = alreadyFatigued || becomeFatigued)
|
||||
val player = session.get.player
|
||||
if (player.HasGUID) {
|
||||
if (becomeFatigued) {
|
||||
avatar.implants.zipWithIndex.foreach {
|
||||
case (Some(implant), slot) =>
|
||||
if (implant.active) {
|
||||
deactivateImplant(implant.definition.implantType)
|
||||
}
|
||||
sessionActor ! SessionActor.SendResponse(
|
||||
AvatarImplantMessage(player.GUID, ImplantAction.OutOfStamina, slot, 1)
|
||||
)
|
||||
case _ => ;
|
||||
}
|
||||
sessionActor ! SessionActor.SendResponse(
|
||||
AvatarImplantMessage(session.get.player.GUID, ImplantAction.OutOfStamina, slot, 1)
|
||||
)
|
||||
case _ => ()
|
||||
}
|
||||
sessionActor ! SessionActor.SendResponse(PlanetsideAttributeMessage(player.GUID, 2, avatar.stamina))
|
||||
} else if (becomeFatigued) {
|
||||
avatar = avatar.copy(implants = avatar.implants.zipWithIndex.collect {
|
||||
case (Some(implant), slot) if implant.active =>
|
||||
implantTimers(slot).cancel()
|
||||
Some(implant.copy(active = false))
|
||||
case (out, _) =>
|
||||
out
|
||||
})
|
||||
}
|
||||
resultingStamina >= 0
|
||||
}
|
||||
|
||||
avatar = avatar.copy(stamina = totalStamina, fatigued = fatigued)
|
||||
sessionActor ! SessionActor.SendResponse(PlanetsideAttributeMessage(session.get.player.GUID, 2, avatar.stamina))
|
||||
consumed
|
||||
}
|
||||
|
||||
def initializeImplants(): Unit = {
|
||||
|
|
|
|||
Loading…
Reference in a new issue