diff --git a/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala b/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala
index fc511e8d..d39790ef 100644
--- a/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala
+++ b/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala
@@ -524,6 +524,8 @@ object GlobalDefinitions {
val medical_terminal = new MedicalTerminalDefinition(529)
+ val repair_silo = new RepairRearmSiloDefinition(729)
+
val spawn_pad = new VehicleSpawnPadDefinition
val mb_locker = new LockerDefinition
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminal.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminal.scala
index c98e7da5..4eafb142 100644
--- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminal.scala
+++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminal.scala
@@ -1,8 +1,6 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.terminals
-import net.psforever.packet.game.PlanetSideGUID
-
/**
* A server object that is a "terminal" that can be accessed for amenities and services,
* triggered when a certain distance from the unit itself (proximity-based).
@@ -11,21 +9,7 @@ import net.psforever.packet.game.PlanetSideGUID
* For example, the cavern crystals are considered owner-neutral elements that are not attached to a `Building` object.
* @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
*/
-class ProximityTerminal(tdef : MedicalTerminalDefinition) extends Terminal(tdef) {
- private var users : Set[PlanetSideGUID] = Set.empty
-
- def NumberUsers : Int = users.size
-
- def AddUser(player_guid : PlanetSideGUID) : Int = {
- users += player_guid
- NumberUsers
- }
-
- def RemoveUser(player_guid : PlanetSideGUID) : Int = {
- users -= player_guid
- NumberUsers
- }
-}
+class ProximityTerminal(tdef : MedicalTerminalDefinition) extends Terminal(tdef) with ProximityUnit
object ProximityTerminal {
/**
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala
index 407fd0cb..753cdb65 100644
--- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala
+++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala
@@ -2,36 +2,24 @@
package net.psforever.objects.serverobject.terminals
import akka.actor.Actor
-import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
-import net.psforever.objects.serverobject.terminals.Terminal.TerminalMessage
/**
- *
* An `Actor` that handles messages being dispatched to a specific `ProximityTerminal`.
* Although this "terminal" itself does not accept the same messages as a normal `Terminal` object,
* it returns the same type of messages - wrapped in a `TerminalMessage` - to the `sender`.
* @param term the proximity unit (terminal)
*/
-class ProximityTerminalControl(term : ProximityTerminal) extends Actor with FactionAffinityBehavior.Check {
+class ProximityTerminalControl(term : Terminal with ProximityUnit) extends Actor with FactionAffinityBehavior.Check with ProximityUnit.Use {
def FactionObject : FactionAffinity = term
- def receive : Receive = checkBehavior.orElse {
- case CommonMessages.Use(player) =>
- val hadNoUsers = term.NumberUsers == 0
- if(term.AddUser(player.GUID) == 1 && hadNoUsers) {
- sender ! TerminalMessage(player, null, Terminal.StartProximityEffect(term))
- }
+ def TerminalObject : Terminal with ProximityUnit = term
- case CommonMessages.Unuse(player) =>
- val hadUsers = term.NumberUsers > 0
- if(term.RemoveUser(player.GUID) == 0 && hadUsers) {
- sender ! TerminalMessage(player, null, Terminal.StopProximityEffect(term))
- }
-
- case _ =>
- sender ! Terminal.NoDeal()
- }
+ def receive : Receive = checkBehavior
+ .orElse(proximityBehavior)
+ .orElse {
+ case _ => ;
+ }
override def toString : String = term.Definition.Name
}
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityUnit.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityUnit.scala
new file mode 100644
index 00000000..8339e51e
--- /dev/null
+++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityUnit.scala
@@ -0,0 +1,55 @@
+// Copyright (c) 2017 PSForever
+package net.psforever.objects.serverobject.terminals
+
+import net.psforever.objects.serverobject.CommonMessages
+import net.psforever.objects.serverobject.terminals.Terminal.TerminalMessage
+import net.psforever.packet.game.PlanetSideGUID
+
+/**
+ * A server object that is a "terminal" that can be accessed for amenities and services,
+ * triggered when a certain distance from the unit itself (proximity-based).
+ *
+ * Unlike conventional terminals, this structure is not necessarily structure-owned.
+ * For example, the cavern crystals are considered owner-neutral elements that are not attached to a `Building` object.
+ */
+trait ProximityUnit {
+ this : Terminal =>
+
+ private var users : Set[PlanetSideGUID] = Set.empty
+
+ def NumberUsers : Int = users.size
+
+ def AddUser(player_guid : PlanetSideGUID) : Int = {
+ users += player_guid
+ NumberUsers
+ }
+
+ def RemoveUser(player_guid : PlanetSideGUID) : Int = {
+ users -= player_guid
+ NumberUsers
+ }
+}
+
+object ProximityUnit {
+ import akka.actor.Actor
+
+ trait Use {
+ this : Actor =>
+
+ def TerminalObject : Terminal with ProximityUnit
+
+ val proximityBehavior : Receive = {
+ case CommonMessages.Use(player) =>
+ val hadNoUsers = TerminalObject.NumberUsers == 0
+ if(TerminalObject.AddUser(player.GUID) == 1 && hadNoUsers) {
+ sender ! TerminalMessage(player, null, Terminal.StartProximityEffect(TerminalObject))
+ }
+
+ case CommonMessages.Unuse(player) =>
+ val hadUsers = TerminalObject.NumberUsers > 0
+ if(TerminalObject.RemoveUser(player.GUID) == 0 && hadUsers) {
+ sender ! TerminalMessage(player, null, Terminal.StopProximityEffect(TerminalObject))
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/RepairRearmControl.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/RepairRearmControl.scala
new file mode 100644
index 00000000..b5514305
--- /dev/null
+++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/RepairRearmControl.scala
@@ -0,0 +1,22 @@
+// Copyright (c) 2017 PSForever
+package net.psforever.objects.serverobject.terminals
+
+import akka.actor.Actor
+import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
+
+class RepairRearmControl(term : RepairRearmSilo) extends Actor with FactionAffinityBehavior.Check with ProximityUnit.Use {
+ def FactionObject : FactionAffinity = term
+
+ def TerminalObject : Terminal with ProximityUnit = term
+
+ def receive : Receive = checkBehavior
+ .orElse(proximityBehavior)
+ .orElse {
+ case Terminal.Request(player, msg) =>
+ sender ! Terminal.TerminalMessage(player, msg, term.Request(player, msg))
+
+ case _ => ;
+ }
+
+ override def toString : String = term.Definition.Name
+}
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/RepairRearmSilo.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/RepairRearmSilo.scala
new file mode 100644
index 00000000..45a01302
--- /dev/null
+++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/RepairRearmSilo.scala
@@ -0,0 +1,38 @@
+// Copyright (c) 2017 PSForever
+package net.psforever.objects.serverobject.terminals
+
+/**
+ * A server object that is a "terminal" that can be accessed for amenities and services,
+ * triggered when a certain distance from the unit itself (proximity-based).
+ *
+ * Unlike conventional terminals, this structure is not necessarily structure-owned.
+ * For example, the cavern crystals are considered owner-neutral elements that are not attached to a `Building` object.
+ * @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
+ */
+class RepairRearmSilo(tdef : RepairRearmSiloDefinition) extends Terminal(tdef) with ProximityUnit
+
+object RepairRearmSilo {
+ /**
+ * Overloaded constructor.
+ * @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
+ */
+ def apply(tdef : RepairRearmSiloDefinition) : RepairRearmSilo = {
+ new RepairRearmSilo(tdef)
+ }
+
+ import akka.actor.ActorContext
+
+ /**
+ * Instantiate an configure a `Terminal` object
+ * @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
+ * @param id the unique id that will be assigned to this entity
+ * @param context a context to allow the object to properly set up `ActorSystem` functionality
+ * @return the `Terminal` object
+ */
+ def Constructor(tdef : RepairRearmSiloDefinition)(id : Int, context : ActorContext) : RepairRearmSilo = {
+ import akka.actor.Props
+ val obj = RepairRearmSilo(tdef)
+ obj.Actor = context.actorOf(Props(classOf[RepairRearmControl], obj), s"${tdef.Name}_$id")
+ obj
+ }
+}
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/RepairRearmSiloDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/RepairRearmSiloDefinition.scala
new file mode 100644
index 00000000..b0daa854
--- /dev/null
+++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/RepairRearmSiloDefinition.scala
@@ -0,0 +1,27 @@
+// Copyright (c) 2017 PSForever
+package net.psforever.objects.serverobject.terminals
+
+import net.psforever.objects.Player
+import net.psforever.packet.game.ItemTransactionMessage
+
+class RepairRearmSiloDefinition(objectId : Int) extends EquipmentTerminalDefinition(objectId) {
+ Name = "repair_silo"
+
+ private val buyFunc : (Player, ItemTransactionMessage)=>Terminal.Exchange = EquipmentTerminalDefinition.Buy(Map.empty, Map.empty, Map.empty)
+
+ override def Buy(player: Player, msg : ItemTransactionMessage) : Terminal.Exchange = buyFunc(player, msg)
+
+ override def Loadout(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = {
+ if(msg.item_page == 4) { //Favorites tab
+ player.LoadLoadout(msg.unk1) match {
+ case Some(loadout) =>
+ Terminal.VehicleLoadout(Nil, Nil)
+ case None =>
+ Terminal.NoDeal()
+ }
+ }
+ else {
+ Terminal.NoDeal()
+ }
+ }
+}
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/Terminal.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/Terminal.scala
index b031a990..8ee17814 100644
--- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/Terminal.scala
+++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/Terminal.scala
@@ -190,17 +190,19 @@ object Terminal {
*/
final case class InfantryLoadout(exosuit : ExoSuitType.Value, subtype : Int = 0, holsters : List[InventoryItem], inventory : List[InventoryItem]) extends Exchange
+ final case class VehicleLoadout(weapons : List[InventoryItem], inventory : List[InventoryItem]) extends Exchange
+
/**
* Start the special effects caused by a proximity-base service.
* @param terminal the proximity-based unit
*/
- final case class StartProximityEffect(terminal : ProximityTerminal) extends Exchange
+ final case class StartProximityEffect(terminal : Terminal with ProximityUnit) extends Exchange
/**
* Stop the special effects caused by a proximity-base service.
* @param terminal the proximity-based unit
*/
- final case class StopProximityEffect(terminal : ProximityTerminal) extends Exchange
+ final case class StopProximityEffect(terminal : Terminal with ProximityUnit) extends Exchange
/**
* Overloaded constructor.
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/TerminalControl.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/TerminalControl.scala
index ad63babf..4efa324e 100644
--- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/TerminalControl.scala
+++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/TerminalControl.scala
@@ -15,8 +15,7 @@ class TerminalControl(term : Terminal) extends Actor with FactionAffinityBehavio
case Terminal.Request(player, msg) =>
sender ! Terminal.TerminalMessage(player, msg, term.Request(player, msg))
- case _ =>
- sender ! Terminal.NoDeal()
+ case _ => ;
}
override def toString : String = term.Definition.Name
diff --git a/pslogin/src/main/scala/Maps.scala b/pslogin/src/main/scala/Maps.scala
index 4051208c..7d0494dd 100644
--- a/pslogin/src/main/scala/Maps.scala
+++ b/pslogin/src/main/scala/Maps.scala
@@ -7,7 +7,7 @@ import net.psforever.objects.serverobject.locks.IFFLock
import net.psforever.objects.serverobject.mblocker.Locker
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
import net.psforever.objects.serverobject.structures.{Building, FoundationBuilder, StructureType, WarpGate}
-import net.psforever.objects.serverobject.terminals.{ProximityTerminal, Terminal}
+import net.psforever.objects.serverobject.terminals.{ProximityTerminal, RepairRearmSilo, Terminal}
import net.psforever.objects.serverobject.tube.SpawnTube
import net.psforever.types.Vector3
@@ -113,6 +113,8 @@ object Maps {
LocalObject(2145, SpawnTube.Constructor(Vector3(3980.4062f, 4252.7656f, 257.5625f), Vector3(0, 0, 90)))
LocalObject(2146, SpawnTube.Constructor(Vector3(3980.4062f, 4259.992f, 257.5625f), Vector3(0, 0, 90)))
LocalObject(2147, SpawnTube.Constructor(Vector3(3980.4062f, 4267.3047f, 257.5625f), Vector3(0, 0, 90)))
+ LocalObject(2050, RepairRearmSilo.Constructor(repair_silo))
+ LocalObject(2062, RepairRearmSilo.Constructor(repair_silo))
LocalObject(2239, Terminal.Constructor(spawn_terminal))
LocalObject(2244, Terminal.Constructor(spawn_terminal))
LocalObject(2245, Terminal.Constructor(spawn_terminal))
@@ -214,6 +216,8 @@ object Maps {
ObjectToBuilding(1576, 2)
ObjectToBuilding(1577, 2)
ObjectToBuilding(1578, 2)
+ ObjectToBuilding(2050, 2)
+ ObjectToBuilding(2062, 2)
ObjectToBuilding(2145, 2)
ObjectToBuilding(2146, 2)
ObjectToBuilding(2147, 2)
diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala
index bfbfe5cf..33514522 100644
--- a/pslogin/src/main/scala/WorldSessionActor.scala
+++ b/pslogin/src/main/scala/WorldSessionActor.scala
@@ -28,8 +28,7 @@ import net.psforever.objects.serverobject.mblocker.Locker
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
import net.psforever.objects.serverobject.pad.process.{AutoDriveControls, VehicleSpawnControlGuided}
import net.psforever.objects.serverobject.structures.{Building, StructureType, WarpGate}
-import net.psforever.objects.serverobject.terminals.{MatrixTerminalDefinition, ProximityTerminal, Terminal}
-import net.psforever.objects.serverobject.terminals.Terminal
+import net.psforever.objects.serverobject.terminals._
import net.psforever.objects.serverobject.terminals.Terminal.TerminalMessage
import net.psforever.objects.serverobject.tube.SpawnTube
import net.psforever.objects.vehicles.{AccessPermissionGroup, Utility, VehicleLockState}
@@ -895,6 +894,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
sendResponse(ItemTransactionResultMessage(msg.terminal_guid, TransactionType.Learn, false))
}
+ case Terminal.VehicleLoadout(weapons, inventory) =>
+ log.info(s"$tplayer wants to change their vehicle equipment loadout to their option #${msg.unk1 + 1}")
+
case Terminal.SellCertification(cert, cost) =>
if(tplayer.Certifications.contains(cert)) {
log.info(s"$tplayer is forgetting the $cert certification for $cost points")
@@ -2267,6 +2269,16 @@ class WorldSessionActor extends Actor with MDCContextAware {
}
}
+ case Some(obj : RepairRearmSilo) =>
+ player.VehicleSeated match {
+ case Some(vehicle_guid) =>
+ val vehicle = continent.GUID(vehicle_guid).get.asInstanceOf[Vehicle]
+ sendResponse(UseItemMessage(avatar_guid, unk1, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
+ sendResponse(UseItemMessage(avatar_guid, unk1, vehicle_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, vehicle.Definition.ObjectId))
+ case None =>
+ log.error("UseItem: expected seated vehicle, but found none")
+ }
+
case Some(obj : Terminal) =>
if(obj.Definition.isInstanceOf[MatrixTerminalDefinition]) {
//TODO matrix spawn point; for now, just blindly bind to show work (and hope nothing breaks)
@@ -2300,7 +2312,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
case msg @ ProximityTerminalUseMessage(player_guid, object_guid, _) =>
log.info(s"ProximityTerminal: $msg")
continent.GUID(object_guid) match {
- case Some(obj : ProximityTerminal) =>
+ case Some(obj : Terminal with ProximityUnit) =>
if(usingProximityTerminal.contains(object_guid)) {
SelectProximityUnit(obj)
}
@@ -2308,9 +2320,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
StartUsingProximityUnit(obj)
}
case Some(obj) => ;
- log.warn(s"ProximityTerminal: object is not a terminal - $obj")
+ log.warn(s"ProximityTerminalUse: object is not a proximity terminal - $obj")
case None =>
- log.warn(s"ProximityTerminal: no object with guid $object_guid found")
+ log.warn(s"ProximityTerminalUse: no object with guid $object_guid found")
}
case msg @ UnuseItemMessage(player_guid, object_guid) =>
@@ -3985,7 +3997,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
* Special note is warranted in the case of a medical terminal or an advanced medical terminal.
* @param terminal the proximity-based unit
*/
- def StartUsingProximityUnit(terminal : ProximityTerminal) : Unit = {
+ def StartUsingProximityUnit(terminal : Terminal with ProximityUnit) : Unit = {
val term_guid = terminal.GUID
if(!usingProximityTerminal.contains(term_guid)) {
usingProximityTerminal += term_guid
@@ -4006,7 +4018,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
* Other sorts of proximity-based units are put on a timer.
* @param terminal the proximity-based unit
*/
- def StopUsingProximityUnit(terminal : ProximityTerminal) : Unit = {
+ def StopUsingProximityUnit(terminal : Terminal with ProximityUnit) : Unit = {
val term_guid = terminal.GUID
if(usingProximityTerminal.contains(term_guid)) {
usingProximityTerminal -= term_guid
@@ -4025,7 +4037,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
* If this timer completes, a message will be sent that will attempt to disassociate from the target proximity unit.
* @param terminal the proximity-based unit
*/
- def SetDelayedProximityUnitReset(terminal : ProximityTerminal) : Unit = {
+ def SetDelayedProximityUnitReset(terminal : Terminal with ProximityUnit) : Unit = {
val terminal_guid = terminal.GUID
ClearDelayedProximityUnitReset(terminal_guid)
import scala.concurrent.duration._
@@ -4070,7 +4082,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
* and determinig which kind of unit is being utilized.
* @param terminal the proximity-based unit
*/
- def SelectProximityUnit(terminal : ProximityTerminal) : Unit = {
+ def SelectProximityUnit(terminal : Terminal with ProximityUnit) : Unit = {
terminal.Definition match {
case GlobalDefinitions.adv_med_terminal | GlobalDefinitions.medical_terminal =>
ProximityMedicalTerminal(terminal)
@@ -4089,7 +4101,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
* If the player is both fully healed and fully repaired, stop using the terminal.
* @param unit the medical terminal
*/
- def ProximityMedicalTerminal(unit : ProximityTerminal) : Unit = {
+ def ProximityMedicalTerminal(unit : Terminal with ProximityUnit) : Unit = {
val healthFull : Boolean = if(player.Health < player.MaxHealth) {
HealAction(player)
}
@@ -4113,7 +4125,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
* If the player is fully healed, stop using the crystal.
* @param unit the healing crystal
*/
- def ProximityHealCrystal(unit : ProximityTerminal) : Unit = {
+ def ProximityHealCrystal(unit : Terminal with ProximityUnit) : Unit = {
val healthFull : Boolean = if(player.Health < player.MaxHealth) {
HealAction(player)
}
@@ -4253,7 +4265,7 @@ object WorldSessionActor {
private final case class ListAccountCharacters()
private final case class SetCurrentAvatar(tplayer : Player)
private final case class VehicleLoaded(vehicle : Vehicle)
- private final case class DelayedProximityUnitStop(unit : ProximityTerminal)
+ private final case class DelayedProximityUnitStop(unit : Terminal with ProximityUnit)
private final case class UnregisterCorpseOnVehicleDisembark(corpse : Player)
/**