mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-03-05 21:40:24 +00:00
periodic message while the llu is active, whether or not there is a carrier, until the hack is finished
This commit is contained in:
parent
a4084e52ce
commit
e4275cf298
2 changed files with 115 additions and 73 deletions
|
|
@ -22,12 +22,13 @@ import scala.concurrent.duration.DurationInt
|
|||
* Responsible for handling capture flag related lifecycles
|
||||
*/
|
||||
class CaptureFlagManager(zone: Zone) extends Actor {
|
||||
import CaptureFlagManager.CaptureFlagEntry
|
||||
private[this] val log = org.log4s.getLogger(self.path.name)
|
||||
|
||||
private var galaxyService: ActorRef = ActorRef.noSender
|
||||
private var mapUpdateTick: Cancellable = Default.Cancellable
|
||||
/** An internally tracked list of cached flags, to avoid querying the amenity owner each second for flag lookups. */
|
||||
private var flags: List[CaptureFlag] = Nil
|
||||
private var flags: List[CaptureFlagEntry] = Nil
|
||||
|
||||
ServiceManager.serviceManager ! Lookup("galaxy")
|
||||
|
||||
|
|
@ -39,7 +40,6 @@ class CaptureFlagManager(zone: Zone) extends Actor {
|
|||
DoMapUpdate()
|
||||
|
||||
case CaptureFlagManager.SpawnCaptureFlag(capture_terminal, target, hackingFaction) =>
|
||||
val zone = capture_terminal.Zone
|
||||
val socket = capture_terminal.Owner.asInstanceOf[Building].GetFlagSocket.get
|
||||
// Override CC message when looked at
|
||||
zone.LocalEvents ! LocalServiceMessage(
|
||||
|
|
@ -62,16 +62,16 @@ class CaptureFlagManager(zone: Zone) extends Actor {
|
|||
socket.captureFlag = flag
|
||||
TrackFlag(flag)
|
||||
TaskWorkflow.execute(WorldSession.CallBackForTask(
|
||||
GUIDTask.registerObject(socket.Zone.GUID, flag),
|
||||
socket.Zone.LocalEvents,
|
||||
GUIDTask.registerObject(zone.GUID, flag),
|
||||
zone.LocalEvents,
|
||||
LocalServiceMessage(
|
||||
socket.Zone.id,
|
||||
zone.id,
|
||||
LocalAction.LluSpawned(Service.defaultPlayerGUID, flag)
|
||||
)
|
||||
))
|
||||
// Broadcast chat message for LLU spawn
|
||||
val owner = flag.Owner.asInstanceOf[Building]
|
||||
ChatBroadcast(flag.Zone, CaptureFlagChatMessageStrings.CTF_FlagSpawned(owner, flag.Target))
|
||||
CaptureFlagManager.ChatBroadcast(zone, CaptureFlagChatMessageStrings.CTF_FlagSpawned(owner, flag.Target))
|
||||
|
||||
case CaptureFlagManager.Captured(flag: CaptureFlag) =>
|
||||
val name = flag.Carrier match {
|
||||
|
|
@ -79,29 +79,29 @@ class CaptureFlagManager(zone: Zone) extends Actor {
|
|||
case None => "A soldier"
|
||||
}
|
||||
// Trigger Install sound
|
||||
flag.Zone.LocalEvents ! LocalServiceMessage(flag.Zone.id, LocalAction.TriggerSound(PlanetSideGUID(-1), TriggeredSound.LLUInstall, flag.Target.CaptureTerminal.get.Position, 20, 0.8000001f))
|
||||
zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.TriggerSound(PlanetSideGUID(-1), TriggeredSound.LLUInstall, flag.Target.CaptureTerminal.get.Position, 20, 0.8000001f))
|
||||
// Broadcast capture chat message
|
||||
ChatBroadcast(flag.Zone, CaptureFlagChatMessageStrings.CTF_Success(name, flag.Faction, flag.Owner.asInstanceOf[Building].Name))
|
||||
CaptureFlagManager.ChatBroadcast(zone, CaptureFlagChatMessageStrings.CTF_Success(name, flag.Faction, flag.Owner.asInstanceOf[Building].Name))
|
||||
// Despawn flag
|
||||
HandleFlagDespawn(flag)
|
||||
|
||||
case CaptureFlagManager.Lost(flag: CaptureFlag, reason: CaptureFlagLostReasonEnum) =>
|
||||
reason match {
|
||||
case CaptureFlagLostReasonEnum.Resecured =>
|
||||
ChatBroadcast(
|
||||
flag.Zone,
|
||||
CaptureFlagManager.ChatBroadcast(
|
||||
zone,
|
||||
CaptureFlagChatMessageStrings.CTF_Failed_SourceResecured(flag.Owner.asInstanceOf[Building].Name, flag.Faction)
|
||||
)
|
||||
case CaptureFlagLostReasonEnum.TimedOut =>
|
||||
val building = flag.Owner.asInstanceOf[Building]
|
||||
ChatBroadcast(
|
||||
flag.Zone,
|
||||
CaptureFlagManager.ChatBroadcast(
|
||||
zone,
|
||||
CaptureFlagChatMessageStrings.CTF_Failed_TimedOut(building.Name, flag.Target.Name, flag.Faction)
|
||||
)
|
||||
case CaptureFlagLostReasonEnum.FlagLost =>
|
||||
val building = flag.Owner.asInstanceOf[Building]
|
||||
ChatBroadcast(
|
||||
flag.Zone,
|
||||
CaptureFlagManager.ChatBroadcast(
|
||||
zone,
|
||||
CaptureFlagChatMessageStrings.CTF_Failed_FlagLost(building.Name, flag.Faction)
|
||||
)
|
||||
case CaptureFlagLostReasonEnum.Ended =>
|
||||
|
|
@ -110,11 +110,14 @@ class CaptureFlagManager(zone: Zone) extends Actor {
|
|||
HandleFlagDespawn(flag)
|
||||
|
||||
case CaptureFlagManager.PickupFlag(flag: CaptureFlag, player: Player) =>
|
||||
val continent = flag.Zone
|
||||
flag.Carrier = Some(player)
|
||||
continent.LocalEvents ! LocalServiceMessage(continent.id, LocalAction.SendPacket(ObjectAttachMessage(player.GUID, flag.GUID, 252)))
|
||||
continent.LocalEvents ! LocalServiceMessage(continent.id, LocalAction.TriggerSound(PlanetSideGUID(-1), TriggeredSound.LLUPickup, player.Position, 15, volume = 0.8f))
|
||||
ChatBroadcast(flag.Zone, CaptureFlagChatMessageStrings.CTF_FlagPickedUp(player.Name, player.Faction, flag.Owner.asInstanceOf[Building].Name), fanfare = false)
|
||||
zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.SendPacket(ObjectAttachMessage(player.GUID, flag.GUID, 252)))
|
||||
zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.TriggerSound(PlanetSideGUID(-1), TriggeredSound.LLUPickup, player.Position, 15, volume = 0.8f))
|
||||
CaptureFlagManager.ChatBroadcast(
|
||||
zone,
|
||||
CaptureFlagChatMessageStrings.CTF_FlagPickedUp(player.Name, player.Faction, flag.Owner.asInstanceOf[Building].Name),
|
||||
fanfare = false
|
||||
)
|
||||
|
||||
case CaptureFlagManager.DropFlag(flag: CaptureFlag) =>
|
||||
flag.Carrier match {
|
||||
|
|
@ -125,9 +128,13 @@ class CaptureFlagManager(zone: Zone) extends Actor {
|
|||
// Remove attached player from flag
|
||||
flag.Carrier = None
|
||||
// Send drop packet
|
||||
flag.Zone.LocalEvents ! LocalServiceMessage(flag.Zone.id, LocalAction.SendPacket(ObjectDetachMessage(player.GUID, flag.GUID, player.Position, 0, 0, 0)))
|
||||
zone.LocalEvents ! LocalServiceMessage(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)
|
||||
CaptureFlagManager.ChatBroadcast(
|
||||
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(
|
||||
|
|
@ -142,10 +149,10 @@ class CaptureFlagManager(zone: Zone) extends Actor {
|
|||
socket.captureFlag = replacementLlu
|
||||
TrackFlag(replacementLlu)
|
||||
TaskWorkflow.execute(WorldSession.CallBackForTask(
|
||||
GUIDTask.registerObject(socket.Zone.GUID, replacementLlu),
|
||||
socket.Zone.LocalEvents,
|
||||
GUIDTask.registerObject(zone.GUID, replacementLlu),
|
||||
zone.LocalEvents,
|
||||
LocalServiceMessage(
|
||||
socket.Zone.id,
|
||||
zone.id,
|
||||
LocalAction.LluSpawned(Service.defaultPlayerGUID, replacementLlu)
|
||||
)
|
||||
))
|
||||
|
|
@ -158,33 +165,47 @@ class CaptureFlagManager(zone: Zone) extends Actor {
|
|||
}
|
||||
|
||||
private def DoMapUpdate(): Unit = {
|
||||
val flagInfo = flags.map(flag =>
|
||||
val events = zone.LocalEvents
|
||||
val zoneId = zone.id
|
||||
val flagInfo = flags.map { case entry @ CaptureFlagManager.CaptureFlagEntry(flag) =>
|
||||
val owner = flag.Owner.asInstanceOf[Building]
|
||||
val pos = flag.Position
|
||||
val hackTimeRemaining = owner.infoUpdateMessage().hack_time_remaining
|
||||
val nextMessageAfterMinutes = CaptureFlagManager.CaptureFlagCountdownMessages(entry.currentMessageIndex)
|
||||
if (hackTimeRemaining < nextMessageAfterMinutes.minutes.toMillis) {
|
||||
entry.currentMessageIndex += 1
|
||||
val msg = CaptureFlagManager.ComposeWarningMessage(flag, owner.Name, nextMessageAfterMinutes)
|
||||
//can't use ChatBroadcast(...) because the message contents are wide
|
||||
events ! LocalServiceMessage(zoneId, LocalAction.SendResponse(
|
||||
ChatMsg(ChatMessageType.UNK_229, wideContents = true, "", msg, None)
|
||||
))
|
||||
}
|
||||
FlagInfo(
|
||||
u1 = 0,
|
||||
owner_map_id = flag.Owner.asInstanceOf[Building].MapId,
|
||||
owner_map_id = owner.MapId,
|
||||
target_map_id = flag.Target.MapId,
|
||||
x = flag.Position.x,
|
||||
y = flag.Position.y,
|
||||
hack_time_remaining = flag.Owner.asInstanceOf[Building].infoUpdateMessage().hack_time_remaining,
|
||||
x = pos.x,
|
||||
y = pos.y,
|
||||
hack_time_remaining = hackTimeRemaining,
|
||||
is_monolith_unit = false
|
||||
)
|
||||
)
|
||||
}
|
||||
galaxyService ! GalaxyServiceMessage(GalaxyAction.FlagMapUpdate(CaptureFlagUpdateMessage(zone.Number, flagInfo)))
|
||||
}
|
||||
|
||||
private def TrackFlag(flag: CaptureFlag): Unit = {
|
||||
flag.Owner.Amenities = flag
|
||||
flags = flags :+ flag
|
||||
flags = flags :+ CaptureFlagEntry(flag)
|
||||
if (mapUpdateTick.isCancelled) {
|
||||
// Start sending map updates periodically
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
mapUpdateTick = context.system.scheduler.scheduleAtFixedRate(0 seconds, 1 second, self, CaptureFlagManager.MapUpdate())
|
||||
mapUpdateTick = context.system.scheduler.scheduleAtFixedRate(initialDelay = 0 seconds, interval = 1 second, self, CaptureFlagManager.MapUpdate())
|
||||
}
|
||||
}
|
||||
|
||||
private def UntrackFlag(flag: CaptureFlag): Unit = {
|
||||
flag.Owner.RemoveAmenity(flag)
|
||||
flags = flags.filterNot(x => x eq flag)
|
||||
flags = flags.filterNot(x => x.flag eq flag)
|
||||
if (flags.isEmpty) {
|
||||
mapUpdateTick.cancel()
|
||||
DoMapUpdate()
|
||||
|
|
@ -192,7 +213,6 @@ class CaptureFlagManager(zone: Zone) extends Actor {
|
|||
}
|
||||
|
||||
private def HandleFlagDespawn(flag: CaptureFlag): Unit = {
|
||||
val zone = flag.Zone
|
||||
// Remove the flag as an amenity
|
||||
flag.Owner.asInstanceOf[Building].GetFlagSocket.get.captureFlag = None
|
||||
UntrackFlag(flag)
|
||||
|
|
@ -201,6 +221,23 @@ class CaptureFlagManager(zone: Zone) extends Actor {
|
|||
// Then unregister it from the GUID pool
|
||||
TaskWorkflow.execute(GUIDTask.unregisterObject(zone.GUID, flag))
|
||||
}
|
||||
}
|
||||
|
||||
object CaptureFlagManager {
|
||||
sealed trait Command
|
||||
|
||||
final case class SpawnCaptureFlag(capture_terminal: CaptureTerminal, target: Building, hackingFaction: PlanetSideEmpire.Value) extends Command
|
||||
final case class PickupFlag(flag: CaptureFlag, player: Player) extends Command
|
||||
final case class DropFlag(flag: CaptureFlag) extends Command
|
||||
final case class Captured(flag: CaptureFlag) extends Command
|
||||
final case class Lost(flag: CaptureFlag, reason: CaptureFlagLostReasonEnum) extends Command
|
||||
final case class MapUpdate()
|
||||
|
||||
private case class CaptureFlagEntry(flag: CaptureFlag) {
|
||||
var currentMessageIndex: Int = 0
|
||||
}
|
||||
|
||||
val CaptureFlagCountdownMessages: Seq[Int] = Seq(10, 5, 2, 1, 0)
|
||||
|
||||
private def ChatBroadcast(zone: Zone, message: String, fanfare: Boolean = true): Unit = {
|
||||
//todo use UNK_222 sometimes
|
||||
|
|
@ -217,17 +254,22 @@ class CaptureFlagManager(zone: Zone) extends Actor {
|
|||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
object CaptureFlagManager {
|
||||
sealed trait Command
|
||||
|
||||
final case class SpawnCaptureFlag(capture_terminal: CaptureTerminal, target: Building, hackingFaction: PlanetSideEmpire.Value) extends Command
|
||||
final case class PickupFlag(flag: CaptureFlag, player: Player) extends Command
|
||||
final case class DropFlag(flag: CaptureFlag) extends Command
|
||||
final case class Captured(flag: CaptureFlag) extends Command
|
||||
final case class Lost(flag: CaptureFlag, reason: CaptureFlagLostReasonEnum) extends Command
|
||||
final case class MapUpdate()
|
||||
private def ComposeWarningMessage(flag: CaptureFlag, buildingName: String, minutesLeft: Int): String = {
|
||||
import CaptureFlagChatMessageStrings._
|
||||
val carrier = flag.Carrier
|
||||
val hasCarrier = carrier.nonEmpty
|
||||
minutesLeft match {
|
||||
case 1 if hasCarrier =>
|
||||
CTF_Warning_Carrier1Min(carrier.get.Name, flag.Faction, buildingName, flag.Target.Name)
|
||||
case 1 =>
|
||||
CTF_Warning_NoCarrier1Min(buildingName, flag.Faction, flag.Target.Name)
|
||||
case time if hasCarrier =>
|
||||
CTF_Warning_Carrier(carrier.get.Name, flag.Faction, buildingName, flag.Target.Name, time)
|
||||
case time =>
|
||||
CTF_Warning_NoCarrier(buildingName, flag.Faction, flag.Target.Name, time)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object CaptureFlagChatMessageStrings {
|
||||
|
|
@ -263,55 +305,55 @@ object CaptureFlagChatMessageStrings {
|
|||
|
||||
// @CTF_FlagPickedUp=%1 of the %2 picked up %3's LLU
|
||||
/** {player.Name} of the {player.Faction} picked up {ownerName}'s LLU */
|
||||
def CTF_FlagPickedUp(playerName: String, playerFaction: PlanetSideEmpire.Value, ownerName: String): String =
|
||||
private[support] def CTF_FlagPickedUp(playerName: String, playerFaction: PlanetSideEmpire.Value, ownerName: String): String =
|
||||
s"@CTF_FlagPickedUp^$playerName~^@${GetFactionString(playerFaction)}~^@$ownerName~"
|
||||
|
||||
// @CTF_FlagDropped=%1 of the %2 dropped %3's LLU
|
||||
/** {playerName} of the {faction} dropped {facilityName}'s LLU */
|
||||
def CTF_FlagDropped(playerName: String, playerFaction: PlanetSideEmpire.Value, ownerName: String): String =
|
||||
private[support] def CTF_FlagDropped(playerName: String, playerFaction: PlanetSideEmpire.Value, ownerName: String): String =
|
||||
s"@CTF_FlagDropped^$playerName~^@${GetFactionString(playerFaction)}~^@$ownerName~"
|
||||
|
||||
// @CTF_Warning_Carrier=%1's LLU is in the field.\nThe %2 must take it to %3 within %4 minutes!
|
||||
/** {facilityName}'s LLU is in the field.\nThe {faction} must take it to {targetFacilityName} within {time} minutes! */
|
||||
def CTF_Warning_Carrier(
|
||||
playerName:String,
|
||||
playerFaction: PlanetSideEmpire.Value,
|
||||
facilityName: String,
|
||||
targetFacilityName: String,
|
||||
time: Int
|
||||
): String = {
|
||||
private[support] def CTF_Warning_Carrier(
|
||||
playerName:String,
|
||||
playerFaction: PlanetSideEmpire.Value,
|
||||
facilityName: String,
|
||||
targetFacilityName: String,
|
||||
time: Int
|
||||
): String = {
|
||||
s"@CTF_Warning_Carrier^$playerName~^@${GetFactionString(playerFaction)}~^@$facilityName~^@$targetFacilityName~^@$time~"
|
||||
}
|
||||
|
||||
// @CTF_Warning_Carrier1Min=%1 of the %2 has %3's LLU.\nIt must be taken to %4 within the next minute!
|
||||
/** {playerName} of the {faction} has {facilityName}'s LLU.\nIt must be taken to {targetFacilityName} within the next minute! */
|
||||
def CTF_Warning_Carrier1Min(
|
||||
playerName:String,
|
||||
playerFaction: PlanetSideEmpire.Value,
|
||||
facilityName: String,
|
||||
targetFacilityName: String
|
||||
): String = {
|
||||
private[support] def CTF_Warning_Carrier1Min(
|
||||
playerName:String,
|
||||
playerFaction: PlanetSideEmpire.Value,
|
||||
facilityName: String,
|
||||
targetFacilityName: String
|
||||
): String = {
|
||||
s"@CTF_Warning_Carrier1Min^$playerName~^@${GetFactionString(playerFaction)}~^@$facilityName~^@$targetFacilityName~"
|
||||
}
|
||||
|
||||
// @CTF_Warning_NoCarrier=%1's LLU is in the field.\nThe %2 must take it to %3 within %4 minutes!
|
||||
/** {facilityName}'s LLU is in the field.\nThe {faction} must take it to {targetFacilityName} within {time} minute! */
|
||||
def CTF_Warning_NoCarrier(
|
||||
facilityName: String,
|
||||
playerFaction: PlanetSideEmpire.Value,
|
||||
targetFacilityName: String,
|
||||
time: Int
|
||||
): String = {
|
||||
private[support] def CTF_Warning_NoCarrier(
|
||||
facilityName: String,
|
||||
playerFaction: PlanetSideEmpire.Value,
|
||||
targetFacilityName: String,
|
||||
time: Int
|
||||
): String = {
|
||||
s"@CTF_Warning_NoCarrier^@$facilityName~^@${GetFactionString(playerFaction)}~^@$targetFacilityName~^$time~"
|
||||
}
|
||||
|
||||
// @CTF_Warning_NoCarrier1Min=%1's LLU is in the field.\nThe %2 must take it to %3 within the next minute!
|
||||
/** {facilityName}'s LLU is in the field.\nThe {faction} must take it to {targetFacilityName} within the next minute! */
|
||||
def CTF_Warning_NoCarrier1Min(
|
||||
facilityName: String,
|
||||
playerFaction: PlanetSideEmpire.Value,
|
||||
targetFacilityName: String
|
||||
): String = {
|
||||
private[support] def CTF_Warning_NoCarrier1Min(
|
||||
facilityName: String,
|
||||
playerFaction: PlanetSideEmpire.Value,
|
||||
targetFacilityName: String
|
||||
): String = {
|
||||
s"@CTF_Warning_NoCarrier1Min^@$facilityName~^@${GetFactionString(playerFaction)}~^@$targetFacilityName~"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,14 +62,14 @@ class HackCaptureActor extends Actor {
|
|||
// If the base has a socket, but no flag spawned it means the hacked base is neutral with no friendly neighbouring bases to deliver to, making it a timed hack.
|
||||
val building = terminal.Owner.asInstanceOf[Building]
|
||||
building.GetFlag match {
|
||||
case Some(llu) if llu.LastCollectionTime == llu.InitialSpawnTime =>
|
||||
// LLU was never once collected. Send resecured notifications
|
||||
terminal.Zone.LocalEvents ! CaptureFlagManager.Lost(llu, CaptureFlagLostReasonEnum.TimedOut)
|
||||
case Some(llu) if llu.Destroyed =>
|
||||
// LLU was destroyed while in the field. Send resecured notifications
|
||||
terminal.Zone.LocalEvents ! CaptureFlagManager.Lost(llu, CaptureFlagLostReasonEnum.FlagLost)
|
||||
NotifyHackStateChange(terminal, isResecured = true)
|
||||
|
||||
case Some(llu) =>
|
||||
// LLU was not delivered in time. Send resecured notifications
|
||||
terminal.Zone.LocalEvents ! CaptureFlagManager.Lost(llu, CaptureFlagLostReasonEnum.FlagLost)
|
||||
terminal.Zone.LocalEvents ! CaptureFlagManager.Lost(llu, CaptureFlagLostReasonEnum.TimedOut)
|
||||
NotifyHackStateChange(terminal, isResecured = true)
|
||||
|
||||
case _ =>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue