mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-01-19 18:44:45 +00:00
commit
5b9e0ec384
|
|
@ -91,7 +91,7 @@ add_property super_staminakit nodrop false
|
||||||
add_property super_staminakit requirement_award0 false
|
add_property super_staminakit requirement_award0 false
|
||||||
add_property suppressor equiptime 600
|
add_property suppressor equiptime 600
|
||||||
add_property suppressor holstertime 600
|
add_property suppressor holstertime 600
|
||||||
add_property trek allowed false
|
add_property trek allowed true
|
||||||
add_property trek equiptime 500
|
add_property trek equiptime 500
|
||||||
add_property trek holstertime 500
|
add_property trek holstertime 500
|
||||||
add_property vulture requirement_award0 false
|
add_property vulture requirement_award0 false
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@
|
||||||
package net.psforever.actors.session.normal
|
package net.psforever.actors.session.normal
|
||||||
|
|
||||||
import akka.actor.ActorContext
|
import akka.actor.ActorContext
|
||||||
import net.psforever.actors.session.support.{LocalHandlerFunctions, SessionData, SessionLocalHandlers}
|
import net.psforever.actors.session.support.SpawnOperations.ActivityQueuedTask
|
||||||
|
import net.psforever.actors.session.support.{LocalHandlerFunctions, SessionData, SessionLocalHandlers, SpawnOperations}
|
||||||
import net.psforever.objects.ce.Deployable
|
import net.psforever.objects.ce.Deployable
|
||||||
import net.psforever.objects.serverobject.doors.Door
|
import net.psforever.objects.serverobject.doors.Door
|
||||||
import net.psforever.objects.vehicles.MountableWeapons
|
import net.psforever.objects.vehicles.MountableWeapons
|
||||||
|
|
@ -191,7 +192,17 @@ class LocalHandlerLogic(val ops: SessionLocalHandlers, implicit val context: Act
|
||||||
sessionLogic.general.useRouterTelepadEffect(passengerGuid, srcGuid, destGuid)
|
sessionLogic.general.useRouterTelepadEffect(passengerGuid, srcGuid, destGuid)
|
||||||
|
|
||||||
case LocalResponse.SendResponse(msg) =>
|
case LocalResponse.SendResponse(msg) =>
|
||||||
sendResponse(msg)
|
msg match {
|
||||||
|
case m: GenericObjectActionMessage =>
|
||||||
|
// delay building virus alert if player is dead/respawning
|
||||||
|
if ((m.code == 58 || m.code == 60 || m.code == 61) && !sessionLogic.zoning.spawn.startEnqueueSquadMessages) {
|
||||||
|
sessionLogic.zoning.spawn.enqueueNewActivity(ActivityQueuedTask(
|
||||||
|
SpawnOperations.delaySendGenericObjectActionMessage(msg), 1))
|
||||||
|
}
|
||||||
|
else sendResponse(msg)
|
||||||
|
case _ =>
|
||||||
|
sendResponse(msg)
|
||||||
|
}
|
||||||
|
|
||||||
case LocalResponse.SetEmpire(objectGuid, empire) =>
|
case LocalResponse.SetEmpire(objectGuid, empire) =>
|
||||||
sendResponse(SetEmpireMessage(objectGuid, empire))
|
sendResponse(SetEmpireMessage(objectGuid, empire))
|
||||||
|
|
|
||||||
|
|
@ -1258,7 +1258,12 @@ class GeneralOperations(
|
||||||
def handleUseTerminal(terminal: Terminal, equipment: Option[Equipment], msg: UseItemMessage): Unit = {
|
def handleUseTerminal(terminal: Terminal, equipment: Option[Equipment], msg: UseItemMessage): Unit = {
|
||||||
equipment match {
|
equipment match {
|
||||||
case Some(item) =>
|
case Some(item) =>
|
||||||
sendUseGeneralEntityMessage(terminal, item)
|
if (terminal.Definition == GlobalDefinitions.main_terminal) {
|
||||||
|
sendUseMainTerminalMessage(terminal, item, msg.unk2)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sendUseGeneralEntityMessage(terminal, item)
|
||||||
|
}
|
||||||
case None
|
case None
|
||||||
if terminal.Owner == Building.NoBuilding || terminal.Faction == player.Faction ||
|
if terminal.Owner == Building.NoBuilding || terminal.Faction == player.Faction ||
|
||||||
terminal.HackedBy.nonEmpty || terminal.Faction == PlanetSideEmpire.NEUTRAL =>
|
terminal.HackedBy.nonEmpty || terminal.Faction == PlanetSideEmpire.NEUTRAL =>
|
||||||
|
|
@ -1484,6 +1489,14 @@ class GeneralOperations(
|
||||||
obj.Actor ! CommonMessages.Use(player, Some(equipment))
|
obj.Actor ! CommonMessages.Use(player, Some(equipment))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def sendUseMainTerminalMessage(obj: PlanetSideServerObject, equipment: Equipment, virus: Long): Unit = {
|
||||||
|
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_use")
|
||||||
|
if (player.Faction == obj.Faction)
|
||||||
|
obj.Actor ! CommonMessages.RemoveVirus(player, Some(equipment))
|
||||||
|
else
|
||||||
|
obj.Actor ! CommonMessages.UploadVirus(player, Some(equipment), virus)
|
||||||
|
}
|
||||||
|
|
||||||
def handleUseDefaultEntity(obj: PlanetSideGameObject, equipment: Option[Equipment]): Unit = {
|
def handleUseDefaultEntity(obj: PlanetSideGameObject, equipment: Option[Equipment]): Unit = {
|
||||||
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_use")
|
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_use")
|
||||||
equipment match {
|
equipment match {
|
||||||
|
|
|
||||||
|
|
@ -193,6 +193,10 @@ object SpawnOperations {
|
||||||
def sendEventMessage(msg: ChatMsg)(sessionLogic: SessionData): Unit = {
|
def sendEventMessage(msg: ChatMsg)(sessionLogic: SessionData): Unit = {
|
||||||
sessionLogic.sendResponse(msg)
|
sessionLogic.sendResponse(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def delaySendGenericObjectActionMessage(msg: PlanetSideGamePacket)(sessionLogic: SessionData): Unit = {
|
||||||
|
sessionLogic.sendResponse(msg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ZoningOperations(
|
class ZoningOperations(
|
||||||
|
|
@ -1116,6 +1120,21 @@ class ZoningOperations(
|
||||||
PlanetsideAttributeEnum.ControlConsoleHackUpdate,
|
PlanetsideAttributeEnum.ControlConsoleHackUpdate,
|
||||||
HackCaptureActor.GetHackUpdateAttributeValue(amenity.asInstanceOf[CaptureTerminal], isResecured = false)
|
HackCaptureActor.GetHackUpdateAttributeValue(amenity.asInstanceOf[CaptureTerminal], isResecured = false)
|
||||||
)
|
)
|
||||||
|
case GlobalDefinitions.main_terminal =>
|
||||||
|
val virus = amenity.asInstanceOf[Terminal].Owner.asInstanceOf[Building].virusId
|
||||||
|
val hackStateMap: Map[Long, HackState7] = Map(
|
||||||
|
0L -> HackState7.UnlockDoors,
|
||||||
|
1L -> HackState7.DisableLatticeBenefits,
|
||||||
|
2L -> HackState7.NTUDrain,
|
||||||
|
3L -> HackState7.DisableRadar,
|
||||||
|
4L -> HackState7.AccessEquipmentTerms
|
||||||
|
)
|
||||||
|
val hackState = hackStateMap.getOrElse(virus, HackState7.Unk8)
|
||||||
|
sessionLogic.general.hackObject(amenity.GUID, unk1 = 1114636288L, hackState)
|
||||||
|
if (virus != 8 && !sessionLogic.zoning.spawn.startEnqueueSquadMessages) {
|
||||||
|
sessionLogic.zoning.spawn.enqueueNewActivity(ActivityQueuedTask(
|
||||||
|
SpawnOperations.delaySendGenericObjectActionMessage(GenericObjectActionMessage(amenityId, 58)), 1))
|
||||||
|
}
|
||||||
case _ =>
|
case _ =>
|
||||||
sessionLogic.general.hackObject(amenity.GUID, unk1 = 1114636288L, HackState7.Unk8) //generic hackable object
|
sessionLogic.general.hackObject(amenity.GUID, unk1 = 1114636288L, HackState7.Unk8) //generic hackable object
|
||||||
}
|
}
|
||||||
|
|
@ -2928,7 +2947,8 @@ class ZoningOperations(
|
||||||
val searhusBenefit = Zones.zones.find(_.Number == 9).exists(_.benefitRecipient == player.Faction)
|
val searhusBenefit = Zones.zones.find(_.Number == 9).exists(_.benefitRecipient == player.Faction)
|
||||||
//biolabs have/grant benefits
|
//biolabs have/grant benefits
|
||||||
val cryoBenefit: Float = toSpawnPoint.Owner match {
|
val cryoBenefit: Float = toSpawnPoint.Owner match {
|
||||||
case b: Building if b.hasLatticeBenefit(LatticeBenefit.BioLaboratory) || (b.BuildingType == StructureType.Facility && !b.CaptureTerminalIsHacked && searhusBenefit) => 0.5f
|
case b: Building if (b.hasLatticeBenefit(LatticeBenefit.BioLaboratory) && b.virusId != 1) ||
|
||||||
|
(b.BuildingType == StructureType.Facility && !b.CaptureTerminalIsHacked && searhusBenefit) => 0.5f
|
||||||
case _ => 1f
|
case _ => 1f
|
||||||
}
|
}
|
||||||
//TODO cumulative death penalty
|
//TODO cumulative death penalty
|
||||||
|
|
|
||||||
|
|
@ -158,6 +158,7 @@ case object MajorFacilityLogic
|
||||||
* @return the next behavior for this control agency messaging system
|
* @return the next behavior for this control agency messaging system
|
||||||
*/
|
*/
|
||||||
def amenityStateChange(details: BuildingWrapper, entity: Amenity, data: Option[Any]): Behavior[Command] = {
|
def amenityStateChange(details: BuildingWrapper, entity: Amenity, data: Option[Any]): Behavior[Command] = {
|
||||||
|
import net.psforever.objects.GlobalDefinitions
|
||||||
entity match {
|
entity match {
|
||||||
case gen: Generator =>
|
case gen: Generator =>
|
||||||
if (generatorStateChange(details, gen, data)) {
|
if (generatorStateChange(details, gen, data)) {
|
||||||
|
|
@ -176,12 +177,24 @@ case object MajorFacilityLogic
|
||||||
case _ =>
|
case _ =>
|
||||||
log(details).warn("CaptureTerminal AmenityStateChange was received with no attached data.")
|
log(details).warn("CaptureTerminal AmenityStateChange was received with no attached data.")
|
||||||
}
|
}
|
||||||
// When a CC is hacked (or resecured) all currently hacked amenities for the base should return to their default unhacked state
|
// When a CC is hacked (or resecured) clear hacks on amenities based on currently installed virus
|
||||||
building.HackableAmenities.foreach(amenity => {
|
val hackedAmenities = building.HackableAmenities.filter(_.HackedBy.isDefined)
|
||||||
if (amenity.HackedBy.isDefined) {
|
val amenitiesToClear = building.virusId match {
|
||||||
building.Zone.LocalEvents ! LocalServiceMessage(amenity.Zone.id,LocalAction.ClearTemporaryHack(PlanetSideGUID(0), amenity))
|
case 0 =>
|
||||||
}
|
hackedAmenities.filterNot(a => a.Definition == GlobalDefinitions.lock_external || a.Definition == GlobalDefinitions.main_terminal)
|
||||||
})
|
case 4 =>
|
||||||
|
hackedAmenities.filterNot(a => a.Definition == GlobalDefinitions.order_terminal || a.Definition == GlobalDefinitions.main_terminal)
|
||||||
|
case 8 =>
|
||||||
|
hackedAmenities
|
||||||
|
case _ =>
|
||||||
|
hackedAmenities
|
||||||
|
}
|
||||||
|
amenitiesToClear.foreach { amenity =>
|
||||||
|
building.Zone.LocalEvents ! LocalServiceMessage(
|
||||||
|
amenity.Zone.id,
|
||||||
|
LocalAction.ClearTemporaryHack(PlanetSideGUID(0), amenity)
|
||||||
|
)
|
||||||
|
}
|
||||||
// No map update needed - will be sent by `HackCaptureActor` when required
|
// No map update needed - will be sent by `HackCaptureActor` when required
|
||||||
case _ =>
|
case _ =>
|
||||||
details.galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(details.building.infoUpdateMessage()))
|
details.galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(details.building.infoUpdateMessage()))
|
||||||
|
|
|
||||||
|
|
@ -1239,6 +1239,8 @@ object GlobalDefinitions {
|
||||||
|
|
||||||
val vanu_control_console = new CaptureTerminalDefinition(930) // Cavern CC
|
val vanu_control_console = new CaptureTerminalDefinition(930) // Cavern CC
|
||||||
|
|
||||||
|
val main_terminal = new MainTerminalDefinition(473)
|
||||||
|
|
||||||
val llm_socket = new CaptureFlagSocketDefinition()
|
val llm_socket = new CaptureFlagSocketDefinition()
|
||||||
|
|
||||||
val capture_flag = new CaptureFlagDefinition()
|
val capture_flag = new CaptureFlagDefinition()
|
||||||
|
|
|
||||||
|
|
@ -72,9 +72,9 @@ object FirstTimeEvents {
|
||||||
)
|
)
|
||||||
|
|
||||||
val Other: Set[String] = Set(
|
val Other: Set[String] = Set(
|
||||||
"used_nchev_scattercannon",
|
"used_nc_hev_scattercannon",
|
||||||
"used_nchev_falcon",
|
"used_nc_hev_falcon",
|
||||||
"used_nchev_sparrow",
|
"used_nc_hev_sparrow",
|
||||||
"used_energy_gun_nc",
|
"used_energy_gun_nc",
|
||||||
"visited_portable_manned_turret_nc"
|
"visited_portable_manned_turret_nc"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -720,6 +720,10 @@ object GlobalDefinitionsMiscellaneous {
|
||||||
vanu_control_console.Repairable = false
|
vanu_control_console.Repairable = false
|
||||||
vanu_control_console.FacilityHackTime = 10.minutes
|
vanu_control_console.FacilityHackTime = 10.minutes
|
||||||
|
|
||||||
|
main_terminal.Name = "main_terminal"
|
||||||
|
main_terminal.Damageable = false
|
||||||
|
main_terminal.Repairable = false
|
||||||
|
|
||||||
lodestar_repair_terminal.Name = "lodestar_repair_terminal"
|
lodestar_repair_terminal.Name = "lodestar_repair_terminal"
|
||||||
lodestar_repair_terminal.Interval = 1000
|
lodestar_repair_terminal.Interval = 1000
|
||||||
lodestar_repair_terminal.HealAmount = 60
|
lodestar_repair_terminal.HealAmount = 60
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ object CommonMessages {
|
||||||
final case class Hack(player: Player, obj: PlanetSideServerObject with Hackable, data: Option[Any] = None)
|
final case class Hack(player: Player, obj: PlanetSideServerObject with Hackable, data: Option[Any] = None)
|
||||||
final case class ClearHack()
|
final case class ClearHack()
|
||||||
final case class EntityHackState(obj: PlanetSideGameObject with Hackable, hackState: Boolean)
|
final case class EntityHackState(obj: PlanetSideGameObject with Hackable, hackState: Boolean)
|
||||||
|
final case class UploadVirus(player: Player, data: Option[Any] = None, virus: Long)
|
||||||
|
final case class RemoveVirus(player: Player, data: Option[Any])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The message that progresses some form of user-driven activity with a certain eventual outcome
|
* The message that progresses some form of user-driven activity with a certain eventual outcome
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
// Copyright (c) 2020 PSForever
|
// Copyright (c) 2020 PSForever
|
||||||
package net.psforever.objects.serverobject.hackable
|
package net.psforever.objects.serverobject.hackable
|
||||||
|
|
||||||
|
import net.psforever.actors.zone.BuildingActor
|
||||||
import net.psforever.objects.serverobject.structures.{Building, StructureType, WarpGate}
|
import net.psforever.objects.serverobject.structures.{Building, StructureType, WarpGate}
|
||||||
|
import net.psforever.objects.serverobject.terminals.Terminal
|
||||||
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal
|
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal
|
||||||
import net.psforever.objects.{Player, Vehicle}
|
import net.psforever.objects.{GlobalDefinitions, Player, Vehicle}
|
||||||
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
||||||
import net.psforever.packet.game.{HackMessage, HackState, HackState1, HackState7}
|
import net.psforever.packet.game.{GenericObjectActionMessage, HackMessage, HackState, HackState1, HackState7, TriggeredSound}
|
||||||
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
|
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
|
||||||
import net.psforever.services.Service
|
import net.psforever.services.Service
|
||||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
|
|
@ -140,6 +142,141 @@ object GenericHackables {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def FinishVirusAction(target: PlanetSideServerObject with Hackable, user: Player, hackValue: Int, hackClearValue: Int, virus: Long)(): Unit = {
|
||||||
|
import akka.pattern.ask
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
|
val tplayer = user
|
||||||
|
ask(target.Actor, CommonMessages.Hack(tplayer, target))(timeout = 2 second)
|
||||||
|
.mapTo[CommonMessages.EntityHackState]
|
||||||
|
.onComplete {
|
||||||
|
case Success(_) =>
|
||||||
|
val building = target.asInstanceOf[Terminal].Owner.asInstanceOf[Building]
|
||||||
|
val zone = target.Zone
|
||||||
|
val zoneId = zone.id
|
||||||
|
val pguid = tplayer.GUID
|
||||||
|
if (tplayer.Faction == target.Faction) {
|
||||||
|
//clear virus
|
||||||
|
val currVirus = building.virusId
|
||||||
|
building.virusId = 8
|
||||||
|
building.virusInstalledBy = None
|
||||||
|
zone.LocalEvents ! LocalServiceMessage(
|
||||||
|
zoneId,
|
||||||
|
LocalAction
|
||||||
|
.ClearTemporaryHack(pguid, target)
|
||||||
|
)
|
||||||
|
zone.LocalEvents ! LocalServiceMessage(
|
||||||
|
zone.id,
|
||||||
|
LocalAction.SendResponse(GenericObjectActionMessage(target.GUID, 60))
|
||||||
|
)
|
||||||
|
currVirus match {
|
||||||
|
case 0L =>
|
||||||
|
building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.lock_external).foreach { iff =>
|
||||||
|
zone.LocalEvents ! LocalServiceMessage(
|
||||||
|
zoneId,
|
||||||
|
LocalAction.ClearTemporaryHack(PlanetSideGUID(0), iff)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
case 4L =>
|
||||||
|
building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.order_terminal).foreach { term =>
|
||||||
|
zone.LocalEvents ! LocalServiceMessage(
|
||||||
|
zoneId,
|
||||||
|
LocalAction.ClearTemporaryHack(PlanetSideGUID(0), term)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
case _ => ()
|
||||||
|
}
|
||||||
|
building.Actor ! BuildingActor.MapUpdate()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//install virus
|
||||||
|
val currVirus = building.virusId
|
||||||
|
//clear previous virus unlocks to prevent virus stacking
|
||||||
|
currVirus match {
|
||||||
|
case 0L =>
|
||||||
|
if (virus != 0) {
|
||||||
|
building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.lock_external).foreach { iff =>
|
||||||
|
zone.LocalEvents ! LocalServiceMessage(
|
||||||
|
zoneId,
|
||||||
|
LocalAction.ClearTemporaryHack(PlanetSideGUID(0), iff)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 4L =>
|
||||||
|
if (virus != 4) {
|
||||||
|
building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.order_terminal).foreach { term =>
|
||||||
|
zone.LocalEvents ! LocalServiceMessage(
|
||||||
|
zoneId,
|
||||||
|
LocalAction.ClearTemporaryHack(PlanetSideGUID(0), term)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case _ => ()
|
||||||
|
}
|
||||||
|
val virusLength: Map[Long, Int] = Map(
|
||||||
|
0L -> 3600,
|
||||||
|
1L -> 900,
|
||||||
|
2L -> 3600,
|
||||||
|
3L -> 900,
|
||||||
|
4L -> 120
|
||||||
|
)
|
||||||
|
val installedVirusDuration = virusLength(virus)
|
||||||
|
val hackStateMap: Map[Long, HackState7] = Map(
|
||||||
|
0L -> HackState7.UnlockDoors,
|
||||||
|
1L -> HackState7.DisableLatticeBenefits,
|
||||||
|
2L -> HackState7.NTUDrain,
|
||||||
|
3L -> HackState7.DisableRadar,
|
||||||
|
4L -> HackState7.AccessEquipmentTerms
|
||||||
|
)
|
||||||
|
val hackState = hackStateMap.getOrElse(virus, HackState7.Unk8)
|
||||||
|
building.virusId = virus
|
||||||
|
building.virusInstalledBy = Some(tplayer.Faction.id)
|
||||||
|
zone.LocalEvents ! LocalServiceMessage(
|
||||||
|
zoneId,
|
||||||
|
LocalAction.TriggerSound(pguid, TriggeredSound.TREKSuccessful, tplayer.Position, 30, 0.49803925f)
|
||||||
|
)
|
||||||
|
zone.LocalEvents ! LocalServiceMessage(
|
||||||
|
zoneId,
|
||||||
|
LocalAction
|
||||||
|
.HackTemporarily(pguid, zone, target, installedVirusDuration, hackClearValue, installedVirusDuration, unk2=hackState)
|
||||||
|
)
|
||||||
|
zone.LocalEvents ! LocalServiceMessage(
|
||||||
|
zone.id,
|
||||||
|
LocalAction.SendResponse(GenericObjectActionMessage(target.GUID, 61))
|
||||||
|
)
|
||||||
|
zone.LocalEvents ! LocalServiceMessage(
|
||||||
|
zone.id,
|
||||||
|
LocalAction.SendResponse(GenericObjectActionMessage(target.GUID, 58))
|
||||||
|
)
|
||||||
|
//amenities if applicable
|
||||||
|
virus match {
|
||||||
|
case 0L =>
|
||||||
|
building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.lock_external).foreach{ iff =>
|
||||||
|
var setHacked = iff.asInstanceOf[PlanetSideServerObject with Hackable]
|
||||||
|
setHacked.HackedBy = tplayer
|
||||||
|
zone.LocalEvents ! LocalServiceMessage(
|
||||||
|
zoneId,
|
||||||
|
LocalAction.HackTemporarily(pguid, zone, iff, hackValue, hackClearValue, installedVirusDuration)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
case 4L =>
|
||||||
|
building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.order_terminal).foreach{ term =>
|
||||||
|
var setHacked = term.asInstanceOf[PlanetSideServerObject with Hackable]
|
||||||
|
setHacked.HackedBy = tplayer
|
||||||
|
zone.LocalEvents ! LocalServiceMessage(
|
||||||
|
zoneId,
|
||||||
|
LocalAction.HackTemporarily(pguid, zone, term, hackValue, hackClearValue, installedVirusDuration)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
case _ => ()
|
||||||
|
}
|
||||||
|
building.Actor ! BuildingActor.MapUpdate()
|
||||||
|
}
|
||||||
|
case Failure(_) =>
|
||||||
|
log.warn(s"Virus action failed on target: ${target.Definition.Name}@${target.GUID.guid}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the state of connected facilities has changed since the hack progress began. It accounts for a friendly facility
|
* Check if the state of connected facilities has changed since the hack progress began. It accounts for a friendly facility
|
||||||
* on the other side of a warpgate as well in case there are no friendly facilities in the same zone
|
* on the other side of a warpgate as well in case there are no friendly facilities in the same zone
|
||||||
|
|
|
||||||
|
|
@ -270,20 +270,19 @@ trait AmenityAutoRepair
|
||||||
autoRepairTimer.cancel()
|
autoRepairTimer.cancel()
|
||||||
autoRepairQueueTask = Some(System.currentTimeMillis() + delay)
|
autoRepairQueueTask = Some(System.currentTimeMillis() + delay)
|
||||||
val modifiedDrain = drain * Config.app.game.amenityAutorepairDrainRate //doubled intentionally
|
val modifiedDrain = drain * Config.app.game.amenityAutorepairDrainRate //doubled intentionally
|
||||||
autoRepairTimer = if(AutoRepairObject.Owner == Building.NoBuilding) {
|
AutoRepairObject.Owner match {
|
||||||
//without an owner, auto-repair freely
|
case Building.NoBuilding =>
|
||||||
context.system.scheduler.scheduleOnce(
|
autoRepairTimer = context.system.scheduler.scheduleOnce(
|
||||||
delay milliseconds,
|
delay.milliseconds,
|
||||||
self,
|
self,
|
||||||
NtuCommand.Grant(null, modifiedDrain)
|
NtuCommand.Grant(null, modifiedDrain))
|
||||||
)
|
case b: Building =>
|
||||||
} else {
|
val doubledDrain = if (b.virusId == 2) modifiedDrain * 2 else modifiedDrain
|
||||||
//ask politely
|
autoRepairTimer = context.system.scheduler.scheduleOnce(
|
||||||
context.system.scheduler.scheduleOnce(
|
delay.milliseconds,
|
||||||
delay milliseconds,
|
b.Actor,
|
||||||
AutoRepairObject.Owner.Actor,
|
BuildingActor.Ntu(NtuCommand.Request(doubledDrain, ntuGrantActorRef)))
|
||||||
BuildingActor.Ntu(NtuCommand.Request(modifiedDrain, ntuGrantActorRef))
|
case _ => ()
|
||||||
)
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
|
||||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.objects.zones.blockmap.BlockMapEntity
|
import net.psforever.objects.zones.blockmap.BlockMapEntity
|
||||||
import net.psforever.packet.game.{BuildingInfoUpdateMessage, DensityLevelUpdateMessage}
|
import net.psforever.packet.game.{Additional3, BuildingInfoUpdateMessage, DensityLevelUpdateMessage}
|
||||||
import net.psforever.types._
|
import net.psforever.types._
|
||||||
import scalax.collection.{Graph, GraphEdge}
|
import scalax.collection.{Graph, GraphEdge}
|
||||||
import akka.actor.typed.scaladsl.adapter._
|
import akka.actor.typed.scaladsl.adapter._
|
||||||
|
|
@ -34,6 +34,8 @@ class Building(
|
||||||
private var playersInSOI: List[Player] = List.empty
|
private var playersInSOI: List[Player] = List.empty
|
||||||
private var forceDomeActive: Boolean = false
|
private var forceDomeActive: Boolean = false
|
||||||
private var participationFunc: ParticipationLogic = NoParticipation
|
private var participationFunc: ParticipationLogic = NoParticipation
|
||||||
|
var virusId: Long = 8 // 8 default = no virus
|
||||||
|
var virusInstalledBy: Option[Int] = None // faction id
|
||||||
super.Zone_=(zone)
|
super.Zone_=(zone)
|
||||||
super.GUID_=(PlanetSideGUID(building_guid)) //set
|
super.GUID_=(PlanetSideGUID(building_guid)) //set
|
||||||
Invalidate() //unset; guid can be used during setup, but does not stop being registered properly later
|
Invalidate() //unset; guid can be used during setup, but does not stop being registered properly later
|
||||||
|
|
@ -211,6 +213,12 @@ class Building(
|
||||||
} else {
|
} else {
|
||||||
Set(CavernBenefit.None)
|
Set(CavernBenefit.None)
|
||||||
}
|
}
|
||||||
|
val (installedVirus, installedByFac) = if (virusId == 8) {
|
||||||
|
(8, None)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
(virusId.toInt, Some(Additional3(inform_defenders=true, virusInstalledBy.getOrElse(3))))
|
||||||
|
}
|
||||||
|
|
||||||
BuildingInfoUpdateMessage(
|
BuildingInfoUpdateMessage(
|
||||||
Zone.Number,
|
Zone.Number,
|
||||||
|
|
@ -230,8 +238,8 @@ class Building(
|
||||||
unk4 = Nil,
|
unk4 = Nil,
|
||||||
unk5 = 0,
|
unk5 = 0,
|
||||||
unk6 = false,
|
unk6 = false,
|
||||||
unk7 = 8, // unk7 != 8 will cause malformed packet
|
installedVirus,
|
||||||
unk7x = None,
|
installedByFac,
|
||||||
boostSpawnPain,
|
boostSpawnPain,
|
||||||
boostGeneratorPain
|
boostGeneratorPain
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ trait FacilityHackParticipation extends ParticipationLogic {
|
||||||
.filterNot { p =>
|
.filterNot { p =>
|
||||||
playerContribution.exists { case (u, _) => p.CharId == u }
|
playerContribution.exists { case (u, _) => p.CharId == u }
|
||||||
}
|
}
|
||||||
|
informOfInstalledVirus(newParticipants)
|
||||||
playerContribution =
|
playerContribution =
|
||||||
vanguardParticipants.map { case (u, (p, d, _)) => (u, (p, d + 1, curr)) } ++
|
vanguardParticipants.map { case (u, (p, d, _)) => (u, (p, d + 1, curr)) } ++
|
||||||
newParticipants.map { p => (p.CharId, (p, 1, curr)) } ++
|
newParticipants.map { p => (p.CharId, (p, 1, curr)) } ++
|
||||||
|
|
@ -96,6 +97,27 @@ trait FacilityHackParticipation extends ParticipationLogic {
|
||||||
}) :+ newEntry
|
}) :+ newEntry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send packet that makes building lights green in case a virus was installed before this player got there
|
||||||
|
* @param list new players to the SOI
|
||||||
|
*/
|
||||||
|
protected def informOfInstalledVirus(list : List[Player]): Unit = {
|
||||||
|
if (building.virusId != 8) {
|
||||||
|
import net.psforever.objects.serverobject.terminals.Terminal
|
||||||
|
import net.psforever.objects.GlobalDefinitions
|
||||||
|
import net.psforever.services.Service
|
||||||
|
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
|
val mainTerm = building.Amenities.filter(x => x.isInstanceOf[Terminal] && x.Definition == GlobalDefinitions.main_terminal).head.GUID
|
||||||
|
val msg1 = AvatarAction.GenericObjectAction(Service.defaultPlayerGUID, mainTerm, 61)
|
||||||
|
val msg2 = AvatarAction.GenericObjectAction(Service.defaultPlayerGUID, mainTerm, 58)
|
||||||
|
val events = building.Zone.AvatarEvents
|
||||||
|
list.foreach { p =>
|
||||||
|
events ! AvatarServiceMessage(p.Name, msg1)
|
||||||
|
events ! AvatarServiceMessage(p.Name, msg2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object FacilityHackParticipation {
|
object FacilityHackParticipation {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright (c) 2025 PSForever
|
||||||
|
package net.psforever.objects.serverobject.terminals
|
||||||
|
|
||||||
|
import akka.actor.ActorContext
|
||||||
|
import net.psforever.objects.{Default, Player}
|
||||||
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
|
import net.psforever.objects.serverobject.structures.Amenity
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The definition for any `Terminal` that is of a type "main_terminal".
|
||||||
|
* Main terminal objects are used to upload or remove a virus from a major facility
|
||||||
|
* @param objectId the object's identifier number
|
||||||
|
*/
|
||||||
|
class MainTerminalDefinition(objectId: Int) extends TerminalDefinition(objectId) {
|
||||||
|
def Request(player: Player, msg: Any): Terminal.Exchange = Terminal.NoDeal()
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
package net.psforever.objects.serverobject.terminals
|
package net.psforever.objects.serverobject.terminals
|
||||||
|
|
||||||
import akka.actor.ActorRef
|
import akka.actor.ActorRef
|
||||||
import net.psforever.objects.{GlobalDefinitions, SimpleItem}
|
import net.psforever.objects.{GlobalDefinitions, SimpleItem, Tool}
|
||||||
import net.psforever.objects.serverobject.CommonMessages
|
import net.psforever.objects.serverobject.CommonMessages
|
||||||
import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
|
import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
|
||||||
import net.psforever.objects.serverobject.damage.Damageable.Target
|
import net.psforever.objects.serverobject.damage.Damageable.Target
|
||||||
|
|
@ -57,7 +57,28 @@ class TerminalControl(term: Terminal)
|
||||||
)
|
)
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
|
case CommonMessages.UploadVirus(player, Some(item: Tool), virus)
|
||||||
|
if item.Definition == GlobalDefinitions.trek =>
|
||||||
|
term.Owner match {
|
||||||
|
case _: Building =>
|
||||||
|
sender() ! CommonMessages.Progress(
|
||||||
|
1.66f,
|
||||||
|
GenericHackables.FinishVirusAction(term, player, hackValue = -1, hackClearValue = -1, virus),
|
||||||
|
GenericHackables.HackingTickAction(HackState1.Unk1, player, term, item.GUID)
|
||||||
|
)
|
||||||
|
case _ => ()
|
||||||
|
}
|
||||||
|
case CommonMessages.RemoveVirus(player, Some(item: SimpleItem))
|
||||||
|
if item.Definition == GlobalDefinitions.remote_electronics_kit =>
|
||||||
|
term.Owner match {
|
||||||
|
case _: Building =>
|
||||||
|
sender() ! CommonMessages.Progress(
|
||||||
|
1.66f,
|
||||||
|
GenericHackables.FinishVirusAction(term, player, hackValue = -1, hackClearValue = -1, virus=8L),
|
||||||
|
GenericHackables.HackingTickAction(HackState1.Unk1, player, term, item.GUID)
|
||||||
|
)
|
||||||
|
case _ => ()
|
||||||
|
}
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,12 @@ final case class Additional1(unk1: String, unk2: Int, unk3: Long)
|
||||||
final case class Additional2(unk1: Int, unk2: Long)
|
final case class Additional2(unk1: Int, unk2: Long)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* na
|
* Used for building information window on map. Tells the empire who installed the virus which one
|
||||||
* @param unk1 na
|
* and tells the defending faction generic "Infected"
|
||||||
* @param unk2 na
|
* @param inform_defenders na
|
||||||
|
* @param installed_by_id na
|
||||||
*/
|
*/
|
||||||
final case class Additional3(unk1: Boolean, unk2: Int)
|
final case class Additional3(inform_defenders: Boolean, installed_by_id: Int)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the state of map asset for a client's specific building's state.
|
* Update the state of map asset for a client's specific building's state.
|
||||||
|
|
@ -73,9 +74,14 @@ final case class Additional3(unk1: Boolean, unk2: Int)
|
||||||
* @param unk4 na
|
* @param unk4 na
|
||||||
* @param unk5 na
|
* @param unk5 na
|
||||||
* @param unk6 na
|
* @param unk6 na
|
||||||
* @param unk7 na;
|
* @param virus_id id of virus installed. value != 8 causes the next field to be defined.
|
||||||
* value != 8 causes the next field to be defined
|
* 0 - unlock all doors
|
||||||
* @param unk7x na
|
* 1 - disable linked benefits
|
||||||
|
* 2 - double ntu drain
|
||||||
|
* 3 - disable enemy radar
|
||||||
|
* 4 - access equipment terminals
|
||||||
|
* 8 - no virus installed - if 8, virus_installed_by is None
|
||||||
|
* @param virus_installed_by if virus_id = 8, None, else this has bool and id of the empire that installed the virus
|
||||||
* @param boost_spawn_pain if the building has spawn tubes, the (boosted) strength of its enemy pain field
|
* @param boost_spawn_pain if the building has spawn tubes, the (boosted) strength of its enemy pain field
|
||||||
* @param boost_generator_pain if the building has a generator, the (boosted) strength of its enemy pain field
|
* @param boost_generator_pain if the building has a generator, the (boosted) strength of its enemy pain field
|
||||||
*/
|
*/
|
||||||
|
|
@ -97,8 +103,8 @@ final case class BuildingInfoUpdateMessage(
|
||||||
unk4: List[Additional2],
|
unk4: List[Additional2],
|
||||||
unk5: Long,
|
unk5: Long,
|
||||||
unk6: Boolean,
|
unk6: Boolean,
|
||||||
unk7: Int,
|
virus_id: Int,
|
||||||
unk7x: Option[Additional3],
|
virus_installed_by: Option[Additional3],
|
||||||
boost_spawn_pain: Boolean,
|
boost_spawn_pain: Boolean,
|
||||||
boost_generator_pain: Boolean
|
boost_generator_pain: Boolean
|
||||||
) extends PlanetSideGamePacket {
|
) extends PlanetSideGamePacket {
|
||||||
|
|
@ -129,8 +135,8 @@ object BuildingInfoUpdateMessage extends Marshallable[BuildingInfoUpdateMessage]
|
||||||
* A `Codec` for a set of additional fields.
|
* A `Codec` for a set of additional fields.
|
||||||
*/
|
*/
|
||||||
private val additional3_codec: Codec[Additional3] = (
|
private val additional3_codec: Codec[Additional3] = (
|
||||||
("unk1" | bool) ::
|
("inform_defenders" | bool) ::
|
||||||
("unk2" | uint2L)
|
("installed_by_id" | uint2L)
|
||||||
).as[Additional3]
|
).as[Additional3]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -190,8 +196,8 @@ object BuildingInfoUpdateMessage extends Marshallable[BuildingInfoUpdateMessage]
|
||||||
("unk4" | listOfN(uint4L, additional2_codec)) ::
|
("unk4" | listOfN(uint4L, additional2_codec)) ::
|
||||||
("unk5" | uint32L) ::
|
("unk5" | uint32L) ::
|
||||||
("unk6" | bool) ::
|
("unk6" | bool) ::
|
||||||
(("unk7" | uint4L) >>:~ { unk7 =>
|
(("virus_id" | uint4L) >>:~ { virus_id =>
|
||||||
conditional(unk7 != 8, codec = "unk7x" | additional3_codec) ::
|
conditional(virus_id != 8, codec = "virus_installed_by" | additional3_codec) ::
|
||||||
("boost_spawn_pain" | bool) ::
|
("boost_spawn_pain" | bool) ::
|
||||||
("boost_generator_pain" | bool)
|
("boost_generator_pain" | bool)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,9 @@ import shapeless.{::, HNil}
|
||||||
* 53 - Put down an FDU<br/>
|
* 53 - Put down an FDU<br/>
|
||||||
* 56 - Sets vehicle or player to be black ops<br/>
|
* 56 - Sets vehicle or player to be black ops<br/>
|
||||||
* 57 - Reverts player from black ops<br/>
|
* 57 - Reverts player from black ops<br/>
|
||||||
|
* 58 - Virus installed, changes lighting in facility to green
|
||||||
|
* 60 - Virus purged
|
||||||
|
* 61 - Virus recently installed. Counts down from 2 minutes until a new virus can be uploaded
|
||||||
* <br>
|
* <br>
|
||||||
* What are these values?<br>
|
* What are these values?<br>
|
||||||
* 90? - for observed driven BFR's, model pitches up slightly and stops idle animation<br>
|
* 90? - for observed driven BFR's, model pitches up slightly and stops idle animation<br>
|
||||||
|
|
|
||||||
|
|
@ -28,11 +28,11 @@ sealed abstract class HackState7(val value: Int) extends IntEnumEntry
|
||||||
object HackState7 extends IntEnum[HackState7] {
|
object HackState7 extends IntEnum[HackState7] {
|
||||||
val values: IndexedSeq[HackState7] = findValues
|
val values: IndexedSeq[HackState7] = findValues
|
||||||
|
|
||||||
case object Unk0 extends HackState7(value = 0)
|
case object UnlockDoors extends HackState7(value = 0)
|
||||||
case object Unk1 extends HackState7(value = 1)
|
case object DisableLatticeBenefits extends HackState7(value = 1)
|
||||||
case object Unk2 extends HackState7(value = 2)
|
case object NTUDrain extends HackState7(value = 2)
|
||||||
case object Unk3 extends HackState7(value = 3)
|
case object DisableRadar extends HackState7(value = 3)
|
||||||
case object Unk4 extends HackState7(value = 4)
|
case object AccessEquipmentTerms extends HackState7(value = 4)
|
||||||
case object Unk5 extends HackState7(value = 5)
|
case object Unk5 extends HackState7(value = 5)
|
||||||
case object Unk6 extends HackState7(value = 6)
|
case object Unk6 extends HackState7(value = 6)
|
||||||
case object Unk7 extends HackState7(value = 7)
|
case object Unk7 extends HackState7(value = 7)
|
||||||
|
|
|
||||||
|
|
@ -265,8 +265,10 @@ class HackCaptureActor extends Actor {
|
||||||
private def HackCompleted(terminal: CaptureTerminal with Hackable, hackedByFaction: PlanetSideEmpire.Value): Unit = {
|
private def HackCompleted(terminal: CaptureTerminal with Hackable, hackedByFaction: PlanetSideEmpire.Value): Unit = {
|
||||||
val building = terminal.Owner.asInstanceOf[Building]
|
val building = terminal.Owner.asInstanceOf[Building]
|
||||||
if (building.NtuLevel > 0) {
|
if (building.NtuLevel > 0) {
|
||||||
|
building.virusId = 8
|
||||||
|
building.virusInstalledBy = None
|
||||||
log.info(s"Setting base ${building.GUID} / MapId: ${building.MapId} as owned by $hackedByFaction")
|
log.info(s"Setting base ${building.GUID} / MapId: ${building.MapId} as owned by $hackedByFaction")
|
||||||
building.Actor! BuildingActor.SetFaction(hackedByFaction)
|
building.Actor ! BuildingActor.SetFaction(hackedByFaction)
|
||||||
//dispatch to players aligned with the capturing faction within the SOI
|
//dispatch to players aligned with the capturing faction within the SOI
|
||||||
val events = building.Zone.LocalEvents
|
val events = building.Zone.LocalEvents
|
||||||
val msg = LocalAction.SendGenericActionMessage(Service.defaultPlayerGUID, GenericAction.FacilityCaptureFanfare)
|
val msg = LocalAction.SendGenericActionMessage(Service.defaultPlayerGUID, GenericAction.FacilityCaptureFanfare)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package net.psforever.services.local.support
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import akka.actor.{Actor, Cancellable}
|
import akka.actor.{Actor, Cancellable}
|
||||||
import net.psforever.objects.Default
|
import net.psforever.objects.{Default, GlobalDefinitions}
|
||||||
import net.psforever.objects.serverobject.hackable.Hackable
|
import net.psforever.objects.serverobject.hackable.Hackable
|
||||||
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
|
|
@ -30,8 +30,12 @@ class HackClearActor() extends Actor {
|
||||||
def receive: Receive = {
|
def receive: Receive = {
|
||||||
case HackClearActor.ObjectIsHacked(target, zone, unk1, unk2, duration, time) =>
|
case HackClearActor.ObjectIsHacked(target, zone, unk1, unk2, duration, time) =>
|
||||||
val durationMillis = TimeUnit.MILLISECONDS.convert(duration, TimeUnit.SECONDS)
|
val durationMillis = TimeUnit.MILLISECONDS.convert(duration, TimeUnit.SECONDS)
|
||||||
hackedObjects = hackedObjects :+ HackClearActor.HackEntry(target, zone, unk1, unk2, time, durationMillis)
|
val newEntry = HackClearActor.HackEntry(target, zone, unk1, unk2, time, durationMillis)
|
||||||
|
// Remove any existing entry for this GUID + zone in case of virus adding an entry for same target
|
||||||
|
hackedObjects = hackedObjects.filterNot(e => e.target.GUID == target.GUID && e.zone.id == zone.id)
|
||||||
|
hackedObjects = newEntry :: hackedObjects
|
||||||
|
// Sort so they are removed in the correct order
|
||||||
|
hackedObjects = hackedObjects.sortBy(e => e.time + e.duration)
|
||||||
// Restart the timer, in case this is the first object in the hacked objects list
|
// Restart the timer, in case this is the first object in the hacked objects list
|
||||||
RestartTimer()
|
RestartTimer()
|
||||||
|
|
||||||
|
|
@ -49,6 +53,9 @@ class HackClearActor() extends Actor {
|
||||||
entry.unk1,
|
entry.unk1,
|
||||||
entry.unk2
|
entry.unk2
|
||||||
) //call up to the main event system
|
) //call up to the main event system
|
||||||
|
if (entry.target.Definition == GlobalDefinitions.main_terminal) {
|
||||||
|
ClearVirusFromBuilding(entry.target)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
RestartTimer()
|
RestartTimer()
|
||||||
|
|
@ -93,6 +100,29 @@ class HackClearActor() extends Actor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the hack timer expires on a main_terminal, clear the virus from the building and
|
||||||
|
* inform the players in the area
|
||||||
|
* @param target main_terminal object
|
||||||
|
*/
|
||||||
|
private def ClearVirusFromBuilding(target: PlanetSideServerObject): Unit = {
|
||||||
|
import net.psforever.objects.serverobject.structures.Building
|
||||||
|
import net.psforever.objects.serverobject.terminals.Terminal
|
||||||
|
import net.psforever.actors.zone.BuildingActor
|
||||||
|
import net.psforever.services.Service
|
||||||
|
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
|
|
||||||
|
val building = target.asInstanceOf[Terminal].Owner.asInstanceOf[Building]
|
||||||
|
building.virusId = 8
|
||||||
|
building.virusInstalledBy = None
|
||||||
|
val msg = AvatarAction.GenericObjectAction(Service.defaultPlayerGUID, target.GUID, 60)
|
||||||
|
val events = building.Zone.AvatarEvents
|
||||||
|
building.PlayersInSOI.foreach { player =>
|
||||||
|
events ! AvatarServiceMessage(player.Name, msg)
|
||||||
|
}
|
||||||
|
building.Actor ! BuildingActor.MapUpdate()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterate over entries in a `List` until an entry that does not exceed the time limit is discovered.
|
* Iterate over entries in a `List` until an entry that does not exceed the time limit is discovered.
|
||||||
* Separate the original `List` into two:
|
* Separate the original `List` into two:
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,7 @@ object Zones {
|
||||||
"vanu_vehicle_station"
|
"vanu_vehicle_station"
|
||||||
)
|
)
|
||||||
private val basicTerminalTypes =
|
private val basicTerminalTypes =
|
||||||
Seq("order_terminal", "spawn_terminal", "cert_terminal", "order_terminal", "vanu_equipment_term")
|
Seq("order_terminal", "spawn_terminal", "cert_terminal", "order_terminal", "vanu_equipment_term", "main_terminal")
|
||||||
private val spawnPadTerminalTypes = Seq(
|
private val spawnPadTerminalTypes = Seq(
|
||||||
"ground_vehicle_terminal",
|
"ground_vehicle_terminal",
|
||||||
"air_vehicle_terminal",
|
"air_vehicle_terminal",
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,8 @@ class BuildingInfoUpdateMessageTest extends Specification {
|
||||||
unk4,
|
unk4,
|
||||||
unk5,
|
unk5,
|
||||||
unk6,
|
unk6,
|
||||||
unk7,
|
virus_id,
|
||||||
unk7x,
|
virus_installed_by,
|
||||||
boost_spawn_pain,
|
boost_spawn_pain,
|
||||||
boost_generator_pain
|
boost_generator_pain
|
||||||
) =>
|
) =>
|
||||||
|
|
@ -53,8 +53,8 @@ class BuildingInfoUpdateMessageTest extends Specification {
|
||||||
unk4.isEmpty mustEqual true
|
unk4.isEmpty mustEqual true
|
||||||
unk5 mustEqual 0
|
unk5 mustEqual 0
|
||||||
unk6 mustEqual false
|
unk6 mustEqual false
|
||||||
unk7 mustEqual 8
|
virus_id mustEqual 8
|
||||||
unk7x.isEmpty mustEqual true
|
virus_installed_by.isEmpty mustEqual true
|
||||||
boost_spawn_pain mustEqual false
|
boost_spawn_pain mustEqual false
|
||||||
boost_generator_pain mustEqual false
|
boost_generator_pain mustEqual false
|
||||||
case _ =>
|
case _ =>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue