From 0da03b0f0f9732d945f0384470b20695600e94e6 Mon Sep 17 00:00:00 2001 From: Fate-JH Date: Thu, 4 May 2023 00:25:42 -0400 Subject: [PATCH] the max timer will assert itself through death and respawn --- src/main/resources/application.conf | 3 + .../actors/session/AvatarActor.scala | 98 ++++++++++++------- .../psforever/objects/GlobalDefinitions.scala | 9 ++ .../scala/net/psforever/util/Config.scala | 1 + 4 files changed, 74 insertions(+), 37 deletions(-) diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index 66d31a914..9a4fc459e 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -90,6 +90,9 @@ game { # Purchases timers for the mechanized assault exo-suits all update at the same time when any of them would update shared-max-cooldown = no + # Purchases timers for the battleframe robotics vehicles all update at the same time when either of them would update + shared-bfr-cooldown = yes + # HART system, shuttles and facilities hart { # How long the shuttle is not boarding passengers (going through the motions) diff --git a/src/main/scala/net/psforever/actors/session/AvatarActor.scala b/src/main/scala/net/psforever/actors/session/AvatarActor.scala index e876ddda6..d375251fc 100644 --- a/src/main/scala/net/psforever/actors/session/AvatarActor.scala +++ b/src/main/scala/net/psforever/actors/session/AvatarActor.scala @@ -400,28 +400,33 @@ object AvatarActor { def resolveSharedPurchaseTimeNames(pair: (BasicDefinition, String)): Seq[(BasicDefinition, String)] = { val (definition, name) = pair if (name.matches("(tr|nc|vs)hev_.+") && Config.app.game.sharedMaxCooldown) { + //all mechanized exo-suits val faction = name.take(2) (if (faction.equals("nc")) { - Seq(GlobalDefinitions.nchev_scattercannon, GlobalDefinitions.nchev_falcon, GlobalDefinitions.nchev_sparrow) - } else if (faction.equals("vs")) { - Seq(GlobalDefinitions.vshev_quasar, GlobalDefinitions.vshev_comet, GlobalDefinitions.vshev_starfire) - } else { - Seq(GlobalDefinitions.trhev_dualcycler, GlobalDefinitions.trhev_pounder, GlobalDefinitions.trhev_burster) - }).zip( - Seq(s"${faction}hev_antipersonnel", s"${faction}hev_antivehicular", s"${faction}hev_antiaircraft") - ) - } else { + Seq(GlobalDefinitions.nchev_scattercannon, GlobalDefinitions.nchev_falcon, GlobalDefinitions.nchev_sparrow) + } else if (faction.equals("vs")) { + Seq(GlobalDefinitions.vshev_quasar, GlobalDefinitions.vshev_comet, GlobalDefinitions.vshev_starfire) + } else { + Seq(GlobalDefinitions.trhev_dualcycler, GlobalDefinitions.trhev_pounder, GlobalDefinitions.trhev_burster) + }).map { tdef => (tdef, tdef.Descriptor) } + } else if ((name.matches(".+_gunner") || name.matches(".+_flight")) && Config.app.game.sharedBfrCooldown) { + //all battleframe robotics vehicles definition match { case vdef: VehicleDefinition if GlobalDefinitions.isBattleFrameFlightVehicle(vdef) => val bframe = name.substring(0, name.indexOf('_')) val gunner = bframe + "_gunner" - Seq((DefinitionUtil.fromString(gunner), gunner), (vdef, name)) - + Seq((DefinitionUtil.fromString(gunner), gunner), pair) case vdef: VehicleDefinition if GlobalDefinitions.isBattleFrameGunnerVehicle(vdef) => val bframe = name.substring(0, name.indexOf('_')) val flight = bframe + "_flight" - Seq((vdef, name), (DefinitionUtil.fromString(flight), flight)) - + Seq(pair, (DefinitionUtil.fromString(flight), flight)) + case _ => + Seq.empty + } + } else { + definition match { + case tdef: ToolDefinition if GlobalDefinitions.isMaxArms(tdef) => + Seq((tdef, tdef.Descriptor)) case _ => Seq(pair) } @@ -1447,7 +1452,8 @@ class AvatarActor( Behaviors.same case UpdatePurchaseTime(definition, time) => - var newTimes = avatar.cooldowns.purchase + var theTimes = avatar.cooldowns.purchase + var updateTheTimes: Boolean = false AvatarActor .resolveSharedPurchaseTimeNames(AvatarActor.resolvePurchaseTimeName(avatar.faction, definition)) .foreach { @@ -1455,7 +1461,8 @@ class AvatarActor( Avatar.purchaseCooldowns.get(item) match { case Some(cooldown) => //only send for items with cooldowns - newTimes = newTimes.updated(name, time) + updateTheTimes = true + theTimes = theTimes.updated(name, time) updatePurchaseTimer( name, cooldown.toSeconds, @@ -1467,7 +1474,9 @@ class AvatarActor( case _ => ; } } - avatarCopy(avatar.copy(cooldowns = avatar.cooldowns.copy(purchase = newTimes))) + if (updateTheTimes) { + avatarCopy(avatar.copy(cooldowns = avatar.cooldowns.copy(purchase = theTimes))) + } Behaviors.same case UpdateUseTime(definition, time) => @@ -2598,27 +2607,40 @@ class AvatarActor( def refreshPurchaseTimes(keys: Set[String]): Unit = { var keysToDrop: Seq[String] = Nil + val faction = avatar.faction keys.foreach { key => - avatar.cooldowns.purchase.find { case (name, _) => name.equals(key) } match { - case Some((name, purchaseTime)) => + avatar + .cooldowns + .purchase + .find { case (name, _) => name.equals(key) } + .flatMap { case (name, purchaseTime) => val secondsSincePurchase = Seconds.secondsBetween(purchaseTime, LocalDateTime.now()).getSeconds - Avatar.purchaseCooldowns.find(_._1.Name.equals(name)) match { - case Some((obj, cooldown)) if cooldown.toSeconds - secondsSincePurchase > 0 => - val (_, name) = AvatarActor.resolvePurchaseTimeName(avatar.faction, obj) - updatePurchaseTimer( - name, - cooldown.toSeconds - secondsSincePurchase, - obj match { - case _: KitDefinition => false - case _ => true - } - ) - - case _ => - keysToDrop = keysToDrop :+ key //key has timed-out + Avatar + .purchaseCooldowns + .find(_._1.Descriptor.equals(name)) + .collect { + case (obj, cooldown) => + (obj, cooldown.toSeconds - secondsSincePurchase) + } + .orElse { + keysToDrop = keysToDrop :+ key //key indicates cooldown, but no cooldown delay + None } - case _ => ; - } + } + .collect { + case (obj, remainingTime) if remainingTime > 0 => + val (_, resolvedName) = AvatarActor.resolvePurchaseTimeName(faction, obj) + updatePurchaseTimer( + resolvedName, + remainingTime, + obj match { + case _: KitDefinition => false + case _ => true + } + ) + case (_, _) => + keysToDrop = keysToDrop :+ key //key has timed-out + } } if (keysToDrop.nonEmpty) { val cdown = avatar.cooldowns @@ -3030,7 +3052,9 @@ class AvatarActor( sex: CharacterSex, empire: PlanetSideEmpire.Value, head: Int, - voice: CharacterVoice.Value + voice: CharacterVoice.Value, + bep: Long = Config.app.game.newAvatar.br.experience, + cep: Long = Config.app.game.newAvatar.cr.experience ): Unit = { import ctx._ val result = for { @@ -3043,8 +3067,8 @@ class AvatarActor( _.headId -> lift(head), _.voiceId -> lift(voice.id), _.genderId -> lift(sex.value), - _.bep -> lift(Config.app.game.newAvatar.br.experience), - _.cep -> lift(Config.app.game.newAvatar.cr.experience) + _.bep -> lift(bep), + _.cep -> lift(cep) ) ) } yield () diff --git a/src/main/scala/net/psforever/objects/GlobalDefinitions.scala b/src/main/scala/net/psforever/objects/GlobalDefinitions.scala index e1187a843..b100597ae 100644 --- a/src/main/scala/net/psforever/objects/GlobalDefinitions.scala +++ b/src/main/scala/net/psforever/objects/GlobalDefinitions.scala @@ -5411,6 +5411,7 @@ object GlobalDefinitions { dynomite.Tile = InventoryTile.Tile22 trhev_dualcycler.Name = "trhev_dualcycler" + trhev_dualcycler.Descriptor = "trhev_antipersonnel" trhev_dualcycler.Size = EquipmentSize.Max trhev_dualcycler.AmmoTypes += dualcycler_ammo trhev_dualcycler.ProjectileTypes += dualcycler_projectile @@ -5428,6 +5429,7 @@ object GlobalDefinitions { trhev_dualcycler.FireModes(2).Magazine = 200 trhev_pounder.Name = "trhev_pounder" + trhev_pounder.Descriptor = "trhev_antivehicular" trhev_pounder.Size = EquipmentSize.Max trhev_pounder.AmmoTypes += pounder_ammo trhev_pounder.ProjectileTypes += pounder_projectile @@ -5461,6 +5463,7 @@ object GlobalDefinitions { trhev_pounder.FireModes(5).Magazine = 30 trhev_burster.Name = "trhev_burster" + trhev_burster.Descriptor = "trhev_antiaircraft" trhev_burster.Size = EquipmentSize.Max trhev_burster.AmmoTypes += burster_ammo trhev_burster.ProjectileTypes += burster_projectile @@ -5470,6 +5473,7 @@ object GlobalDefinitions { trhev_burster.FireModes.head.Magazine = 40 nchev_scattercannon.Name = "nchev_scattercannon" + nchev_scattercannon.Descriptor = "nchev_antipersonnel" nchev_scattercannon.Size = EquipmentSize.Max nchev_scattercannon.AmmoTypes += scattercannon_ammo nchev_scattercannon.ProjectileTypes += scattercannon_projectile @@ -5490,6 +5494,7 @@ object GlobalDefinitions { nchev_scattercannon.FireModes(2).Chamber = 10 //40 shells * 10 pellets = 400 nchev_falcon.Name = "nchev_falcon" + nchev_falcon.Descriptor = "nchev_antivehicular" nchev_falcon.Size = EquipmentSize.Max nchev_falcon.AmmoTypes += falcon_ammo nchev_falcon.ProjectileTypes += falcon_projectile @@ -5499,6 +5504,7 @@ object GlobalDefinitions { nchev_falcon.FireModes.head.Magazine = 20 nchev_sparrow.Name = "nchev_sparrow" + nchev_sparrow.Descriptor = "nchev_antiaircraft" nchev_sparrow.Size = EquipmentSize.Max nchev_sparrow.AmmoTypes += sparrow_ammo nchev_sparrow.ProjectileTypes += sparrow_projectile @@ -5508,6 +5514,7 @@ object GlobalDefinitions { nchev_sparrow.FireModes.head.Magazine = 12 vshev_quasar.Name = "vshev_quasar" + vshev_quasar.Descriptor = "vshev_antipersonnel" vshev_quasar.Size = EquipmentSize.Max vshev_quasar.AmmoTypes += quasar_ammo vshev_quasar.ProjectileTypes += quasar_projectile @@ -5523,6 +5530,7 @@ object GlobalDefinitions { vshev_quasar.FireModes(1).Magazine = 120 vshev_comet.Name = "vshev_comet" + vshev_comet.Descriptor = "vshev_antivehicular" vshev_comet.Size = EquipmentSize.Max vshev_comet.AmmoTypes += comet_ammo vshev_comet.ProjectileTypes += comet_projectile @@ -5532,6 +5540,7 @@ object GlobalDefinitions { vshev_comet.FireModes.head.Magazine = 10 vshev_starfire.Name = "vshev_starfire" + vshev_starfire.Descriptor = "vshev_antiaircraft" vshev_starfire.Size = EquipmentSize.Max vshev_starfire.AmmoTypes += starfire_ammo vshev_starfire.ProjectileTypes += starfire_projectile diff --git a/src/main/scala/net/psforever/util/Config.scala b/src/main/scala/net/psforever/util/Config.scala index 0e372c70f..b7097cbb4 100644 --- a/src/main/scala/net/psforever/util/Config.scala +++ b/src/main/scala/net/psforever/util/Config.scala @@ -154,6 +154,7 @@ case class GameConfig( newAvatar: NewAvatar, hart: HartConfig, sharedMaxCooldown: Boolean, + sharedBfrCooldown: Boolean, baseCertifications: Seq[Certification], warpGates: WarpGateConfig, cavernRotation: CavernRotationConfig,