mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-07-16 08:55:18 +00:00
implant initialization timers now saved to the database; uninitialized implants will appear as uninitialized when the character loads; passive initialized implants will always start as activate
This commit is contained in:
parent
40c93d8105
commit
7caa64d5df
5 changed files with 100 additions and 35 deletions
|
|
@ -0,0 +1,3 @@
|
||||||
|
/* New */
|
||||||
|
ALTER TABLE implant
|
||||||
|
ADD COLUMN timer SMALLINT NOT NULL DEFAULT 0;
|
||||||
|
|
@ -837,6 +837,24 @@ object AvatarActor {
|
||||||
_.useCooldowns -> lift(buildClobfromCooldowns(avatar.cooldowns.use))
|
_.useCooldowns -> lift(buildClobfromCooldowns(avatar.cooldowns.use))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
lazy val curr = System.currentTimeMillis()
|
||||||
|
avatar
|
||||||
|
.implants
|
||||||
|
.collect {
|
||||||
|
case Some(implant) if implant.timer > 0 =>
|
||||||
|
(implant.definition.Name, math.max(0L, (implant.timer - curr) / 1000L).toInt)
|
||||||
|
case Some(implant) =>
|
||||||
|
(implant.definition.Name, 0)
|
||||||
|
}
|
||||||
|
.foreach {
|
||||||
|
case (name, delay) =>
|
||||||
|
ctx.run(
|
||||||
|
query[persistence.Implant]
|
||||||
|
.filter { _.avatarId == lift(avatarId) }
|
||||||
|
.filter { _.name.equals(lift(name)) }
|
||||||
|
.update { _.timer -> lift(delay) }
|
||||||
|
)
|
||||||
|
}
|
||||||
out.completeWith(Future(1))
|
out.completeWith(Future(1))
|
||||||
case _ =>
|
case _ =>
|
||||||
out.completeWith(Future(0))
|
out.completeWith(Future(0))
|
||||||
|
|
@ -998,6 +1016,16 @@ object AvatarActor {
|
||||||
decoration = ProgressDecoration(cosmetics = convertedCosmetics)
|
decoration = ProgressDecoration(cosmetics = convertedCosmetics)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def initializationTime(implant: Implant): FiniteDuration = {
|
||||||
|
val timer = implant.timer
|
||||||
|
val normalDuration = implant.definition.InitializationDuration
|
||||||
|
(if (timer == 0) {
|
||||||
|
normalDuration
|
||||||
|
} else {
|
||||||
|
math.max(0L, (timer - System.currentTimeMillis()) / 1000L)
|
||||||
|
}).seconds
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AvatarActor(
|
class AvatarActor(
|
||||||
|
|
@ -1809,11 +1837,21 @@ class AvatarActor(
|
||||||
} yield (certs, implants, locker, debt)
|
} yield (certs, implants, locker, debt)
|
||||||
result.onComplete {
|
result.onComplete {
|
||||||
case Success((certs, implants, lockerInv, debt)) =>
|
case Success((certs, implants, lockerInv, debt)) =>
|
||||||
|
val curr = System.currentTimeMillis()
|
||||||
avatarCopy(
|
avatarCopy(
|
||||||
avatar.copy(
|
avatar.copy(
|
||||||
certifications =
|
certifications =
|
||||||
certs.map(cert => Certification.withValue(cert.id)).toSet ++ Config.app.game.baseCertifications,
|
certs.map(cert => Certification.withValue(cert.id)).toSet ++ Config.app.game.baseCertifications,
|
||||||
implants = implants.map(implant => Some(Implant(implant.toImplantDefinition))).padTo(3, None),
|
implants = implants.map { imp =>
|
||||||
|
val timerEqualsZero = imp.timer == 0
|
||||||
|
val initTimer: Long = if (timerEqualsZero) {
|
||||||
|
0L
|
||||||
|
} else {
|
||||||
|
curr + imp.timer * 1000L //convert from seconds to milliseconds time in future
|
||||||
|
}
|
||||||
|
val definition = imp.toImplantDefinition
|
||||||
|
Some(Implant(definition, initialized = timerEqualsZero, timer = initTimer, active = timerEqualsZero && definition.Passive))
|
||||||
|
}.padTo(3, None),
|
||||||
locker = lockerInv
|
locker = lockerInv
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -1983,8 +2021,7 @@ class AvatarActor(
|
||||||
} else if (becomeFatigued) {
|
} else if (becomeFatigued) {
|
||||||
avatarCopy(avatar.copy(implants = avatar.implants.zipWithIndex.collect {
|
avatarCopy(avatar.copy(implants = avatar.implants.zipWithIndex.collect {
|
||||||
case (Some(implant), slot) if implant.active =>
|
case (Some(implant), slot) if implant.active =>
|
||||||
implantTimers.lift(slot).foreach(_.cancel())
|
cancelImplantInitializedTimer(slot)
|
||||||
implantTimers.update(slot, Default.Cancellable)
|
|
||||||
Some(implant.copy(active = false))
|
Some(implant.copy(active = false))
|
||||||
case (out, _) =>
|
case (out, _) =>
|
||||||
out
|
out
|
||||||
|
|
@ -3249,7 +3286,8 @@ class AvatarActor(
|
||||||
ItemTransactionResultMessage(terminalGuid, TransactionType.Buy, success = true)
|
ItemTransactionResultMessage(terminalGuid, TransactionType.Buy, success = true)
|
||||||
)
|
)
|
||||||
findImplantByType(definition.implantType).foreach {
|
findImplantByType(definition.implantType).foreach {
|
||||||
case (implant, slot) => updateAvatarForImplant(implant, slot, initializeImplant(implant.definition.InitializationDuration.seconds))
|
case (implant, slot) =>
|
||||||
|
updateAvatarForImplant(implant, slot, initializeImplant(AvatarActor.initializationTime(implant)))
|
||||||
}
|
}
|
||||||
sessionActor ! SessionActor.CharSaved
|
sessionActor ! SessionActor.CharSaved
|
||||||
case _ =>
|
case _ =>
|
||||||
|
|
@ -3365,7 +3403,7 @@ class AvatarActor(
|
||||||
Some(implant.definition.implantType.shortcut)
|
Some(implant.definition.implantType.shortcut)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
initializeImplant(implant.definition.InitializationDuration.seconds)(implant, slot)
|
initializeImplant(AvatarActor.initializationTime(implant))(implant, slot)
|
||||||
case (None, _) => ()
|
case (None, _) => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3385,20 +3423,37 @@ class AvatarActor(
|
||||||
session.get.zone.id,
|
session.get.zone.id,
|
||||||
AvatarAction.AvatarImplant(session.get.player.GUID, ImplantAction.Initialization, slot, 0)
|
AvatarAction.AvatarImplant(session.get.player.GUID, ImplantAction.Initialization, slot, 0)
|
||||||
)
|
)
|
||||||
initializeImplant(implant.definition.InitializationDuration.seconds)(implant, slot)
|
initializeImplant(AvatarActor.initializationTime(implant))(implant, slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def initializeImplant(delay: FiniteDuration)(implant: Implant, slot: Int): Implant = {
|
private def initializeImplant(delay: FiniteDuration)(implant: Implant, slot: Int): Implant = {
|
||||||
|
val curr = System.currentTimeMillis()
|
||||||
|
val implantTimer = implant.timer
|
||||||
|
val (actualDelay, futureDelay, actionProgress): (FiniteDuration, Long, Long) = if (
|
||||||
|
implantTimer > 0 &&
|
||||||
|
implantTimers.lift(slot).exists(_.isCancelled)
|
||||||
|
) {
|
||||||
|
val countedDelay = math.max(0L, (implantTimer - curr) / 1000L)
|
||||||
|
val fullNormalDelay = implant.definition.InitializationDuration
|
||||||
|
val progress = if (countedDelay > fullNormalDelay) {
|
||||||
|
0L
|
||||||
|
} else {
|
||||||
|
(100f * ((fullNormalDelay - countedDelay).toFloat / fullNormalDelay.toFloat)).toLong
|
||||||
|
}
|
||||||
|
(countedDelay.seconds, implantTimer, progress)
|
||||||
|
} else {
|
||||||
|
(delay, curr + delay.toMillis, 0L)
|
||||||
|
}
|
||||||
//start initialization process
|
//start initialization process
|
||||||
setImplantInitializedTimer(implant, slot, delay)
|
setImplantInitializedTimer(implant, slot, actualDelay)
|
||||||
// Start client side initialization timer, visible on the character screen
|
// Start clien t side initialization timer, visible on the character screen
|
||||||
// Progress accumulates according to the client's knowledge of the implant initialization time
|
// Progress accumulates according to the client's knowledge of the implant initialization time
|
||||||
// What is normally a 60s timer that is set to 120s on the server will still visually update as if 60s\
|
// What is normally a 60s timer that is set to 120s on the server will still visually update as if 60s
|
||||||
session.get.zone.AvatarEvents ! AvatarServiceMessage(
|
session.get.zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
avatar.name,
|
avatar.name,
|
||||||
AvatarAction.SendResponse(Service.defaultPlayerGUID, ActionProgressMessage(slot + 6, 0))
|
AvatarAction.SendResponse(Service.defaultPlayerGUID, ActionProgressMessage(slot + 6, actionProgress))
|
||||||
)
|
)
|
||||||
implant.copy(initialized = false, active = false)
|
implant.copy(initialized = false, active = false, timer = futureDelay)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def deinitializeImplants(): Unit = {
|
private def deinitializeImplants(): Unit = {
|
||||||
|
|
@ -3421,7 +3476,12 @@ class AvatarActor(
|
||||||
session.get.zone.id,
|
session.get.zone.id,
|
||||||
AvatarAction.AvatarImplant(session.get.player.GUID, ImplantAction.Initialization, slot, 0)
|
AvatarAction.AvatarImplant(session.get.player.GUID, ImplantAction.Initialization, slot, 0)
|
||||||
)
|
)
|
||||||
implant.copy(initialized = false, active = false)
|
//can not formally stop the initialization time on the character information window; set it to 100 to make it look blank
|
||||||
|
session.get.zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
|
avatar.name,
|
||||||
|
AvatarAction.SendResponse(Service.defaultPlayerGUID, ActionProgressMessage(slot + 6, 100))
|
||||||
|
)
|
||||||
|
implant.copy(initialized = false, active = false, timer = 0L)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def setImplantInitialized(implantType: ImplantType): Unit = {
|
private def setImplantInitialized(implantType: ImplantType): Unit = {
|
||||||
|
|
@ -3429,15 +3489,17 @@ class AvatarActor(
|
||||||
.collect {
|
.collect {
|
||||||
case (implant, slot) =>
|
case (implant, slot) =>
|
||||||
sendAvatarImplantMessageToSelf(session.get.player.GUID, ImplantAction.Initialization, slot, value = 1)
|
sendAvatarImplantMessageToSelf(session.get.player.GUID, ImplantAction.Initialization, slot, value = 1)
|
||||||
|
cancelImplantInitializedTimer(slot)
|
||||||
avatarCopy(avatar.copy(implants = avatar.implants.map {
|
avatarCopy(avatar.copy(implants = avatar.implants.map {
|
||||||
case Some(implant)
|
case Some(implant)
|
||||||
if implant.definition.implantType == implantType && implant.definition.Passive =>
|
if implant.definition.implantType == implantType && implant.definition.Passive =>
|
||||||
activateImplantPackets(implant, slot)
|
activateImplantPackets(implant, slot)
|
||||||
Some(implant.copy(initialized = true, active = true))
|
Some(implant.copy(initialized = true, active = true, timer = 0))
|
||||||
case Some(implant)
|
case Some(implant)
|
||||||
if implant.definition.implantType == implantType =>
|
if implant.definition.implantType == implantType =>
|
||||||
Some(implant.copy(initialized = true))
|
Some(implant.copy(initialized = true, timer = 0))
|
||||||
case other => other
|
case other =>
|
||||||
|
other
|
||||||
}))
|
}))
|
||||||
Some(implant)
|
Some(implant)
|
||||||
}
|
}
|
||||||
|
|
@ -3456,6 +3518,11 @@ class AvatarActor(
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def cancelImplantInitializedTimer(slot: Int): Unit = {
|
||||||
|
implantTimers.lift(slot).foreach(_.cancel())
|
||||||
|
implantTimers.update(slot, Default.Cancellable)
|
||||||
|
}
|
||||||
|
|
||||||
private def deactivateImplant(implantType: ImplantType): Unit = {
|
private def deactivateImplant(implantType: ImplantType): Unit = {
|
||||||
avatar.implants.zipWithIndex.collectFirst {
|
avatar.implants.zipWithIndex.collectFirst {
|
||||||
case (Some(implant), index) if implant.definition.implantType == implantType => (implant, index)
|
case (Some(implant), index) if implant.definition.implantType == implantType => (implant, index)
|
||||||
|
|
@ -3478,8 +3545,7 @@ class AvatarActor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private def deactivateImplant(implant: Implant, slot: Int): Implant = {
|
private def deactivateImplant(implant: Implant, slot: Int): Implant = {
|
||||||
implantTimers.lift(slot).foreach(_.cancel())
|
cancelImplantInitializedTimer(slot)
|
||||||
implantTimers.update(slot, Default.Cancellable)
|
|
||||||
// Deactivation sound / effect
|
// Deactivation sound / effect
|
||||||
session.get.zone.AvatarEvents ! AvatarServiceMessage(
|
session.get.zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
session.get.zone.id,
|
session.get.zone.id,
|
||||||
|
|
|
||||||
|
|
@ -2957,19 +2957,6 @@ class ZoningOperations(
|
||||||
tplayer.Actor ! JammableUnit.ClearJammeredSound()
|
tplayer.Actor ! JammableUnit.ClearJammeredSound()
|
||||||
}
|
}
|
||||||
avatarActor ! AvatarActor.SoftResetImplants
|
avatarActor ! AvatarActor.SoftResetImplants
|
||||||
tavatar.implants.zipWithIndex.collect {
|
|
||||||
case (Some(implant), slot) if !implant.initialized =>
|
|
||||||
sendResponse(AvatarImplantMessage(guid, ImplantAction.Initialization, slot, 0))
|
|
||||||
}
|
|
||||||
// tavatar.implants.zipWithIndex.collect {
|
|
||||||
// case (Some(implant), slot) if implant.active && implant.definition.Passive =>
|
|
||||||
// sendResponse(AvatarImplantMessage(guid, ImplantAction.Initialization, slot, 1))
|
|
||||||
// sendResponse(AvatarImplantMessage(guid, ImplantAction.Activation, slot, 1))
|
|
||||||
// case (Some(implant), slot) if implant.initialized =>
|
|
||||||
// sendResponse(AvatarImplantMessage(guid, ImplantAction.Initialization, slot, 1))
|
|
||||||
// case (Some(implant), _) =>
|
|
||||||
// () //avatarActor ! AvatarActor.ResetImplant(implant.definition.implantType)
|
|
||||||
// }
|
|
||||||
val originalDeadState = deadState
|
val originalDeadState = deadState
|
||||||
deadState = DeadState.Alive
|
deadState = DeadState.Alive
|
||||||
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 82, 0))
|
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 82, 0))
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,19 @@ import net.psforever.packet.game.objectcreate.ImplantEntry
|
||||||
case class Implant(
|
case class Implant(
|
||||||
definition: ImplantDefinition,
|
definition: ImplantDefinition,
|
||||||
active: Boolean = false,
|
active: Boolean = false,
|
||||||
initialized: Boolean = false
|
initialized: Boolean = false,
|
||||||
//initializationTime: FiniteDuration
|
timer: Long = 0L
|
||||||
) {
|
) {
|
||||||
def toEntry: ImplantEntry = {
|
def toEntry: ImplantEntry = {
|
||||||
// TODO initialization time?
|
val initState = if (!initialized) {
|
||||||
new ImplantEntry(definition.implantType, None, active)
|
if (timer > 0) {
|
||||||
|
Some(math.max(0, ((timer - System.currentTimeMillis()) / 1000L).toInt))
|
||||||
|
} else {
|
||||||
|
Some(definition.InitializationDuration.toInt)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
new ImplantEntry(definition.implantType, initState, active)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,8 @@ import net.psforever.objects.serverobject.terminals.implant.ImplantTerminalDefin
|
||||||
|
|
||||||
case class Implant(
|
case class Implant(
|
||||||
name: String,
|
name: String,
|
||||||
avatarId: Int
|
avatarId: Int,
|
||||||
|
timer: Int = 0 //seconds to initialize
|
||||||
) {
|
) {
|
||||||
def toImplantDefinition: ImplantDefinition = {
|
def toImplantDefinition: ImplantDefinition = {
|
||||||
ImplantTerminalDefinition.implants(name)
|
ImplantTerminalDefinition.implants(name)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue