From a699c6c223056eb3f85905d81c923576c1484747 Mon Sep 17 00:00:00 2001 From: Fate-JH Date: Mon, 15 Jul 2024 16:03:45 -0400 Subject: [PATCH] reload opened and closed doors upon zoning changes; rework ntu silo and ant interaction start; clear hack on proximity terminals; facility turrets stop indicating towards jamming cause when mounted --- .../actors/session/normal/GeneralLogic.scala | 15 +++-- .../session/normal/LocalHandlerLogic.scala | 14 ++--- .../session/spectator/LocalHandlerLogic.scala | 6 +- .../support/SessionLocalHandlers.scala | 16 ++++- .../session/support/ZoningOperations.scala | 52 ++++++++++++++-- .../GlobalDefinitionsMiscellaneous.scala | 1 + .../resourcesilo/ResourceSiloControl.scala | 61 +++++++++---------- .../terminals/ProximityTerminalControl.scala | 8 ++- .../turret/FacilityTurretControl.scala | 7 ++- 9 files changed, 119 insertions(+), 61 deletions(-) diff --git a/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala b/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala index 0a26acee8..1eb457f9d 100644 --- a/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala +++ b/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala @@ -41,7 +41,7 @@ import net.psforever.objects.zones.blockmap.BlockMapEntity import net.psforever.objects.zones.{Zone, ZoneProjectile, Zoning} import net.psforever.packet.PlanetSideGamePacket import net.psforever.packet.game.objectcreate.ObjectClass -import net.psforever.packet.game.{ActionCancelMessage, ActionResultMessage, AvatarFirstTimeEventMessage, AvatarImplantMessage, AvatarJumpMessage, BattleplanMessage, BindPlayerMessage, BindStatus, BugReportMessage, ChangeFireModeMessage, ChangeShortcutBankMessage, CharacterCreateRequestMessage, CharacterRequestAction, CharacterRequestMessage, ChatMsg, CollisionIs, ConnectToWorldRequestMessage, CreateShortcutMessage, DeadState, DeployObjectMessage, DisplayedAwardMessage, DropItemMessage, EmoteMsg, FacilityBenefitShieldChargeRequestMessage, FriendsRequest, GenericAction, GenericActionMessage, GenericCollisionMsg, GenericObjectActionAtPositionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HitHint, ImplantAction, InvalidTerrainMessage, ItemTransactionMessage, LootItemMessage, MoveItemMessage, ObjectDeleteMessage, ObjectDetectedMessage, ObjectHeldMessage, PickupItemMessage, PlanetsideAttributeMessage, PlayerStateMessageUpstream, PlayerStateShiftMessage, RequestDestroyMessage, ShiftState, Shortcut, TargetInfo, TargetingImplantRequest, TargetingInfoMessage, TerrainCondition, TradeMessage, UnuseItemMessage, UseItemMessage, VoiceHostInfo, VoiceHostRequest, ZipLineMessage} +import net.psforever.packet.game.{ActionCancelMessage, ActionResultMessage, AvatarFirstTimeEventMessage, AvatarImplantMessage, AvatarJumpMessage, BattleplanMessage, BindPlayerMessage, BindStatus, BugReportMessage, ChangeFireModeMessage, ChangeShortcutBankMessage, CharacterCreateRequestMessage, CharacterRequestAction, CharacterRequestMessage, ChatMsg, CollisionIs, ConnectToWorldRequestMessage, CreateShortcutMessage, DeadState, DeployObjectMessage, DisplayedAwardMessage, DropItemMessage, EmoteMsg, FacilityBenefitShieldChargeRequestMessage, FriendsRequest, GenericAction, GenericActionMessage, GenericCollisionMsg, GenericObjectActionAtPositionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HitHint, ImplantAction, InvalidTerrainMessage, ItemTransactionMessage, LootItemMessage, MoveItemMessage, ObjectDeleteMessage, ObjectDetectedMessage, ObjectHeldMessage, PickupItemMessage, PlanetsideAttributeMessage, PlayerStateMessageUpstream, PlayerStateShiftMessage, RequestDestroyMessage, ShiftState, TargetInfo, TargetingImplantRequest, TargetingInfoMessage, TerrainCondition, TradeMessage, UnuseItemMessage, UseItemMessage, VoiceHostInfo, VoiceHostRequest, ZipLineMessage} import net.psforever.services.RemoverActor import net.psforever.services.account.{AccountPersistenceService, RetrieveAccountData} import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} @@ -1025,13 +1025,18 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex private def handleUseResourceSilo(resourceSilo: ResourceSilo, equipment: Option[Equipment]): Unit = { sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_use") - (continent.GUID(player.VehicleSeated), equipment) match { + val vehicleOpt = continent.GUID(player.avatar.vehicle) + (vehicleOpt, equipment) match { case (Some(vehicle: Vehicle), Some(item)) if GlobalDefinitions.isBattleFrameVehicle(vehicle.Definition) && GlobalDefinitions.isBattleFrameNTUSiphon(item.Definition) => - resourceSilo.Actor ! CommonMessages.Use(player, equipment) - case _ => - resourceSilo.Actor ! CommonMessages.Use(player) + resourceSilo.Actor ! CommonMessages.Use(player, Some(vehicle)) + case (Some(vehicle: Vehicle), _) + if vehicle.Definition == GlobalDefinitions.ant && + vehicle.DeploymentState == DriveState.Deployed && + Vector3.DistanceSquared(resourceSilo.Position.xy, vehicle.Position.xy) < math.pow(resourceSilo.Definition.UseRadius, 2) => + resourceSilo.Actor ! CommonMessages.Use(player, Some(vehicle)) + case _ => () } } diff --git a/src/main/scala/net/psforever/actors/session/normal/LocalHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/normal/LocalHandlerLogic.scala index 896f9ea6a..009d0bbd7 100644 --- a/src/main/scala/net/psforever/actors/session/normal/LocalHandlerLogic.scala +++ b/src/main/scala/net/psforever/actors/session/normal/LocalHandlerLogic.scala @@ -5,7 +5,6 @@ import akka.actor.ActorContext import net.psforever.actors.session.support.{LocalHandlerFunctions, SessionData, SessionLocalHandlers} import net.psforever.objects.ce.Deployable import net.psforever.objects.serverobject.doors.Door -import net.psforever.objects.serverobject.interior.Sidedness import net.psforever.objects.vehicles.MountableWeapons import net.psforever.objects.{BoomerDeployable, ExplosiveDeployable, TelepadDeployable, Tool, TurretDeployable} import net.psforever.packet.game.{ChatMsg, DeployableObjectsInfoMessage, GenericActionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HackMessage, HackState, InventoryStateMessage, ObjectAttachMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectDetachMessage, OrbitalShuttleTimeMsg, PadAndShuttlePair, PlanetsideAttributeMessage, ProximityTerminalUseMessage, SetEmpireMessage, TriggerEffectMessage, TriggerSoundMessage, TriggeredSound, VehicleStateMessage} @@ -69,9 +68,7 @@ class LocalHandlerLogic(val ops: SessionLocalHandlers, implicit val context: Act case LocalResponse.DoorOpens(doorGuid) if isNotSameTarget => val pos = player.Position.xy - val range = if (Sidedness.equals(player.WhichSide, Sidedness.InsideOf)) 100f - else if (sessionLogic.general.canSeeReallyFar) 800f - else 400f + val range = ops.doorLoadRange() val foundDoor = continent .blockMap .sector(pos, range) @@ -79,13 +76,12 @@ class LocalHandlerLogic(val ops: SessionLocalHandlers, implicit val context: Act .collect { case door: Door => door } .find(_.GUID == doorGuid) val doorExistsInRange: Boolean = foundDoor.nonEmpty - //lazy val doorReallyClose: Boolean = foundDoor.exists(door => Vector3.DistanceSquared(door.Position.xy, pos) < 10201f) if (doorExistsInRange) { sendResponse(GenericObjectStateMsg(doorGuid, state=16)) } case LocalResponse.DoorCloses(doorGuid) => //door closes for everyone - sendResponse(GenericObjectStateMsg(doorGuid, state = 17)) + sendResponse(GenericObjectStateMsg(doorGuid, state=17)) case LocalResponse.EliminateDeployable(obj: TurretDeployable, dguid, _, _) if obj.Destroyed => sendResponse(ObjectDeleteMessage(dguid, unk1=0)) @@ -111,16 +107,14 @@ class LocalHandlerLogic(val ops: SessionLocalHandlers, implicit val context: Act case LocalResponse.EliminateDeployable(obj: TelepadDeployable, dguid, _, _) if obj.Active && obj.Destroyed => //if active, deactivate obj.Active = false - sendResponse(GenericObjectActionMessage(dguid, code=29)) - sendResponse(GenericObjectActionMessage(dguid, code=30)) + ops.deactivateTelpadDeployableMessages(dguid) //standard deployable elimination behavior sendResponse(ObjectDeleteMessage(dguid, unk1=0)) case LocalResponse.EliminateDeployable(obj: TelepadDeployable, dguid, pos, _) if obj.Active => //if active, deactivate obj.Active = false - sendResponse(GenericObjectActionMessage(dguid, code=29)) - sendResponse(GenericObjectActionMessage(dguid, code=30)) + ops.deactivateTelpadDeployableMessages(dguid) //standard deployable elimination behavior obj.Destroyed = true DeconstructDeployable(obj, dguid, pos, obj.Orientation, deletionType=2) diff --git a/src/main/scala/net/psforever/actors/session/spectator/LocalHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/spectator/LocalHandlerLogic.scala index 21d85d7a1..c0810ab64 100644 --- a/src/main/scala/net/psforever/actors/session/spectator/LocalHandlerLogic.scala +++ b/src/main/scala/net/psforever/actors/session/spectator/LocalHandlerLogic.scala @@ -96,16 +96,14 @@ class LocalHandlerLogic(val ops: SessionLocalHandlers, implicit val context: Act case LocalResponse.EliminateDeployable(obj: TelepadDeployable, dguid, _, _) if obj.Active && obj.Destroyed => //if active, deactivate obj.Active = false - sendResponse(GenericObjectActionMessage(dguid, code=29)) - sendResponse(GenericObjectActionMessage(dguid, code=30)) + ops.deactivateTelpadDeployableMessages(dguid) //standard deployable elimination behavior sendResponse(ObjectDeleteMessage(dguid, unk1=0)) case LocalResponse.EliminateDeployable(obj: TelepadDeployable, dguid, pos, _) if obj.Active => //if active, deactivate obj.Active = false - sendResponse(GenericObjectActionMessage(dguid, code=29)) - sendResponse(GenericObjectActionMessage(dguid, code=30)) + ops.deactivateTelpadDeployableMessages(dguid) //standard deployable elimination behavior obj.Destroyed = true DeconstructDeployable(obj, dguid, pos, obj.Orientation, deletionType=2) diff --git a/src/main/scala/net/psforever/actors/session/support/SessionLocalHandlers.scala b/src/main/scala/net/psforever/actors/session/support/SessionLocalHandlers.scala index 456e3a237..7fc6a893b 100644 --- a/src/main/scala/net/psforever/actors/session/support/SessionLocalHandlers.scala +++ b/src/main/scala/net/psforever/actors/session/support/SessionLocalHandlers.scala @@ -5,6 +5,8 @@ import akka.actor.ActorContext import net.psforever.objects.{Players, TurretDeployable} import net.psforever.objects.ce.Deployable import net.psforever.objects.guid.{GUIDTask, TaskWorkflow} +import net.psforever.objects.serverobject.interior.Sidedness +import net.psforever.packet.game.GenericObjectActionMessage import net.psforever.services.local.LocalResponse import net.psforever.types.PlanetSideGUID @@ -22,7 +24,10 @@ class SessionLocalHandlers( val sessionLogic: SessionData, implicit val context: ActorContext ) extends CommonSessionInterfacingFunctionality { - + def deactivateTelpadDeployableMessages(guid: PlanetSideGUID): Unit = { + sendResponse(GenericObjectActionMessage(guid, code = 29)) + sendResponse(GenericObjectActionMessage(guid, code = 30)) + } def handleTurretDeployableIsDismissed(obj: TurretDeployable): Unit = { Players.buildCooldownReset(continent, player.Name, obj) @@ -33,4 +38,13 @@ class SessionLocalHandlers( Players.buildCooldownReset(continent, player.Name, obj) TaskWorkflow.execute(GUIDTask.unregisterObject(continent.GUID, obj)) } + + def doorLoadRange(): Float = { + if (Sidedness.equals(player.WhichSide, Sidedness.InsideOf)) + 100f + else if (sessionLogic.general.canSeeReallyFar) + 800f + else + 400f + } } diff --git a/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala b/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala index 5981f3850..6648cf3ba 100644 --- a/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala +++ b/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala @@ -2227,15 +2227,28 @@ class ZoningOperations( sessionLogic.actionsToCancel() continent.GUID(player.VehicleSeated) match { case Some(vehicle: Vehicle) if vehicle.MountedIn.isEmpty => - vehicle.PassengerInSeat(player) match { - case Some(0) => - deadState = DeadState.Release // cancel movement updates - vehicle.Position = position - LoadZonePhysicalSpawnPoint(continent.id, position, Vector3.z(vehicle.Orientation.z), 0 seconds, None) - case _ => // not seated as the driver, in which case we can't move + vehicle + .PassengerInSeat(player) + .collect { + case 0 => //driver of the vehicle carries the vehicle and its passengers + deadState = DeadState.Release //cancel movement updates + vehicle.Position = position + doorsThatShouldBeClosedOrBeOpenedByRange( + player.Position, + sessionLogic.localResponse.doorLoadRange(), + position, + openRange = 100f + ) + LoadZonePhysicalSpawnPoint(continent.id, position, Vector3.z(vehicle.Orientation.z), 0 seconds, None) } case None => deadState = DeadState.Release // cancel movement updates + doorsThatShouldBeClosedOrBeOpenedByRange( + player.Position, + sessionLogic.localResponse.doorLoadRange(), + position, + openRange = 100f + ) player.Position = position sendResponse(PlayerStateShiftMessage(ShiftState(0, position, player.Orientation.z, None))) deadState = DeadState.Alive // must be set here @@ -3105,6 +3118,7 @@ class ZoningOperations( } }) } + doorsThatShouldBeOpenInRange(pos, range = 100f) setAvatar = true player.allowInteraction = true upstreamMessageCount = 0 @@ -3622,6 +3636,32 @@ class ZoningOperations( } } + def doorsThatShouldBeClosedOrBeOpenedByRange( + closedPosition: Vector3, + closedRange: Float, + openPosition: Vector3, + openRange: Float + ): Unit = { + continent + .blockMap + .sector(closedPosition, closedRange) + .amenityList + .collect { case door: Door if door.isOpen => + sendResponse(GenericObjectStateMsg(door.GUID, state=17)) + } + doorsThatShouldBeOpenInRange(openPosition, openRange) + } + + def doorsThatShouldBeOpenInRange(position: Vector3, range: Float): Unit = { + continent + .blockMap + .sector(position.xy, range) + .amenityList + .collect { case door: Door if door.isOpen => + sendResponse(GenericObjectStateMsg(door.GUID, state=16)) + } + } + override protected[session] def stop(): Unit = { zoningTimer.cancel() spawn.respawnTimer.cancel() diff --git a/src/main/scala/net/psforever/objects/global/GlobalDefinitionsMiscellaneous.scala b/src/main/scala/net/psforever/objects/global/GlobalDefinitionsMiscellaneous.scala index 12868e001..41b224adc 100644 --- a/src/main/scala/net/psforever/objects/global/GlobalDefinitionsMiscellaneous.scala +++ b/src/main/scala/net/psforever/objects/global/GlobalDefinitionsMiscellaneous.scala @@ -698,6 +698,7 @@ object GlobalDefinitionsMiscellaneous { spawn_tube_door_coffin.Damageable = true resource_silo.Name = "resource_silo" + resource_silo.UseRadius = 22 //20 resource_silo.Damageable = false resource_silo.Repairable = false resource_silo.MaxNtuCapacitor = 1000 diff --git a/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala b/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala index 0f8eceb58..a892e21b0 100644 --- a/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala @@ -1,7 +1,7 @@ // Copyright (c) 2019 PSForever package net.psforever.objects.serverobject.resourcesilo -import akka.actor.{Actor, ActorRef} +import akka.actor.{Actor, ActorRef, Cancellable} import net.psforever.objects.serverobject.CommonMessages import net.psforever.actors.zone.BuildingActor import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior} @@ -53,37 +53,31 @@ class ResourceSiloControl(resourceSilo: ResourceSilo) checkBehavior .orElse(storageBehavior) .orElse { - case CommonMessages.Use(player, _) => + case CommonMessages.Use(_, Some(vehicle: Vehicle)) + if GlobalDefinitions.isBattleFrameVehicle(vehicle.Definition) => val siloFaction = resourceSilo.Faction - val playerFaction = player.Faction - resourceSilo.Zone.Vehicles.find(v => v.PassengerInSeat(player).contains(0)) match { - case Some(vehicle) => - (if (GlobalDefinitions.isBattleFrameVehicle(vehicle.Definition)) { - //bfr's discharge into friendly silos and charge from enemy and neutral silos - if (siloFaction == playerFaction) { - Some(TransferBehavior.Discharging(Ntu.Nanites)) - } else if (resourceSilo.MaxNtuCapacitor * 0.4f < resourceSilo.NtuCapacitor) { - //the bfr never drains below 40% - Some(TransferBehavior.Charging(Ntu.Nanites)) - } else { - None - } - } else if(siloFaction == PlanetSideEmpire.NEUTRAL || siloFaction == playerFaction) { - //ants discharge into neutral and friendly silos - Some(TransferBehavior.Discharging(Ntu.Nanites)) - } else { - None - }) match { - case Some(msg) => - context.system.scheduler.scheduleOnce( - delay = 1000 milliseconds, - vehicle.Actor, - msg - ) - case None => ; - } - case _ => ; + val vehicleFaction = vehicle.Faction + val msgOpt = if (siloFaction == vehicleFaction) { + Some(TransferBehavior.Discharging(Ntu.Nanites)) + } else if (resourceSilo.MaxNtuCapacitor * 0.4f < resourceSilo.NtuCapacitor) { + //the bfr never drains below 40% + Some(TransferBehavior.Charging(Ntu.Nanites)) + } else { + None } + msgOpt.collect { SendNtuMessage(vehicle.Actor, _) } + + case CommonMessages.Use(_, Some(vehicle: Vehicle)) + if vehicle.Definition == GlobalDefinitions.ant => + val siloFaction = resourceSilo.Faction + val vehicleFaction = vehicle.Faction + val msgOpt = if (siloFaction == PlanetSideEmpire.NEUTRAL || siloFaction == vehicleFaction) { + //ants discharge into neutral and friendly silos + Some(TransferBehavior.Discharging(Ntu.Nanites)) + } else { + None + } + msgOpt.collect { SendNtuMessage(vehicle.Actor, _) } case ResourceSilo.LowNtuWarning(enabled: Boolean) => LowNtuWarning(enabled) @@ -91,9 +85,13 @@ class ResourceSiloControl(resourceSilo: ResourceSilo) case ResourceSilo.UpdateChargeLevel(amount: Float) => UpdateChargeLevel(amount) - case _ => ; + case _ => () } + def SendNtuMessage(replyTo: ActorRef, msg: Any): Cancellable = { + context.system.scheduler.scheduleOnce(delay = 1000 milliseconds, replyTo, msg) + } + def LowNtuWarning(enabled: Boolean): Unit = { resourceSilo.LowNtuWarningOn = enabled log.trace(s"LowNtuWarning: Silo ${resourceSilo.GUID} low ntu warning set to $enabled") @@ -147,6 +145,7 @@ class ResourceSiloControl(resourceSilo: ResourceSilo) * The silo will agree to offers until its nanite capacitor is completely full. */ def HandleNtuOffer(sender: ActorRef, src: NtuContainer): Unit = { + //todo if I want to test conditions towards continuing ntu transfers, do those here sender ! (if (resourceSilo.NtuCapacitor < resourceSilo.MaxNtuCapacitor) { Ntu.Request(0, resourceSilo.MaxNtuCapacitor - resourceSilo.NtuCapacitor) } else { diff --git a/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala index 02191e393..adea8ef27 100644 --- a/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala @@ -5,6 +5,7 @@ import akka.actor.{ActorRef, Cancellable} import net.psforever.objects.sourcing.AmenitySource import org.log4s.Logger +import scala.annotation.unused import scala.collection.mutable import scala.concurrent.duration._ // @@ -121,6 +122,7 @@ class ProximityTerminalControl(term: Terminal with ProximityUnit) } def unpoweredStateLogic : Receive = commonBehavior + .orElse(clearHackBehavior) .orElse { case CommonMessages.Use(_, _) => log.warn(s"unexpected format for CommonMessages.Use in this context") @@ -145,7 +147,7 @@ class ProximityTerminalControl(term: Terminal with ProximityUnit) isPowered && super.tryAutoRepair() } - def Use(target: PlanetSideGameObject, zone: String, callback: ActorRef): Unit = { + def Use(target: PlanetSideGameObject, @unused zone: String, callback: ActorRef): Unit = { val hadNoUsers = term.NumberUsers == 0 if (term.AddUser(target)) { log.trace(s"ProximityTerminal.Use: unit ${term.Definition.Name}@${term.GUID.guid} will act on $target") @@ -169,7 +171,7 @@ class ProximityTerminalControl(term: Terminal with ProximityUnit) } } - def Unuse(target: PlanetSideGameObject, zone: String): Unit = { + def Unuse(target: PlanetSideGameObject, @unused zone: String): Unit = { val whereTarget = term.Targets.indexWhere(_ eq target) val previousUsers = term.NumberUsers val hadUsers = previousUsers > 0 @@ -223,7 +225,7 @@ object ProximityTerminalControl { * @param target the object being affected by the unit */ def selectAndTryProximityUnitBehavior( - callback: ActorRef, + @unused callback: ActorRef, terminal: Terminal with ProximityUnit, target: PlanetSideGameObject ): Boolean = { diff --git a/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala b/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala index e40369d9a..5f172c8c0 100644 --- a/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala @@ -104,9 +104,14 @@ class FacilityTurretControl(turret: FacilityTurret) } override protected def tryMount(obj: PlanetSideServerObject with Mountable, seatNumber: Int, player: Player): Boolean = { + val originalAutoState = AutomaticOperation AutomaticOperation = false //turn off + if (JammableObject.Jammed) { + val zone = TurretObject.Zone + AutomatedTurretBehavior.stopTracking(zone, zone.id, TurretObject.GUID) //can not recover lost jamming aggro + } if (!super.tryMount(obj, seatNumber, player)) { - AutomaticOperation = true //revert? + AutomaticOperation = originalAutoState //revert false } else { true