Gating Fixes (#254)

* rescheduling of passenger gating summons to increase chances of detecting passengers joining same zone; short-circuit new spawn requests and new warp gate requests while a previous request is already being processed

* changing respawn delays for warp gate spawn points

* adjusting how warp gates store broadcast data and how broadcast gates are declared in packets; activating TR sanctuary warp gates and making Solsar warp gates broadcast for the TR

* changes to vehicle disowning and what happens to an AMS when it is unloaded
This commit is contained in:
Fate-JH 2019-04-21 08:23:12 -04:00 committed by GitHub
parent 6399963e68
commit 5209f9ec21
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 223 additions and 94 deletions

View file

@ -1039,14 +1039,12 @@ object GlobalDefinitions {
val warpgate : ObjectDefinition with SpawnPointDefinition = new ObjectDefinition(993) with SpawnPointDefinition
warpgate.Name = "warpgate"
warpgate.UseRadius = 301.8713f
warpgate.Delay = 10
warpgate.VehicleAllowance = true
warpgate.SpecificPointFunc = SpawnPoint.Gate
val hst : ObjectDefinition with SpawnPointDefinition = new ObjectDefinition(402) with SpawnPointDefinition
hst.Name = "hst"
hst.UseRadius = 20.4810f
hst.Delay = 10
hst.VehicleAllowance = true
hst.NoWarp += dropship
hst.NoWarp += galaxy_gunship
@ -1062,7 +1060,6 @@ object GlobalDefinitions {
val warpgate_cavern : ObjectDefinition with SpawnPointDefinition = new ObjectDefinition(994) with SpawnPointDefinition
warpgate_cavern.Name = "warpgate_cavern"
warpgate_cavern.UseRadius = 55.0522f
warpgate_cavern.Delay = 10
warpgate_cavern.VehicleAllowance = true
warpgate_cavern.SpecificPointFunc = SpawnPoint.Gate

View file

@ -9,11 +9,15 @@ import net.psforever.objects.zones.Zone
import net.psforever.packet.game.{Additional1, Additional2, Additional3, PlanetSideGeneratorState}
import net.psforever.types.{PlanetSideEmpire, Vector3}
import scala.collection.mutable
class WarpGate(building_guid : Int, map_id : Int, zone : Zone, buildingDefinition : ObjectDefinition with SpawnPointDefinition)
extends Building(building_guid, map_id, zone, StructureType.WarpGate, buildingDefinition)
with SpawnPoint {
/** can this building be used as an active warp gate */
private var active : Boolean = true
private var broadcast : Boolean = false
/** what faction views this warp gate as a broadcast gate */
private var broadcast : mutable.Set[PlanetSideEmpire.Value] = mutable.Set.empty[PlanetSideEmpire.Value]
override def Info : (
Int,
@ -48,18 +52,105 @@ class WarpGate(building_guid : Int, map_id : Int, zone : Zone, buildingDefinitio
)
}
/**
* If a warp gate is active, it can be used to transport faction-affiliated forces between other gates.
* For transportation of faction-opposed forces, use broadcast logic for that faction.
* @return `true`, if the warp gate can be used for transport;
* `false`, otherwise
*/
def Active : Boolean = active
/**
* Control whether a warp gate is usable for transporting faction-affiliated forces between other gates.
* @param state `true`, to activate the gate;
* `false`, otherwise
* @return `true`, if the gate is active;
* `false`, otherwise
*/
def Active_=(state : Boolean) : Boolean = {
active = state
Active
}
def Broadcast : Boolean = Active && broadcast
/**
* Determine whether any faction interacts with this warp gate as "broadcast."
* The gate must be active first.
* @return `true`, if some faction sees this warp gate as a "broadcast gate";
* `false`, otherwise
*/
def Broadcast : Boolean = Active && broadcast.nonEmpty
def Broadcast_=(cast : Boolean) : Boolean = {
broadcast = cast
Broadcast
/**
* Determine whether a specific faction interacts with this warp gate as "broadcast."
* The warp gate being `NEUTRAL` should allow for any polled faction to interact.
* The gate must be active first.
* @return `true`, if the given faction interacts with this warp gate as a "broadcast gate";
* `false`, otherwise
*/
def Broadcast(faction : PlanetSideEmpire.Value) : Boolean = {
Active && (broadcast.contains(faction) || broadcast.contains(PlanetSideEmpire.NEUTRAL))
}
/**
* Toggle whether the warp gate's faction-affiliated force interacts with this warp gate as "broadcast."
* Other "broadcast" associations are not affected.
* The gate must be active first.
* @param bcast `true`, if the faction-affiliated force interacts with this gate as broadcast;
* `false`, if not
* @return the set of all factions who interact with this warp gate as "broadcast"
*/
def Broadcast_=(bcast : Boolean) : Set[PlanetSideEmpire.Value] = {
if(Active) {
if(bcast) {
broadcast += Faction
}
else {
broadcast -= Faction
}
}
broadcast.toSet
}
/**
* Which factions interact with this warp gate as "broadcast?"
* @return the set of all factions who interact with this warp gate as "broadcast"
*/
def BroadcastFor : Set[PlanetSideEmpire.Value] = broadcast.toSet
/**
* Allow a faction to interact with a given warp gate as "broadcast" if it is active.
* @param bcast the faction
* @return the set of all factions who interact with this warp gate as "broadcast"
*/
def BroadcastFor_=(bcast : PlanetSideEmpire.Value) : Set[PlanetSideEmpire.Value] = {
(broadcast += bcast).toSet
}
/**
* Allow some factions to interact with a given warp gate as "broadcast" if it is active.
* @param bcast the factions
* @return the set of all factions who interact with this warp gate as "broadcast"
*/
def BroadcastFor_=(bcast : Set[PlanetSideEmpire.Value]) : Set[PlanetSideEmpire.Value] = {
(broadcast ++= bcast).toSet
}
/**
* Disallow a faction to interact with a given warp gate as "broadcast."
* @param bcast the faction
* @return the set of all factions who interact with this warp gate as "broadcast"
*/
def StopBroadcastFor_=(bcast : PlanetSideEmpire.Value) : Set[PlanetSideEmpire.Value] = {
(broadcast -= bcast).toSet
}
/**
* Disallow some factions to interact with a given warp gate as "broadcast."
* @param bcast the factions
* @return the set of all factions who interact with this warp gate as "broadcast"
*/
def StopBroadcastFor_=(bcast : Set[PlanetSideEmpire.Value]) : Set[PlanetSideEmpire.Value] = {
(broadcast --= bcast).toSet
}
def Owner : PlanetSideServerObject = this

View file

@ -6,28 +6,26 @@ import scodec.Codec
import scodec.codecs._
/**
* Promotes a warpgate's "broadcast" functionality.<br>
* Dispatched by the server to promote a warp gate's broadcast functionality.<br>
* <br>
* Change the map name of a warpgate into "Broadcast" when the proper state is set.
* If a proper warpgate is not designated, nothing happens.
* If not set, the map name of the warpgate will default to whatever is normally written on the map.
* The map designation of geowarps is not affected by this packet.<br>
* <br>
* Exploration:<br>
* I believe these `Boolean` values actually indicate some measure of warpgate operation.
* Geowarps, for example, though their appearance does not change, recieve this packet.
* Moreover, they can operate as a receiving-end broadcast gate.
* @param continent_id the zone
* @param building_id the warp gate (see `BuildingInfoUpdateMessage`)
* @param unk1 na
* @param unk2 na
* @param broadcast if true, the gate replaces its destination text with "Broadcast"
* Changes the map name of a warp gate into "Broadcast"
* and allow a given faction to access the gate's intercontinental transport functionality to/from that gate,
* even if the gate is not properly owned.
* If an actual warp gate is not designated, nothing happens.
* If not set, the map name of the warp gate will default to whatever is normally written on the map.
* The map designation of geowarps is not affected by this packet.
* @see `BuildingInfoUpdateMessage`
* @param zone_id the zone ordinal number
* @param building_id the warp gate map id
* @param tr players belonging to the Terran Republic interact with this warp gate as a "broadcast gate"
* @param nc players belonging to the New Conglomerate interact with this warp gate as a "broadcast gate"
* @param vs players belonging to the Vanu Sovereignty interact with this warp gate as a "broadcast gate"
*/
final case class BroadcastWarpgateUpdateMessage(continent_id : Int,
final case class BroadcastWarpgateUpdateMessage(zone_id : Int,
building_id : Int,
unk1 : Boolean,
unk2 : Boolean,
broadcast : Boolean)
tr : Boolean,
nc : Boolean,
vs : Boolean)
extends PlanetSideGamePacket {
type Packet = BroadcastWarpgateUpdateMessage
def opcode = GamePacketOpcode.BroadcastWarpgateUpdateMessage
@ -36,10 +34,10 @@ final case class BroadcastWarpgateUpdateMessage(continent_id : Int,
object BroadcastWarpgateUpdateMessage extends Marshallable[BroadcastWarpgateUpdateMessage] {
implicit val codec : Codec[BroadcastWarpgateUpdateMessage] = (
("continent_id" | uint16L) ::
("zone_id" | uint16L) ::
("building_id" | uint16L) ::
("unk1" | bool) ::
("unk2" | bool) ::
("broadcast" | bool)
("tr" | bool) ::
("nc" | bool) ::
("vs" | bool)
).as[BroadcastWarpgateUpdateMessage]
}

View file

@ -164,6 +164,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
//quickly and briefly kill player to avoid disembark animation
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player_guid, 0, 0))
DismountVehicleOnLogOut()
DisownVehicle()
}
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, player_guid))
taskResolver ! GUIDTask.UnregisterAvatar(player)(continent.GUID)
@ -207,14 +208,14 @@ class WorldSessionActor extends Actor with MDCContextAware {
* Vehicle cleanup that is specific to log out behavior.
*/
def DismountVehicleOnLogOut() : Unit = {
(player.VehicleSeated match {
case Some(vehicle_guid) =>
continent.GUID(vehicle_guid)
case None =>
None
(continent.GUID(player.VehicleSeated) match {
case Some(obj : Mountable) =>
(Some(obj), obj.PassengerInSeat(player))
case _ =>
(None, None)
}) match {
case Some(mobj : Mountable) =>
mobj.Seat(mobj.PassengerInSeat(player).get).get.Occupant = None
case (Some(mountObj), Some(seatIndex)) =>
mountObj.Seats(seatIndex).Occupant = None
case _ => ;
}
@ -2733,6 +2734,19 @@ class WorldSessionActor extends Actor with MDCContextAware {
})
StopBundlingPackets()
drawDeloyableIcon = DontRedrawIcons
//if driver of a vehicle, summon any passengers and cargo vehicles left behind on previous continent
GetVehicleAndSeat() match {
case (Some(vehicle), Some(0)) =>
LoadZoneTransferPassengerMessages(
guid,
continent.Id,
TransportVehicleChannelName(vehicle),
vehicle,
interstellarFerryTopLevelGUID.getOrElse(vehicle.GUID)
)
interstellarFerryTopLevelGUID = None
case _ => ;
}
}
def handleControlPkt(pkt : PlanetSideControlPacket) = {
@ -3028,16 +3042,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
})
//our vehicle would have already been loaded; see NewPlayerLoaded/AvatarCreate
usedVehicle.headOption match {
case Some(vehicle) if vehicle.PassengerInSeat(player).contains(0) =>
//if driver of vehicle, summon any passengers and cargo vehicles left behind on previous continent
LoadZoneTransferPassengerMessages(
guid,
continentId,
TransportVehicleChannelName(vehicle),
vehicle,
interstellarFerryTopLevelGUID.orElse(player.VehicleSeated).getOrElse(PlanetSideGUID(0))
)
case Some(vehicle) =>
case Some(vehicle) if !vehicle.PassengerInSeat(player).contains(0) =>
//if passenger, attempt to depict any other passengers already in this zone
val vguid = vehicle.GUID
vehicle.Seats
@ -3054,7 +3059,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
)
)
})
case _ => ; //no vehicle
case _ => ; //driver, or no vehicle
}
//vehicle wreckages
wreckages.foreach(vehicle => {
@ -3287,7 +3292,13 @@ class WorldSessionActor extends Actor with MDCContextAware {
case msg @ SpawnRequestMessage(u1, spawn_type, u3, u4, zone_number) =>
log.info(s"SpawnRequestMessage: $msg")
cluster ! Zone.Lattice.RequestSpawnPoint(zone_number.toInt, player, spawn_type.id.toInt)
if(deadState != DeadState.RespawnTime) {
deadState = DeadState.RespawnTime
cluster ! Zone.Lattice.RequestSpawnPoint(zone_number.toInt, player, spawn_type.id.toInt)
}
else {
log.warn("SpawnRequestMessage: request consumed; already respawning ...")
}
case msg @ SetChatFilterMessage(send_channel, origin, whitelist) =>
//log.info("SetChatFilters: " + msg)
@ -3332,18 +3343,22 @@ class WorldSessionActor extends Actor with MDCContextAware {
PlayerActionsToCancel()
continent.GUID(player.VehicleSeated) match {
case Some(vehicle : Vehicle) =>
vehicle.Position = pos
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.UnloadVehicle(player.GUID, continent, vehicle, vehicle.GUID))
LoadZonePhysicalSpawnPoint(zone, pos, Vector3.Zero, 0)
vehicle.PassengerInSeat(player) match {
case Some(0) =>
vehicle.Position = pos
LoadZonePhysicalSpawnPoint(zone, pos, Vector3.Zero, 0)
case _ => //not seated as the driver, in which case we can't move
deadState = DeadState.Alive
}
case None =>
player.Position = pos
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player.GUID, player.GUID))
//avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player.GUID, player.GUID))
LoadZonePhysicalSpawnPoint(zone, pos, Vector3.Zero, 0)
case _ => //seated in something that is not a vehicle, in which case we can't move
case _ => //seated in something that is not a vehicle, or we're dead, in which case we can't move
deadState = DeadState.Alive
}
case (false, _, _) => ;
case (_, _, _) => ;
}
CSRWarp.read(traveler, msg) match {
@ -3351,17 +3366,23 @@ class WorldSessionActor extends Actor with MDCContextAware {
deadState = DeadState.Release //cancel movement updates
PlayerActionsToCancel()
continent.GUID(player.VehicleSeated) match {
case Some(vehicle : Vehicle) =>
LoadZonePhysicalSpawnPoint(continent.Id, pos, Vector3.z(vehicle.Orientation.z), 0)
case Some(vehicle : Vehicle) if player.isAlive =>
vehicle.PassengerInSeat(player) match {
case Some(0) =>
vehicle.Position = pos
LoadZonePhysicalSpawnPoint(continent.Id, pos, Vector3.z(vehicle.Orientation.z), 0)
case _ => //not seated as the driver, in which case we can't move
deadState = DeadState.Alive
}
case None =>
player.Position = pos
sendResponse(PlayerStateShiftMessage(ShiftState(0, pos, player.Orientation.z, None)))
deadState = DeadState.Alive //must be set here
case _ => //seated in something that is not a vehicle, in which case we can't move
case _ => //seated in something that is not a vehicle, or we're dead, in which case we can't move
deadState = DeadState.Alive
}
case (false, _) => ;
case (_, _) => ;
}
// TODO: Prevents log spam, but should be handled correctly
@ -4485,17 +4506,23 @@ class WorldSessionActor extends Actor with MDCContextAware {
case msg @ WarpgateRequest(continent_guid, building_guid, dest_building_guid, dest_continent_guid, unk1, unk2) =>
log.info(s"WarpgateRequest: $msg")
continent.Buildings.values.find(building => building.GUID == building_guid) match {
case Some(wg : WarpGate) if(wg.Active && (GetKnownVehicleAndSeat() match {
case (Some(vehicle), _) =>
wg.Definition.VehicleAllowance && !wg.Definition.NoWarp.contains(vehicle.Definition)
case _ =>
true
})) =>
cluster ! Zone.Lattice.RequestSpecificSpawnPoint(dest_continent_guid.guid, player, dest_building_guid)
if(deadState != DeadState.RespawnTime) {
deadState = DeadState.RespawnTime
continent.Buildings.values.find(building => building.GUID == building_guid) match {
case Some(wg : WarpGate) if (wg.Active && (GetKnownVehicleAndSeat() match {
case (Some(vehicle), _) =>
wg.Definition.VehicleAllowance && !wg.Definition.NoWarp.contains(vehicle.Definition)
case _ =>
true
})) =>
cluster ! Zone.Lattice.RequestSpecificSpawnPoint(dest_continent_guid.guid, player, dest_building_guid)
case _ =>
RequestSanctuaryZoneSpawn(player, continent.Number)
case _ =>
RequestSanctuaryZoneSpawn(player, continent.Number)
}
}
else {
log.warn("WarpgateRequest: request consumed; already respawning ...")
}
case msg @ MountVehicleMsg(player_guid, mountable_guid, entry_point) =>
@ -5332,7 +5359,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
* @param vehicle the discovered vehicle
*/
private def SpecialCaseVehicleDespawn(tplayer : Player, vehicle : Vehicle) : Option[Vehicle] = {
if(vehicle.Owner.contains(tplayer.GUID) || !vehicle.Seats(0).isOccupied) {
if(vehicle.Owner.contains(tplayer.GUID)) {
vehicle.Owner = None
vehicleService ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(vehicle), continent))
vehicle.CargoHolds.values
@ -5345,7 +5372,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
vehicle,
ferry.GUID,
ferry,
true,
false,
false,
false
)
@ -6357,7 +6384,16 @@ class WorldSessionActor extends Actor with MDCContextAware {
)
)
sendResponse(DensityLevelUpdateMessage(continentNumber, buildingNumber, List(0,0, 0,0, 0,0, 0,0)))
sendResponse(BroadcastWarpgateUpdateMessage(continentNumber, buildingNumber, false, false, wg.Broadcast))
//TODO one faction knows which gates are broadcast for another faction?
sendResponse(
BroadcastWarpgateUpdateMessage(
continentNumber,
buildingNumber,
wg.Broadcast(PlanetSideEmpire.TR),
wg.Broadcast(PlanetSideEmpire.NC),
wg.Broadcast(PlanetSideEmpire.VS)
)
)
case _ => ;
}
}
@ -6598,15 +6634,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
case _ =>
vehicle.MountedIn = None
}
//call for passengers across the expanse
LoadZoneTransferPassengerMessages(
player.GUID,
continent.Id,
TransportVehicleChannelName(vehicle),
vehicle,
interstellarFerryTopLevelGUID.orElse(player.VehicleSeated).getOrElse(PlanetSideGUID(0))
)
interstellarFerryTopLevelGUID = None
}
else {
//if passenger;
@ -7875,7 +7902,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
* does not factor in any time required for loading zone or game objects
*/
def LoadZonePhysicalSpawnPoint(zone_id : String, pos : Vector3, ori : Vector3, respawnTime : Long) : Unit = {
log.info(s"Load in zone $zone_id at position $pos")
log.info(s"Load in zone $zone_id at position $pos in $respawnTime seconds")
respawnTimer.cancel
reviveTimer.cancel
val backpack = player.isBackpack
@ -7940,7 +7967,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
else {
LoadZoneCommonTransferActivity()
val original = player
if(tplayer.isBackpack) {
if(player.isBackpack) {
//unregister avatar locker + GiveWorld
player = tplayer
(taskResolver, TaskBeforeZoneChange(GUIDTask.UnregisterLocker(original.Locker)(continent.GUID), zone_id))
@ -8381,7 +8408,12 @@ class WorldSessionActor extends Actor with MDCContextAware {
*/
def BeforeUnloadVehicle(vehicle : Vehicle) : Unit = {
vehicle.Definition match {
case GlobalDefinitions.ams if vehicle.Faction == player.Faction =>
log.info("BeforeUnload: cleaning up after a mobile spawn vehicle ...")
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.UpdateAmsSpawnPoint(continent))
None
case GlobalDefinitions.router =>
//this may repeat for multiple players on the same continent but that's okay(?)
log.info("BeforeUnload: cleaning up after a router ...")
(vehicle.Utility(UtilityType.internal_router_telepad_deployable) match {
case Some(util : Utility.InternalTelepad) =>
@ -8566,7 +8598,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
/**
* Given an origin and a destination, determine how long the process of traveling should take in reconstruction time.
* For most destinations, the unit of receiving ("spawn point") determines the reconstruction time.
* In a special consideration, travel from any sanctuary or sanctuary-special zone should be as immediate as zone loading.
* In a special consideration, travel to any sanctuary or sanctuary-special zone should be as immediate as zone loading.
* @param toZoneId the zone where the target is headed
* @param toSpawnPoint the unit the target is using as a destination
* @param fromZoneId the zone where the target current is located
@ -8574,12 +8606,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
*/
def CountSpawnDelay(toZoneId : String, toSpawnPoint : SpawnPoint, fromZoneId : String) : Long = {
val sanctuaryZoneId = Zones.SanctuaryZoneId(player.Faction)
if(sanctuaryZoneId.equals(fromZoneId)) { //TODO includes traveing zones
if(sanctuaryZoneId.equals(toZoneId)) { //to sanctuary
0L
}
else if(sanctuaryZoneId.equals(toZoneId)) {
10L
}
else if(!player.isAlive) {
toSpawnPoint.Definition.Delay //TODO +cumulative death penalty
}
@ -8601,8 +8630,10 @@ class WorldSessionActor extends Actor with MDCContextAware {
.sortBy(tube => Vector3.DistanceSquared(tube.Position, player.Position))
.headOption match {
case Some(tube) =>
log.info("DrawCurrentAmsSpawnPoint - new @ams spawn point drawn")
sendResponse(BindPlayerMessage(BindStatus.Available, "@ams", true, false, SpawnGroup.AMS, continent.Number, 5, tube.Position))
case None =>
log.info("DrawCurrentAmsSpawnPoint - no @ams spawn point drawn")
sendResponse(BindPlayerMessage(BindStatus.Unavailable, "@ams", false, false, SpawnGroup.AMS, continent.Number, 0, Vector3.Zero))
}
}

View file

@ -7,7 +7,16 @@ import net.psforever.objects.zones.Zone
import net.psforever.types.PlanetSideEmpire
object Zones {
val z1 = new Zone("z1", Maps.map1, 1)
val z1 = new Zone("z1", Maps.map1, 1) {
override def Init(implicit context : ActorContext) : Unit = {
super.Init(context)
BuildingByMapId(1).get.asInstanceOf[WarpGate].BroadcastFor = PlanetSideEmpire.TR
BuildingByMapId(2).get.asInstanceOf[WarpGate].BroadcastFor = PlanetSideEmpire.TR
BuildingByMapId(3).get.asInstanceOf[WarpGate].BroadcastFor = PlanetSideEmpire.TR
BuildingByMapId(4).get.asInstanceOf[WarpGate].BroadcastFor = PlanetSideEmpire.TR
}
}
val z2 = new Zone("z2", Maps.map2, 2)
@ -101,10 +110,10 @@ object Zones {
}
import net.psforever.types.PlanetSideEmpire
BuildingByMapId(2).get.Faction = PlanetSideEmpire.VS
BuildingByMapId(10).get.asInstanceOf[WarpGate].Broadcast = true
BuildingByMapId(11).get.asInstanceOf[WarpGate].Broadcast = true
BuildingByMapId(12).get.asInstanceOf[WarpGate].Broadcast = true
BuildingByMapId(13).get.asInstanceOf[WarpGate].Broadcast = true
BuildingByMapId(10).get.asInstanceOf[WarpGate].BroadcastFor = PlanetSideEmpire.VS
BuildingByMapId(11).get.asInstanceOf[WarpGate].BroadcastFor = PlanetSideEmpire.VS
BuildingByMapId(12).get.asInstanceOf[WarpGate].BroadcastFor = PlanetSideEmpire.VS
BuildingByMapId(13).get.asInstanceOf[WarpGate].BroadcastFor = PlanetSideEmpire.VS
BuildingByMapId(48).get.Faction = PlanetSideEmpire.VS
BuildingByMapId(49).get.Faction = PlanetSideEmpire.VS
BuildingByMapId(18657).get.asInstanceOf[WarpGate].Active = false
@ -135,6 +144,9 @@ object Zones {
import net.psforever.types.PlanetSideEmpire
Buildings.values.foreach { _.Faction = PlanetSideEmpire.TR }
BuildingByMapId(1).get.asInstanceOf[WarpGate].Broadcast = true
BuildingByMapId(2).get.asInstanceOf[WarpGate].Broadcast = true
BuildingByMapId(3).get.asInstanceOf[WarpGate].Broadcast = true
}
}