From c4c860923862a713d1d8d181e5336ce5e45245f7 Mon Sep 17 00:00:00 2001 From: Fate-JH Date: Wed, 5 Dec 2018 01:17:02 -0500 Subject: [PATCH] Lodestar Terminals (#240) * added three objects to serve as the terminals for Lodestars; only the multivehicle_rearm_terminal is operational, for now * giving the new terminal type a setup function for being constructed as an amenity --- .../psforever/objects/GlobalDefinitions.scala | 22 ++ .../terminals/OrderTerminalDefinition.scala | 190 +++++++++++++++++- .../psforever/objects/vehicles/Utility.scala | 15 ++ .../src/main/scala/WorldSessionActor.scala | 2 +- 4 files changed, 226 insertions(+), 3 deletions(-) diff --git a/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala b/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala index 48481a71..3f8b1297 100644 --- a/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala +++ b/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala @@ -938,6 +938,22 @@ object GlobalDefinitions { val secondary_capture = new CaptureTerminalDefinition(751) // Tower CC + val lodestar_repair_terminal = new OrderTerminalDefinition { //TODO wrong object class + override def ObjectId : Int = 461 + } + + val multivehicle_rearm_terminal = new _OrderTerminalDefinition(576) { + Name = "multivehicle_rearm_terminal" + Page += 3 -> _OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition) + Page += 4 -> _OrderTerminalDefinition.VehicleLoadoutPage() + } + + val bfr_rearm_terminal = new _OrderTerminalDefinition(142) { + Name = "bfr_rearm_terminal" + Page += 3 -> _OrderTerminalDefinition.EquipmentPage(Map.empty[String, ()=>Equipment]) //TODO add stock to page + Page += 4 -> _OrderTerminalDefinition.VehicleLoadoutPage() + } + val manned_turret = new TurretDefinition(480) { Name = "manned_turret" MaxHealth = 3600 @@ -5394,6 +5410,12 @@ object GlobalDefinitions { lodestar.MountPoints += 1 -> 0 lodestar.MountPoints += 2 -> 1 lodestar.Cargo += 1 -> new CargoDefinition() + lodestar.Utilities += 2 -> UtilityType.lodestar_repair_terminal + lodestar.Utilities += 3 -> UtilityType.lodestar_repair_terminal + lodestar.Utilities += 4 -> UtilityType.multivehicle_rearm_terminal + lodestar.Utilities += 5 -> UtilityType.multivehicle_rearm_terminal + lodestar.Utilities += 6 -> UtilityType.bfr_rearm_terminal + lodestar.Utilities += 7 -> UtilityType.bfr_rearm_terminal lodestar.TrunkSize = InventoryTile.Tile1612 lodestar.TrunkOffset = 30 lodestar.AutoPilotSpeeds = (0, 4) diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/OrderTerminalDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/OrderTerminalDefinition.scala index d9730bd6..9182d3b0 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/OrderTerminalDefinition.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/OrderTerminalDefinition.scala @@ -1,11 +1,18 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.serverobject.terminals -import net.psforever.objects.Player -import net.psforever.objects.loadouts.InfantryLoadout +import akka.actor.ActorContext +import net.psforever.objects.definition.ImplantDefinition +import net.psforever.objects.{Player, Vehicle} +import net.psforever.objects.equipment.Equipment +import net.psforever.objects.loadouts.{InfantryLoadout, VehicleLoadout} import net.psforever.objects.inventory.InventoryItem +import net.psforever.objects.serverobject.structures.Amenity import net.psforever.packet.game.ItemTransactionMessage import net.psforever.objects.serverobject.terminals.EquipmentTerminalDefinition._ +import net.psforever.types.{CertificationType, ExoSuitType} + +import scala.collection.mutable /** * The definition for any `Terminal` that is of a type "order_terminal". @@ -51,3 +58,182 @@ class OrderTerminalDefinition extends EquipmentTerminalDefinition(612) { } } } + +class _OrderTerminalDefinition(objId : Int) extends TerminalDefinition(objId) { + private val pages : mutable.HashMap[Int, _OrderTerminalDefinition.PageDefinition] = + new mutable.HashMap[Int, _OrderTerminalDefinition.PageDefinition]() + private var sellEquipmentDefault : Boolean = true + + def Page : mutable.HashMap[Int, _OrderTerminalDefinition.PageDefinition] = pages + + def SellEquipmentByDefault : Boolean = sellEquipmentDefault + + def SellEquipmentByDefault_=(sell : Boolean) : Boolean = { + sellEquipmentDefault = sell + SellEquipmentByDefault + } + + override def Buy(player: Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + pages.get(msg.item_page) match { + case Some(page) => + page.Buy(player, msg) + case _ => + Terminal.NoDeal() + } + } + + override def Loadout(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Buy(player, msg) + + override def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + if(sellEquipmentDefault) { + Terminal.SellEquipment() + } + else { + pages.get(msg.item_page) match { + case Some(page) => + page.Sell(player, msg) + case _ => + Terminal.NoDeal() + } + } + } +} + +object _OrderTerminalDefinition { + abstract class PageDefinition(stock : Map[String, Any]) { + def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange + def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange + } + + final case class ArmorPage(stock : Map[String, (ExoSuitType.Value, Int)]) extends PageDefinition(stock) { + def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + stock.get(msg.item_name) match { + case Some((suit : ExoSuitType.Value, subtype : Int)) => + Terminal.BuyExosuit(suit, subtype) + case _ => + Terminal.NoDeal() + } + } + + def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal() + } + + final case class CertificationPage(stock : Map[String, CertificationType.Value]) extends PageDefinition(stock) { + def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + stock.get(msg.item_name) match { + case Some(cert : CertificationType.Value) => + Terminal.LearnCertification(cert) + case _ => + Terminal.NoDeal() + } + } + + def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + stock.get(msg.item_name) match { + case Some(cert : CertificationType.Value) => + Terminal.SellCertification(cert) + case None => + Terminal.NoDeal() + } + } + } + + final case class EquipmentPage(stock : Map[String, ()=>Equipment]) extends PageDefinition(stock) { + def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + stock.get(msg.item_name) match { + case Some(item : (()=>Equipment)) => + Terminal.BuyEquipment(item()) + case _ => + Terminal.NoDeal() + } + } + + def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.SellEquipment() + } + + final case class ImplantPage(stock : Map[String, ImplantDefinition]) extends PageDefinition(stock) { + def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + stock.get(msg.item_name) match { + case Some(implant : ImplantDefinition) => + Terminal.LearnImplant(implant) + case None => + Terminal.NoDeal() + } + } + + def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + stock.get(msg.item_name) match { + case Some(implant : ImplantDefinition) => + Terminal.SellImplant(implant) + case None => + Terminal.NoDeal() + } + } + } + + final case class InfantryLoadoutPage() extends PageDefinition(Map.empty) { + def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + player.LoadLoadout(msg.unk1) match { + case Some(loadout : InfantryLoadout) => + val holsters = loadout.visible_slots.map(entry => { InventoryItem(BuildSimplifiedPattern(entry.item), entry.index) }) + val inventory = loadout.inventory.map(entry => { InventoryItem(BuildSimplifiedPattern(entry.item), entry.index) }) + Terminal.InfantryLoadout(loadout.exosuit, loadout.subtype, holsters, inventory) + case _ => + Terminal.NoDeal() + } + } + + def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal() + } + + final case class VehicleLoadoutPage() extends PageDefinition(Map.empty) { + def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + player.LoadLoadout(msg.unk1 + 10) match { + case Some(loadout : VehicleLoadout) => + val weapons = loadout.visible_slots.map(entry => { InventoryItem(BuildSimplifiedPattern(entry.item), entry.index) }) + val inventory = loadout.inventory.map(entry => { InventoryItem(BuildSimplifiedPattern(entry.item), entry.index) }) + Terminal.VehicleLoadout(loadout.vehicle_definition, weapons, inventory) + case _ => + Terminal.NoDeal() + } + } + + def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal() + } + + import net.psforever.objects.loadouts.{Loadout => Contents} //distinguish from Terminal.Loadout message + final case class VehiclePage(stock : Map[String, ()=>Vehicle], trunk : Map[String, Contents]) extends PageDefinition(stock) { + def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = { + stock.get(msg.item_name) match { + case Some(vehicle) => + val (weapons, inventory) = trunk.get(msg.item_name) match { + case Some(loadout : VehicleLoadout) => + ( + loadout.visible_slots.map(entry => { InventoryItem(EquipmentTerminalDefinition.BuildSimplifiedPattern(entry.item), entry.index) }), + loadout.inventory.map(entry => { InventoryItem(EquipmentTerminalDefinition.BuildSimplifiedPattern(entry.item), entry.index) }) + ) + case _ => + (List.empty, List.empty) + } + Terminal.BuyVehicle(vehicle(), weapons, inventory) + case None => + Terminal.NoDeal() + } + } + + def Sell(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal() + } + + /** + * Assemble some logic for a provided object. + * @param obj an `Amenity` object; + * anticipating a `Terminal` object using this same definition + * @param context hook to the local `Actor` system + */ + def Setup(obj : Amenity, context : ActorContext) : Unit = { + import akka.actor.{ActorRef, Props} + if(obj.Actor == ActorRef.noSender) { + obj.Actor = context.actorOf(Props(classOf[TerminalControl], obj), s"${obj.Definition.Name}_${obj.GUID.guid}") + } + } +} diff --git a/common/src/main/scala/net/psforever/objects/vehicles/Utility.scala b/common/src/main/scala/net/psforever/objects/vehicles/Utility.scala index ee984b87..395971d0 100644 --- a/common/src/main/scala/net/psforever/objects/vehicles/Utility.scala +++ b/common/src/main/scala/net/psforever/objects/vehicles/Utility.scala @@ -22,7 +22,10 @@ object UtilityType extends Enumeration { type Type = Value val ams_respawn_tube, + bfr_rearm_terminal, + lodestar_repair_terminal, matrix_terminalc, + multivehicle_rearm_terminal, order_terminala, order_terminalb, teleportpad_terminal, @@ -93,8 +96,14 @@ object Utility { private def BuildUtilityFunc(util : UtilityType.Value) : Amenity = util match { case UtilityType.ams_respawn_tube => new SpawnTubeUtility(GlobalDefinitions.ams_respawn_tube) + case UtilityType.bfr_rearm_terminal => + new TerminalUtility(GlobalDefinitions.bfr_rearm_terminal) + case UtilityType.lodestar_repair_terminal => + new TerminalUtility(GlobalDefinitions.lodestar_repair_terminal) case UtilityType.matrix_terminalc => new TerminalUtility(GlobalDefinitions.matrix_terminalc) + case UtilityType.multivehicle_rearm_terminal => + new TerminalUtility(GlobalDefinitions.multivehicle_rearm_terminal) case UtilityType.order_terminala => new TerminalUtility(GlobalDefinitions.order_terminala) case UtilityType.order_terminalb => @@ -180,8 +189,14 @@ object Utility { private def SelectUtilitySetupFunc(util : UtilityType.Value) : UtilLogic = util match { case UtilityType.ams_respawn_tube => SpawnTubeDefinition.Setup + case UtilityType.bfr_rearm_terminal => + _OrderTerminalDefinition.Setup + case UtilityType.lodestar_repair_terminal => + OrderTerminalABDefinition.Setup //TODO wrong case UtilityType.matrix_terminalc => MatrixTerminalDefinition.Setup + case UtilityType.multivehicle_rearm_terminal => + _OrderTerminalDefinition.Setup case UtilityType.order_terminala => OrderTerminalABDefinition.Setup case UtilityType.order_terminalb => diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala index ecddc547..ab1ebeb8 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -3764,7 +3764,7 @@ class WorldSessionActor extends Actor with MDCContextAware { //TODO matrix spawn point; for now, just blindly bind to show work (and hope nothing breaks) sendResponse(BindPlayerMessage(BindStatus.Bind, "", true, true, SpawnGroup.Sanctuary, 0, 0, terminal.Position)) } - else if(tdef.isInstanceOf[RepairRearmSiloDefinition]) { + else if(tdef.isInstanceOf[RepairRearmSiloDefinition] || tdef == GlobalDefinitions.multivehicle_rearm_terminal) { FindLocalVehicle match { case Some(vehicle) => sendResponse(UseItemMessage(avatar_guid, item_used_guid, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))