From ddf702eea914952a2da0a49a281fc88646751279 Mon Sep 17 00:00:00 2001 From: Mazo Date: Wed, 8 Jan 2020 13:24:14 +0000 Subject: [PATCH] Vehicle fixes (#313) * Send shield + capacitor state to players mounting a vehicle * Allow players to dismount vehicles that are slightly moving (e.g. rotating magrider, deployed vehicle with phantom velocity from pre-deployment), or vehicles in a deployed state * Add vehicle ntu capacitor, keeping old capacitor for EMP functionality when implemented, send capacitor / ntu values on vehicle mount if definition has a maximum set --- .../psforever/objects/GlobalDefinitions.scala | 2 +- .../scala/net/psforever/objects/Vehicle.scala | 18 +++++++++-- .../definition/VehicleDefinition.scala | 18 ++++++++--- .../mount/MountableBehavior.scala | 5 +-- .../src/main/scala/WorldSessionActor.scala | 32 ++++++++++++------- 5 files changed, 53 insertions(+), 22 deletions(-) diff --git a/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala b/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala index a77ec812..3973841b 100644 --- a/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala +++ b/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala @@ -5564,7 +5564,7 @@ object GlobalDefinitions { ant.DeployTime = 1500 ant.UndeployTime = 1500 ant.AutoPilotSpeeds = (18, 6) - ant.MaximumCapacitor = 1500 + ant.MaxNtuCapacitor = 1500 ant.Packet = utilityConverter ant.DestroyedModel = Some(DestroyedVehicle.Ant) ant.Subtract.Damage1 = 5 diff --git a/common/src/main/scala/net/psforever/objects/Vehicle.scala b/common/src/main/scala/net/psforever/objects/Vehicle.scala index a9adc2ba..a2867436 100644 --- a/common/src/main/scala/net/psforever/objects/Vehicle.scala +++ b/common/src/main/scala/net/psforever/objects/Vehicle.scala @@ -83,6 +83,7 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner private var jammered : Boolean = false private var cloaked : Boolean = false private var flying : Boolean = false + private var ntuCapacitor : Int = 0 private var capacitor : Int = 0 /** * Permissions control who gets to access different parts of the vehicle; @@ -196,11 +197,24 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner Flying } + def NtuCapacitor : Int = ntuCapacitor + + def NtuCapacitor_=(value: Int) : Int = { + if(value > Definition.MaxNtuCapacitor) { + ntuCapacitor = Definition.MaxNtuCapacitor + } else if (value < 0) { + ntuCapacitor = 0 + } else { + ntuCapacitor = value + } + NtuCapacitor + } + def Capacitor : Int = capacitor def Capacitor_=(value: Int) : Int = { - if(value > Definition.MaximumCapacitor) { - capacitor = Definition.MaximumCapacitor + if(value > Definition.MaxCapacitor) { + capacitor = Definition.MaxCapacitor } else if (value < 0) { capacitor = 0 } else { diff --git a/common/src/main/scala/net/psforever/objects/definition/VehicleDefinition.scala b/common/src/main/scala/net/psforever/objects/definition/VehicleDefinition.scala index 8f6fc071..bd5a1343 100644 --- a/common/src/main/scala/net/psforever/objects/definition/VehicleDefinition.scala +++ b/common/src/main/scala/net/psforever/objects/definition/VehicleDefinition.scala @@ -40,7 +40,8 @@ class VehicleDefinition(objectId : Int) extends ObjectDefinition(objectId) private var canBeOwned : Boolean = true private var serverVehicleOverrideSpeeds : (Int, Int) = (0, 0) private var deconTime : Option[FiniteDuration] = None - private var maximumCapacitor : Int = 0 + private var maxCapacitor : Int = 0 + private var maxNtuCapacitor : Int = 0 private var destroyedModel : Option[DestroyedVehicle.Value] = None Name = "vehicle" Packet = VehicleDefinition.converter @@ -153,11 +154,18 @@ class VehicleDefinition(objectId : Int) extends ObjectDefinition(objectId) def AutoPilotSpeed2 : Int = serverVehicleOverrideSpeeds._2 - def MaximumCapacitor : Int = maximumCapacitor + def MaxNtuCapacitor : Int = maxNtuCapacitor - def MaximumCapacitor_=(maxCapacitor: Int) : Int = { - maximumCapacitor = maxCapacitor - MaximumCapacitor + def MaxNtuCapacitor_=(max: Int) : Int = { + maxNtuCapacitor = max + MaxNtuCapacitor + } + + def MaxCapacitor : Int = maxCapacitor + + def MaxCapacitor_=(max: Int) : Int = { + maxCapacitor = max + MaxCapacitor } private var jackDuration = Array(0, 0, 0, 0) diff --git a/common/src/main/scala/net/psforever/objects/serverobject/mount/MountableBehavior.scala b/common/src/main/scala/net/psforever/objects/serverobject/mount/MountableBehavior.scala index 5384382e..26f3ca56 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/mount/MountableBehavior.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/mount/MountableBehavior.scala @@ -2,11 +2,12 @@ package net.psforever.objects.serverobject.mount import akka.actor.Actor -import net.psforever.objects.PlanetSideGameObject +import net.psforever.objects.{PlanetSideGameObject, Vehicle} import net.psforever.objects.entity.{Identifiable, WorldEntity} import net.psforever.objects.serverobject.affinity.FactionAffinity import net.psforever.objects.serverobject.hackable.Hackable import net.psforever.objects.serverobject.turret.TurretDefinition +import net.psforever.types.DriveState object MountableBehavior { /** @@ -80,7 +81,7 @@ object MountableBehavior { val obj = MountableObject obj.Seat(seat_num) match { case Some(seat) => - if(seat.Bailable || !obj.isMoving) { + if(seat.Bailable || !obj.isMoving(1) || (obj.isInstanceOf[Vehicle] && obj.asInstanceOf[Vehicle].DeploymentState == DriveState.Deployed)) { seat.Occupant = None user.VehicleSeated = None sender ! Mountable.MountMessages(user, Mountable.CanDismount(obj, seat_num)) diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala index fb688599..d9863929 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -1781,8 +1781,16 @@ class WorldSessionActor extends Actor log.info(s"MountVehicleMsg: $player_guid mounts $obj_guid @ $seat_num") PlayerActionsToCancel() sendResponse(PlanetsideAttributeMessage(obj_guid, 0, obj.Health)) - sendResponse(PlanetsideAttributeMessage(obj_guid, 68, 0)) //shield health - sendResponse(PlanetsideAttributeMessage(obj_guid, 113, 0)) //capacitor + sendResponse(PlanetsideAttributeMessage(obj_guid, 68, obj.Shields)) //shield health + if(obj.Definition.MaxNtuCapacitor > 0) { + val ntuCapacitor = scala.math.ceil((obj.NtuCapacitor.toFloat / obj.Definition.MaxNtuCapacitor.toFloat) * 10).toInt + sendResponse(PlanetsideAttributeMessage(obj_guid, 45, ntuCapacitor)) + } + if(obj.Definition.MaxCapacitor > 0) { + val capacitor = scala.math.ceil((obj.Capacitor.toFloat / obj.Definition.MaxCapacitor.toFloat) * 10).toInt + sendResponse(PlanetsideAttributeMessage(obj_guid, 113, capacitor)) + } + if(seat_num == 0) { continent.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(obj), continent)) //clear timer //simplistic vehicle ownership management @@ -2928,10 +2936,10 @@ class WorldSessionActor extends Actor */ def HandleNtuCharging(tplayer : Player, vehicle : Vehicle) : Unit = { log.trace(s"NtuCharging: Vehicle ${vehicle.GUID} is charging NTU capacitor.") - if(vehicle.Capacitor < vehicle.Definition.MaximumCapacitor) { + if(vehicle.NtuCapacitor < vehicle.Definition.MaxNtuCapacitor) { // Charging - vehicle.Capacitor += 100 - sendResponse(PlanetsideAttributeMessage(vehicle.GUID, 45, scala.math.ceil((vehicle.Capacitor.toFloat / vehicle.Definition.MaximumCapacitor.toFloat) * 10).toInt)) // set ntu on vehicle UI + vehicle.NtuCapacitor += 100 + sendResponse(PlanetsideAttributeMessage(vehicle.GUID, 45, scala.math.ceil((vehicle.NtuCapacitor.toFloat / vehicle.Definition.MaxNtuCapacitor.toFloat) * 10).toInt)) // set ntu on vehicle UI continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(vehicle.GUID, 52, 1L)) // panel glow on continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(vehicle.GUID, 49, 1L)) // orb particle effect on @@ -2939,7 +2947,7 @@ class WorldSessionActor extends Actor } else { // Fully charged - sendResponse(PlanetsideAttributeMessage(vehicle.GUID, 45, scala.math.ceil((vehicle.Capacitor.toFloat / vehicle.Definition.MaximumCapacitor.toFloat) * 10).toInt)) // set ntu on vehicle UI + sendResponse(PlanetsideAttributeMessage(vehicle.GUID, 45, scala.math.ceil((vehicle.NtuCapacitor.toFloat / vehicle.Definition.MaxNtuCapacitor.toFloat) * 10).toInt)) // set ntu on vehicle UI // Turning off glow/orb effects on ANT doesn't seem to work when deployed. Try to undeploy ANT from server side context.system.scheduler.scheduleOnce(vehicle.UndeployTime milliseconds, vehicle.Actor, Deployment.TryUndeploy(DriveState.Undeploying)) @@ -2960,21 +2968,21 @@ class WorldSessionActor extends Actor var silo = continent.GUID(silo_guid).get.asInstanceOf[ResourceSilo] // Check vehicle is still deployed before continuing. User can undeploy manually or vehicle may not longer be present. if(vehicle.DeploymentState == DriveState.Deployed) { - if(vehicle.Capacitor > 0 && silo.ChargeLevel < silo.MaximumCharge) { + if(vehicle.NtuCapacitor > 0 && silo.ChargeLevel < silo.MaximumCharge) { // Make sure we don't exceed the silo maximum charge or remove much NTU from ANT if maximum is reached, or try to make ANT go below 0 NTU - var chargeToDeposit = Math.min(Math.min(vehicle.Capacitor, 100), (silo.MaximumCharge - silo.ChargeLevel)) - vehicle.Capacitor -= chargeToDeposit + var chargeToDeposit = Math.min(Math.min(vehicle.NtuCapacitor, 100), (silo.MaximumCharge - silo.ChargeLevel)) + vehicle.NtuCapacitor -= chargeToDeposit silo.Actor ! ResourceSilo.UpdateChargeLevel(chargeToDeposit) continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(silo_guid, 49, 1L)) // panel glow on & orb particles on - sendResponse(PlanetsideAttributeMessage(vehicle.GUID, 45, scala.math.ceil((vehicle.Capacitor.toFloat / vehicle.Definition.MaximumCapacitor.toFloat) * 10).toInt)) // set ntu on vehicle UI + sendResponse(PlanetsideAttributeMessage(vehicle.GUID, 45, scala.math.ceil((vehicle.NtuCapacitor.toFloat / vehicle.Definition.MaxNtuCapacitor.toFloat) * 10).toInt)) // set ntu on vehicle UI //todo: grant BEP to user //todo: grant BEP to squad in range //todo: handle silo orb / panel glow properly if more than one person is refilling silo and one player stops. effects should stay on until all players stop - if(vehicle.Capacitor > 0 && silo.ChargeLevel < silo.MaximumCharge) { + if(vehicle.NtuCapacitor > 0 && silo.ChargeLevel < silo.MaximumCharge) { log.trace(s"NtuDischarging: ANT not empty and Silo not full. Scheduling another discharge") // Silo still not full and ant still has charge left - keep rescheduling ticks antDischargingTick = context.system.scheduler.scheduleOnce(1000 milliseconds, self, NtuDischarging(player, vehicle, silo_guid)) @@ -2989,7 +2997,7 @@ class WorldSessionActor extends Actor } else { // This shouldn't normally be run, only if the client thinks the ANT has capacitor charge when it doesn't, or thinks the silo isn't full when it is. - log.warn(s"NtuDischarging: Invalid discharge state. ANT Capacitor: ${vehicle.Capacitor} Silo Capacitor: ${silo.ChargeLevel}") + log.warn(s"NtuDischarging: Invalid discharge state. ANT Capacitor: ${vehicle.NtuCapacitor} Silo Capacitor: ${silo.ChargeLevel}") // Turning off glow/orb effects on ANT doesn't seem to work when deployed. Try to undeploy ANT from server side context.system.scheduler.scheduleOnce(vehicle.UndeployTime milliseconds, vehicle.Actor, Deployment.TryUndeploy(DriveState.Undeploying)) continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(silo_guid, 49, 0L)) // panel glow off & orb particles off