Merge pull request #1146 from ScrawnyRonnie/jammer

Keep the jam going & other misc fixes
This commit is contained in:
Fate-JH 2023-12-18 16:39:25 -05:00 committed by GitHub
commit c99e170a26
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 133 additions and 49 deletions

View file

@ -8926,7 +8926,7 @@
"AbsY": 3742.29175,
"AbsZ": 42.3043633,
"Yaw": 198.0,
"GUID": 713,
"GUID": 715,
"MapID": null,
"IsChildObject": true
},
@ -8939,7 +8939,7 @@
"AbsY": 3729.643,
"AbsZ": 42.3043633,
"Yaw": 288.0,
"GUID": 714,
"GUID": 713,
"MapID": null,
"IsChildObject": true
},
@ -8952,7 +8952,7 @@
"AbsY": 3729.643,
"AbsZ": 49.8043633,
"Yaw": 108.0,
"GUID": 715,
"GUID": 714,
"MapID": null,
"IsChildObject": true
},

View file

@ -10,7 +10,7 @@ import net.psforever.actors.zone.ZoneActor
import net.psforever.objects.avatar.scoring.{Assist, Death, EquipmentStat, KDAStat, Kill, Life, ScoreCard, SupportActivity}
import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.objects.sourcing.VehicleSource
import net.psforever.objects.vital.InGameHistory
import net.psforever.objects.vital.{InGameHistory, ReconstructionActivity}
import net.psforever.objects.vehicles.MountedWeapons
import net.psforever.types.{ChatMessageType, StatisticalCategory, StatisticalElement}
import org.joda.time.{LocalDateTime, Seconds}
@ -235,7 +235,7 @@ object AvatarActor {
final case class SetStamina(stamina: Int) extends Command
private case class SetImplantInitialized(implantType: ImplantType) extends Command
final case class SetImplantInitialized(implantType: ImplantType) extends Command
final case class MemberListRequest(action: MemberAction.Value, name: String) extends Command
@ -1588,8 +1588,68 @@ class AvatarActor(
Behaviors.same
case ResetImplants() =>
deinitializeImplants()
initializeImplants()
val player = session.get.player
// Get time of when you spawned after a deconstruction or zoning activity.
val lastDecon: Long = player.History.findLast {entry => entry.isInstanceOf[ReconstructionActivity]} match {
case Some(entry) => entry.time
case _ => 0L
}
// Get time of when you entered the world or respawned after death.
val lastRespawn: Long = player.History.findLast {entry => entry.isInstanceOf[SpawningActivity]} match {
case Some(entry) => entry.time
case _ => 0L
}
// You didn't die. You deconstructed or changed zones via warpgate/IA/recall.
// When you respawn after death, it does both recon and spawn activities, hence the minus 3000 to make sure
// this doesn't happen at respawn after death.
if (lastDecon - 3000 > lastRespawn) {
deinitializeImplants()
val implants = avatar.implants
implants.zipWithIndex.foreach {
case (Some(implant), slot) =>
sessionActor ! SessionActor.SendResponse(
CreateShortcutMessage(
session.get.player.GUID,
slot + 2,
Some(implant.definition.implantType.shortcut)
)
)
// If the amount of time that has passed since you entered the world or died is > how long it takes to
// initialize this implant, initialize it after 1 second.
if ((System.currentTimeMillis() / 1000) - (lastRespawn / 1000) > implant.definition.InitializationDuration) {
implantTimers.get(slot).foreach(_.cancel())
implantTimers(slot) = context.scheduleOnce(
1.seconds,
context.self,
SetImplantInitialized(implant.definition.implantType)
)
session.get.zone.AvatarEvents ! AvatarServiceMessage(
avatar.name,
AvatarAction.SendResponse(Service.defaultPlayerGUID, ActionProgressMessage(slot + 6, 0))
)
}
// If the implant initialization timer hasn't quite finished, calculate a reduced timer based on last spawn activity
else {
val remainingTime = (lastRespawn / 1000).seconds - (System.currentTimeMillis() / 1000).seconds + implant.definition.InitializationDuration.seconds
implantTimers.get(slot).foreach(_.cancel())
implantTimers(slot) = context.scheduleOnce(
remainingTime,
context.self,
SetImplantInitialized(implant.definition.implantType)
)
session.get.zone.AvatarEvents ! AvatarServiceMessage(
avatar.name,
AvatarAction.SendResponse(Service.defaultPlayerGUID, ActionProgressMessage(slot + 6, 0))
)
}
case (None, _) =>
}
}
// You just entered the world or died. Implants reset and timers start from scratch
else {
deinitializeImplants()
initializeImplants()
}
Behaviors.same
case UpdateToolDischarge(stats) =>

View file

@ -219,7 +219,7 @@ class SessionData(
if (isMovingPlus) {
if (zoning.zoningStatus == Zoning.Status.Deconstructing) {
stopDeconstructing()
} else {
} else if (zoning.zoningStatus != Zoning.Status.None) {
zoning.CancelZoningProcessWithDescriptiveReason("cancel_motion")
}
}

View file

@ -2,6 +2,7 @@
package net.psforever.actors.session.support
import akka.actor.{ActorContext, typed}
import net.psforever.objects.zones.Zoning
import net.psforever.objects.zones.exp.ToDatabase
import scala.collection.mutable
@ -50,7 +51,8 @@ private[support] class WeaponAndProjectileOperations(
private[support] var shotsWhileDead: Int = 0
private val projectiles: Array[Option[Projectile]] =
Array.fill[Option[Projectile]](Projectile.rangeUID - Projectile.baseUID)(None)
private var zoningOpt: Option[ZoningOperations] = None
def zoning: ZoningOperations = zoningOpt.orNull
/* packets */
def handleWeaponFire(pkt: WeaponFireMessage): Unit = {
@ -536,7 +538,9 @@ private[support] class WeaponAndProjectileOperations(
weaponGUID: PlanetSideGUID,
projectileGUID: PlanetSideGUID
): (Option[PlanetSideGameObject with Container], Option[Tool]) = {
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_fire")
if (player.ZoningRequest != Zoning.Method.None) {
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_fire")
}
if (player.isShielded) {
// Cancel NC MAX shield if it's active
sessionData.toggleMaxSpecialState(enable = false)

View file

@ -889,7 +889,7 @@ class ZoningOperations(
def beginZoningCountdown(runnable: Runnable): Unit = {
val descriptor = zoningType.toString.toLowerCase
if (zoningStatus == Zoning.Status.Request) {
avatarActor ! AvatarActor.DeinitializeImplants()
avatarActor ! AvatarActor.DeactivateActiveImplants()
zoningStatus = Zoning.Status.Countdown
val (time, origin) = ZoningStartInitialMessageAndTimer()
zoningCounter = time
@ -2300,18 +2300,8 @@ class ZoningOperations(
//vehicle and driver/passenger
val vdef = vehicle.Definition
val vguid = vehicle.GUID
val vdata = if (seat == 0) {
val seat = vehicle.Seats(0)
seat.unmount(player)
val _vdata = vdef.Packet.ConstructorData(vehicle).get
sendResponse(ObjectCreateMessage(vehicle.Definition.ObjectId, vguid, _vdata))
seat.mount(player)
_vdata
} else {
val _vdata = vdef.Packet.ConstructorData(vehicle).get
sendResponse(ObjectCreateMessage(vehicle.Definition.ObjectId, vguid, _vdata))
_vdata
}
val vdata = vdef.Packet.ConstructorData(vehicle).get
sendResponse(ObjectCreateMessage(vehicle.Definition.ObjectId, vguid, vdata))
Vehicles.ReloadAccessPermissions(vehicle, continent.id)
log.debug(s"AvatarCreate (vehicle): ${player.Name}'s ${vehicle.Definition.Name}")
log.trace(s"AvatarCreate (vehicle): ${player.Name}'s ${vehicle.Definition.Name} - $vguid -> $vdata")
@ -2777,10 +2767,7 @@ class ZoningOperations(
}
val originalDeadState = deadState
deadState = DeadState.Alive
if (originalDeadState != DeadState.Alive) {
avatarActor ! AvatarActor.ResetImplants()
}
avatarActor ! AvatarActor.ResetImplants()
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 82, 0))
initializeShortcutsAndBank(guid)
//Favorites lists

View file

@ -7568,7 +7568,7 @@ object GlobalDefinitions {
apc_tr.UnderwaterLifespan(suffocation = 15000L, recovery = 7500L)
apc_tr.Geometry = apcForm
apc_tr.MaxCapacitor = 300
apc_tr.CapacitorRecharge = 10
apc_tr.CapacitorRecharge = 1
apc_tr.collision.avatarCollisionDamageMax = 300
apc_tr.collision.xy = CollisionXYData(Array((0.1f, 1), (0.25f, 10), (0.5f, 40), (0.75f, 70), (1f, 110)))
apc_tr.collision.z = CollisionZData(Array((2f, 1), (6f, 50), (10f, 300), (12f, 1000), (13f, 3000)))
@ -7638,7 +7638,7 @@ object GlobalDefinitions {
apc_nc.UnderwaterLifespan(suffocation = 15000L, recovery = 7500L)
apc_nc.Geometry = apcForm
apc_nc.MaxCapacitor = 300
apc_nc.CapacitorRecharge = 10
apc_nc.CapacitorRecharge = 1
apc_nc.collision.avatarCollisionDamageMax = 300
apc_nc.collision.xy = CollisionXYData(Array((0.1f, 1), (0.25f, 10), (0.5f, 40), (0.75f, 70), (1f, 110)))
apc_nc.collision.z = CollisionZData(Array((2f, 1), (6f, 50), (10f, 300), (12f, 1000), (13f, 3000)))
@ -7708,7 +7708,7 @@ object GlobalDefinitions {
apc_vs.UnderwaterLifespan(suffocation = 15000L, recovery = 7500L)
apc_vs.Geometry = apcForm
apc_vs.MaxCapacitor = 300
apc_vs.CapacitorRecharge = 10
apc_vs.CapacitorRecharge = 1
apc_vs.collision.avatarCollisionDamageMax = 300
apc_vs.collision.xy = CollisionXYData(Array((0.1f, 1), (0.25f, 10), (0.5f, 40), (0.75f, 70), (1f, 110)))
apc_vs.collision.z = CollisionZData(Array((2f, 1), (6f, 50), (10f, 300), (12f, 1000), (13f, 3000)))

View file

@ -84,7 +84,7 @@ class SensorDeployableControl(sensor: SensorDeployable)
override def StartJammeredStatus(target: Any, dur: Int): Unit =
target match {
case obj: PlanetSideServerObject with JammableUnit if !obj.Jammed =>
case obj: PlanetSideServerObject with JammableUnit =>
val zone = obj.Zone
zone.LocalEvents ! LocalServiceMessage(
zone.id,

View file

@ -124,7 +124,7 @@ class ShieldGeneratorControl(gen: ShieldGeneratorDeployable)
override def StartJammeredStatus(target: Any, dur: Int): Unit =
target match {
case obj: PlanetSideServerObject with JammableUnit if !obj.Jammed =>
case obj: PlanetSideServerObject with JammableUnit =>
obj.Zone.VehicleEvents ! VehicleServiceMessage(
obj.Zone.id,
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 27, 1)

View file

@ -76,10 +76,10 @@ object Vehicles {
val factionChannel = s"${vehicle.Faction}"
(0 to 2).foreach(group => {
vehicle.PermissionGroup(group, empire)
vehicle.Zone.VehicleEvents ! VehicleServiceMessage(
/*vehicle.Zone.VehicleEvents ! VehicleServiceMessage(
factionChannel,
VehicleAction.SeatPermissions(Service.defaultPlayerGUID, guid, group, empire)
)
)*/
})
ReloadAccessPermissions(vehicle, player.Name)
Some(vehicle)
@ -135,10 +135,10 @@ object Vehicles {
val empire = VehicleLockState.Empire.id
(0 to 2).foreach(group => {
vehicle.PermissionGroup(group, empire)
vehicle.Zone.VehicleEvents ! VehicleServiceMessage(
/*vehicle.Zone.VehicleEvents ! VehicleServiceMessage(
s"${vehicle.Faction}",
VehicleAction.SeatPermissions(pguid, vguid, group, empire)
)
)*/
})
ReloadAccessPermissions(vehicle, player.Name)
Some(vehicle)

View file

@ -1309,7 +1309,10 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
* @param data additional interaction information, if applicable
*/
def doInteractingWithDeath(obj: PlanetSideServerObject, body: PieceOfEnvironment, data: Option[OxygenStateTarget]): Unit = {
suicide()
player.History.findLast { entry => entry.isInstanceOf[ReconstructionActivity] } match {
case Some(entry) if System.currentTimeMillis() - entry.time > 4000L => suicide()
case _ =>
}
}
//noinspection ScalaUnusedSymbol

View file

@ -253,7 +253,7 @@ trait JammableMountedWeapons extends JammableBehavior {
override def StartJammeredStatus(target: Any, dur: Int): Unit = {
target match {
case obj: PlanetSideServerObject with MountedWeapons with JammableUnit if !obj.Jammed =>
case obj: PlanetSideServerObject with MountedWeapons with JammableUnit =>
JammableMountedWeaponsJammeredStatus(obj, statusCode = 1)
super.StartJammeredStatus(target, dur)
case _ => ;

View file

@ -79,6 +79,8 @@ object DamageableMountable {
.values
.flatMap { _.occupant }
.collect { case player if player.isAlive =>
//make llu visible to others in zone if passenger is carrying one
player.Zone.AvatarEvents ! AvatarServiceMessage(player.Name, AvatarAction.DropSpecialItem())
//player.LogActivity(cause)
player.Actor ! Player.Die(
DamageInteraction(interaction.resolution, SourceEntry(player), interaction.cause, interaction.hitPos)

View file

@ -23,7 +23,7 @@ import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.objects.sourcing.{PlayerSource, SourceEntry, VehicleSource}
import net.psforever.objects.vehicles._
import net.psforever.objects.vital.interaction.{DamageInteraction, DamageResult}
import net.psforever.objects.vital.{DamagingActivity, InGameActivity, ShieldCharge, SpawningActivity, VehicleDismountActivity, VehicleMountActivity}
import net.psforever.objects.vital.{DamagingActivity, InGameActivity, ReconstructionActivity, ShieldCharge, SpawningActivity, VehicleDismountActivity, VehicleMountActivity}
import net.psforever.objects.vital.environment.EnvironmentReason
import net.psforever.objects.vital.etc.SuicideReason
import net.psforever.objects.zones._
@ -679,14 +679,18 @@ class VehicleControl(vehicle: Vehicle)
*/
def doInteractingWithDeath(obj: PlanetSideServerObject, body: PieceOfEnvironment, data: Option[OxygenStateTarget]): Unit = {
if (!obj.Destroyed) {
PerformDamage(
vehicle,
DamageInteraction(
VehicleSource(vehicle),
SuicideReason(),
vehicle.Position
).calculate()
)
vehicle.History.findLast { entry => entry.isInstanceOf[ReconstructionActivity] } match {
case Some(entry) if System.currentTimeMillis() - entry.time > 4000L =>
PerformDamage(
vehicle,
DamageInteraction(
VehicleSource(vehicle),
SuicideReason(),
vehicle.Position
).calculate()
)
case _ =>
}
}
}
@ -859,10 +863,8 @@ class VehicleControl(vehicle: Vehicle)
override def StartJammeredStatus(target: Any, dur: Int): Unit = {
super.StartJammeredStatus(target, dur)
val subsystems = vehicle.Subsystems()
if (!subsystems.exists { _.Jammed }) {
subsystems.foreach { _.jam() }
vehicleSubsystemMessages(subsystems.flatMap { _.changedMessages(vehicle) })
}
}
override def CancelJammeredStatus(target: Any): Unit = {

View file

@ -365,6 +365,8 @@ class PersistenceMonitor(
def PerformLogout(): Unit = {
(inZone.Players.find(p => p.name == name), inZone.LivePlayers.find(p => p.Name == name)) match {
case (Some(avatar), Some(player)) if player.VehicleSeated.nonEmpty =>
//in case the player is holding the llu and disconnects
player.Zone.AvatarEvents ! AvatarServiceMessage(player.Name, AvatarAction.DropSpecialItem())
//alive or dead in a vehicle
//if the avatar is dead while in a vehicle, they haven't released yet
AvatarActor.saveAvatarData(avatar)
@ -381,6 +383,8 @@ class PersistenceMonitor(
PlayerAvatarLogout(avatar, player)
case (Some(avatar), Some(player)) =>
//in case the player is holding the llu and disconnects
player.Zone.AvatarEvents ! AvatarServiceMessage(player.Name, AvatarAction.DropSpecialItem())
//alive or dead, as standard Infantry
AvatarActor.saveAvatarData(avatar)
AvatarActor.finalSavePlayerData(player)

View file

@ -113,6 +113,7 @@ class CaptureFlagManager(zone: Zone) extends Actor {
case CaptureFlagManager.DropFlag(flag: CaptureFlag) =>
flag.Carrier match {
case Some(player: Player) =>
val newFlag = flag
// Set the flag position to where the player is that dropped it
flag.Position = player.Position
// Remove attached player from flag
@ -121,6 +122,27 @@ class CaptureFlagManager(zone: Zone) extends Actor {
flag.Zone.LocalEvents ! LocalServiceMessage(flag.Zone.id, LocalAction.SendPacket(ObjectDetachMessage(player.GUID, flag.GUID, player.Position, 0, 0, 0)))
// Send dropped chat message
ChatBroadcast(flag.Zone, CaptureFlagChatMessageStrings.CTF_FlagDropped(player.Name, player.Faction, flag.Owner.asInstanceOf[Building].Name), fanfare = false)
HandleFlagDespawn(flag)
// Register LLU object create task and callback to create on clients
val replacementLlu = CaptureFlag.Constructor(
newFlag.Position,
newFlag.Orientation,
newFlag.Target,
newFlag.Owner,
player.Faction
)
// Add the flag as an amenity and track it internally
val socket = newFlag.Owner.asInstanceOf[Building].GetFlagSocket.get
socket.captureFlag = replacementLlu
TrackFlag(replacementLlu)
TaskWorkflow.execute(WorldSession.CallBackForTask(
GUIDTask.registerObject(socket.Zone.GUID, replacementLlu),
socket.Zone.LocalEvents,
LocalServiceMessage(
socket.Zone.id,
LocalAction.LluSpawned(Service.defaultPlayerGUID, replacementLlu)
)
))
case _ =>
log.warn("Tried to drop flag but flag has no carrier")
}