diff --git a/common/src/main/scala/net/psforever/objects/loadouts/InfantryLoadout.scala b/common/src/main/scala/net/psforever/objects/loadouts/InfantryLoadout.scala index e7470546..5277f4ba 100644 --- a/common/src/main/scala/net/psforever/objects/loadouts/InfantryLoadout.scala +++ b/common/src/main/scala/net/psforever/objects/loadouts/InfantryLoadout.scala @@ -29,3 +29,74 @@ final case class InfantryLoadout(label : String, inventory : List[Loadout.SimplifiedEntry], exosuit : ExoSuitType.Value, subtype : Int) extends Loadout(label, visible_slots, inventory) + +object InfantryLoadout { + import net.psforever.objects.Player + import net.psforever.objects.GlobalDefinitions + import net.psforever.objects.equipment.Equipment + + /** + * The sub-type of the player's uniform. + * Applicable to mechanized assault units, mainly. + * The subtype is reported as a number but indicates the specialization - anti-infantry, ani-vehicular, anti-air - of the suit + * as indicated by the arm weapon(s). + * @param player the player + * @return the numeric subtype + */ + def DetermineSubtype(player : Player) : Int = { + DetermineSubtypeA(player.ExoSuit, player.Slot(0).Equipment) + } + + /** + * The sub-type of the player's uniform. + * Applicable to mechanized assault units, mainly. + * The subtype is reported as a number but indicates the specialization - anti-infantry, ani-vehicular, anti-air - of the suit + * as indicated by the arm weapon(s). + * @param suit the player's uniform; + * the target is for MAX armors + * @param weapon any weapon the player may have it his "first pistol slot;" + * to a MAX, that is its "primary weapon slot" + * @return the numeric subtype + */ + def DetermineSubtypeA(suit : ExoSuitType.Value, weapon : Option[Equipment]) : Int = { + if(suit == ExoSuitType.MAX) { + weapon match { + case Some(item) => + item.Definition match { + case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.nchev_scattercannon | GlobalDefinitions.vshev_quasar => + 1 + case GlobalDefinitions.trhev_pounder | GlobalDefinitions.nchev_falcon | GlobalDefinitions.vshev_comet => + 2 + case GlobalDefinitions.trhev_burster | GlobalDefinitions.nchev_sparrow | GlobalDefinitions.vshev_starfire => + 3 + case _ => + 0 + } + case None => + 0 + } + } + else { + 0 + } + } + + /** + * The sub-type of the player's uniform, as used in `FavoritesMessage`.
+ *
+ * The values for `Standard`, `Infiltration`, and the generic `MAX` are not perfectly known. + * The latter-most exo-suit option is presumed. + * @param suit the player's uniform + * @param subtype the mechanized assault exo-suit subtype as determined by their arm weapons + * @return the numeric subtype + */ + def DetermineSubtypeB(suit : ExoSuitType.Value, subtype : Int) : Int = { + suit match { + case ExoSuitType.Standard => 0 + case ExoSuitType.Agile => 1 + case ExoSuitType.Reinforced => 2 + case ExoSuitType.MAX => 3 + subtype //4, 5, 6 + case ExoSuitType.Infiltration => 7 + } + } +} diff --git a/common/src/main/scala/net/psforever/objects/loadouts/Loadout.scala b/common/src/main/scala/net/psforever/objects/loadouts/Loadout.scala index 7035c89d..5ff4f92d 100644 --- a/common/src/main/scala/net/psforever/objects/loadouts/Loadout.scala +++ b/common/src/main/scala/net/psforever/objects/loadouts/Loadout.scala @@ -5,7 +5,6 @@ import net.psforever.objects._ import net.psforever.objects.definition._ import net.psforever.objects.equipment.Equipment import net.psforever.objects.inventory.InventoryItem -import net.psforever.types.ExoSuitType import scala.annotation.tailrec @@ -120,42 +119,16 @@ object Loadout { * @return the numeric subtype */ def DetermineSubtype(player : Player) : Int = { - DetermineSubtype(player.ExoSuit, player.Slot(0).Equipment) + InfantryLoadout.DetermineSubtype(player) } /** - * The sub-type of the player's uniform. - * Applicable to mechanized assault units, mainly. - * The subtype is reported as a number but indicates the specialization - anti-infantry, ani-vehicular, anti-air - of the suit - * as indicated by the arm weapon(s). - * @param suit the player's uniform; - * the target is for MAX armors - * @param weapon any weapon the player may have it his "first pistol slot;" - * to a MAX, that is its "primary weapon slot" - * @return the numeric subtype + * The sub-type of the vehicle. + * Vehicle's have no subtype. + * @param vehicle the vehicle + * @return the numeric subtype, always 0 */ - def DetermineSubtype(suit : ExoSuitType.Value, weapon : Option[Equipment]) : Int = { - if(suit == ExoSuitType.MAX) { - weapon match { - case Some(item) => - item.Definition match { - case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.nchev_scattercannon | GlobalDefinitions.vshev_quasar => - 1 - case GlobalDefinitions.trhev_pounder | GlobalDefinitions.nchev_falcon | GlobalDefinitions.vshev_comet => - 2 - case GlobalDefinitions.trhev_burster | GlobalDefinitions.nchev_sparrow | GlobalDefinitions.vshev_starfire => - 3 - case _ => - 0 - } - case None => - 0 - } - } - else { - 0 - } - } + def DetermineSubtype(vehicle : Vehicle) : Int = 0 /** * Overloaded entry point for constructing simplified blueprints from holster slot equipment. diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/MedicalTerminalDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/MedicalTerminalDefinition.scala index fbd7f012..66581aac 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/MedicalTerminalDefinition.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/MedicalTerminalDefinition.scala @@ -1,18 +1,12 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.serverobject.terminals -import net.psforever.objects.Player -import net.psforever.packet.game.ItemTransactionMessage - /** * The definition for any `Terminal` that is of a type "medical_terminal". - * This includes the limited proximity-based functionality of the formal medical terminals - * and the actual proximity-based functionality of the cavern crystals.
- *
- * Do not confuse the "medical_terminal" category and the actual `medical_terminal` object (529). - * Objects created by this definition being linked by their use of `ProximityTerminalUseMessage` is more accurate. + * This includes the functionality of the formal medical terminals and some of the cavern crystals. + * Do not confuse the game's internal "medical_terminal" object category and the actual `medical_terminal` object (529). */ -class MedicalTerminalDefinition(objectId : Int) extends TerminalDefinition(objectId) { +class MedicalTerminalDefinition(objectId : Int) extends TerminalDefinition(objectId) with ProximityDefinition { Name = if(objectId == 38) { "adv_med_terminal" } @@ -31,6 +25,4 @@ class MedicalTerminalDefinition(objectId : Int) extends TerminalDefinition(objec else { throw new IllegalArgumentException("medical terminal must be either object id 38, 225, 226, 529, or 689") } - - def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal() } diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityDefinition.scala new file mode 100644 index 00000000..f1ccfcc4 --- /dev/null +++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityDefinition.scala @@ -0,0 +1,15 @@ +// Copyright (c) 2017 PSForever +package net.psforever.objects.serverobject.terminals + +import net.psforever.objects.Player +import net.psforever.packet.game.ItemTransactionMessage + +/** + * The definition for any `Terminal` that possesses a proximity-based effect. + * This includes the limited proximity-based functionality of the formal medical terminals + * and the actual proximity-based functionality of the cavern crystals. + * Objects created by this definition being linked by their use of `ProximityTerminalUseMessage`. + */ +trait ProximityDefinition { + def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal() +} 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 4eafb142..8b9b7e67 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 @@ -9,14 +9,14 @@ package net.psforever.objects.serverobject.terminals * 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) with ProximityUnit +class ProximityTerminal(tdef : TerminalDefinition with ProximityDefinition) extends Terminal(tdef) with ProximityUnit object ProximityTerminal { /** * Overloaded constructor. * @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields */ - def apply(tdef : MedicalTerminalDefinition) : ProximityTerminal = { + def apply(tdef : TerminalDefinition with ProximityDefinition) : ProximityTerminal = { new ProximityTerminal(tdef) } @@ -29,7 +29,7 @@ object ProximityTerminal { * @param context a context to allow the object to properly set up `ActorSystem` functionality * @return the `Terminal` object */ - def Constructor(tdef : MedicalTerminalDefinition)(id : Int, context : ActorContext) : Terminal = { + def Constructor(tdef : TerminalDefinition with ProximityDefinition)(id : Int, context : ActorContext) : Terminal = { import akka.actor.Props val obj = ProximityTerminal(tdef) obj.Actor = context.actorOf(Props(classOf[ProximityTerminalControl], obj), s"${tdef.Name}_$id") 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 deleted file mode 100644 index 2451fbb3..00000000 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/RepairRearmControl.scala +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.objects.serverobject.terminals - -import akka.actor.Actor -import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior} - -/** - * An `Actor` that handles messages being dispatched to a specific `IFFLock`. - * @param term the `RepairRearmSilo` object being governed - * @see `CommonMessages` - */ -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 deleted file mode 100644 index b01cfbae..00000000 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/RepairRearmSilo.scala +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.objects.serverobject.terminals - -/** - * A structure-owned server object for preserving vehicle loadouts, - * obtaining vehicle weapon ammunition, - * and, with proper perks, automatically repairing damage doen to allied vehicles. - * 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 index 2fd82802..9cfc6fa7 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/RepairRearmSiloDefinition.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/RepairRearmSiloDefinition.scala @@ -11,7 +11,7 @@ import net.psforever.packet.game.ItemTransactionMessage * The `Definition` for any `Terminal` that is of a type "repair_silo." * Has both proximity-based operation and direct access purchasing power. */ -class RepairRearmSiloDefinition(objectId : Int) extends EquipmentTerminalDefinition(objectId) { +class RepairRearmSiloDefinition(objectId : Int) extends EquipmentTerminalDefinition(objectId) with ProximityDefinition { Name = "repair_silo" private val buyFunc : (Player, ItemTransactionMessage)=>Terminal.Exchange = EquipmentTerminalDefinition.Buy(Map.empty, Map.empty, Map.empty) diff --git a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala index e7ebd353..9d586476 100644 --- a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala +++ b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala @@ -312,7 +312,7 @@ object GamePacketOpcode extends Enumeration { = Value private def noDecoder(opcode : GamePacketOpcode.Type) = (a : BitVector) => - Attempt.failure(Err(s"Could not find a marshaller for game packet ${opcode}")) + Attempt.failure(Err(s"Could not find a marshaller for game packet $opcode")) /// Mapping of packet IDs to decoders. Notice that we are using the @switch annotation which ensures that the Scala /// compiler will be able to optimize this as a lookup table (switch statement). Microbenchmarks show a nearly 400x @@ -549,7 +549,7 @@ object GamePacketOpcode extends Enumeration { // OPCODES 0xc0-cf case 0xc0 => noDecoder(CaptureFlagUpdateMessage) case 0xc1 => noDecoder(VanuModuleUpdateMessage) - case 0xc2 => noDecoder(FacilityBenefitShieldChargeRequestMessage) + case 0xc2 => game.FacilityBenefitShieldChargeRequestMessage.decode case 0xc3 => game.ProximityTerminalUseMessage.decode case 0xc4 => game.QuantityDeltaUpdateMessage.decode case 0xc5 => noDecoder(ChainLashMessage) @@ -608,7 +608,7 @@ object GamePacketOpcode extends Enumeration { case 0xf1 => game.MailMessage.decode case 0xf2 => noDecoder(GameVarUpdate) case 0xf3 => noDecoder(ClientCheatedMessage) - case default => noDecoder(opcode) + case _ => noDecoder(opcode) } implicit val codec: Codec[this.Value] = PacketHelpers.createEnumerationCodec(this, uint8L) diff --git a/common/src/main/scala/net/psforever/packet/game/FacilityBenefitShieldChargeRequestMessage.scala b/common/src/main/scala/net/psforever/packet/game/FacilityBenefitShieldChargeRequestMessage.scala new file mode 100644 index 00000000..15389532 --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/FacilityBenefitShieldChargeRequestMessage.scala @@ -0,0 +1,24 @@ +// Copyright (c) 2017 PSForever +package net.psforever.packet.game + +import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket} +import scodec.Codec +import scodec.codecs._ + +/** + * Dispatched by the client when driving a vehicle in the sphere of influence of an allied base + * that is a dropship center or that possesses the lattice-connected benefit of a dropship center. + * The vehicle that is being driven will not have perfect fully-charged shields at the time. + * @param vehicle_guid the vehicle whose shield is being charged + */ +final case class FacilityBenefitShieldChargeRequestMessage(vehicle_guid : PlanetSideGUID) + extends PlanetSideGamePacket { + type Packet = FacilityBenefitShieldChargeRequestMessage + def opcode = GamePacketOpcode.FacilityBenefitShieldChargeRequestMessage + def encode = FacilityBenefitShieldChargeRequestMessage.encode(this) +} + +object FacilityBenefitShieldChargeRequestMessage extends Marshallable[FacilityBenefitShieldChargeRequestMessage] { + implicit val codec : Codec[FacilityBenefitShieldChargeRequestMessage] = + ("vehicle_guid" | PlanetSideGUID.codec).as[FacilityBenefitShieldChargeRequestMessage] +} diff --git a/common/src/main/scala/net/psforever/packet/game/FavoritesMessage.scala b/common/src/main/scala/net/psforever/packet/game/FavoritesMessage.scala index 314986c4..3e28c027 100644 --- a/common/src/main/scala/net/psforever/packet/game/FavoritesMessage.scala +++ b/common/src/main/scala/net/psforever/packet/game/FavoritesMessage.scala @@ -51,11 +51,31 @@ final case class FavoritesMessage(list : LoadoutType.Value, } object FavoritesMessage extends Marshallable[FavoritesMessage] { + /** + * Overloaded constructor, for infantry loadouts specifically. + * @param list the destination list + * @param player_guid the player + * @param line the zero-indexed line number of this entry in its list + * @param label the identifier for this entry + * @param armor the type of exo-suit, if an Infantry loadout + * @return a `FavoritesMessage` object + */ + def apply(list : LoadoutType.Value, player_guid : PlanetSideGUID, line : Int, label : String, armor : Int) : FavoritesMessage = { + FavoritesMessage(list, player_guid, line, label, Some(armor)) + } + + /** + * Overloaded constructor, for vehicle loadouts specifically. + * @param list the destination list + * @param player_guid the player + * @param line the zero-indexed line number of this entry in its list + * @param label the identifier for this entry + * @return a `FavoritesMessage` object + */ def apply(list : LoadoutType.Value, player_guid : PlanetSideGUID, line : Int, label : String) : FavoritesMessage = { FavoritesMessage(list, player_guid, line, label, None) } - - implicit val codec : Codec[FavoritesMessage] = ( +implicit val codec : Codec[FavoritesMessage] = ( ("list" | LoadoutType.codec) >>:~ { value => ("player_guid" | PlanetSideGUID.codec) :: ("line" | uint4L) :: diff --git a/common/src/test/scala/game/FacilityBenefitShieldChargeRequestMessageTest.scala b/common/src/test/scala/game/FacilityBenefitShieldChargeRequestMessageTest.scala new file mode 100644 index 00000000..71b885c0 --- /dev/null +++ b/common/src/test/scala/game/FacilityBenefitShieldChargeRequestMessageTest.scala @@ -0,0 +1,28 @@ +// Copyright (c) 2017 PSForever +package game + +import org.specs2.mutable._ +import net.psforever.packet._ +import net.psforever.packet.game._ +import scodec.bits._ + +class FacilityBenefitShieldChargeRequestMessageTest extends Specification { + val string = hex"C2 4C00" + + "decode" in { + PacketCoding.DecodePacket(string).require match { + case FacilityBenefitShieldChargeRequestMessage(guid) => + guid mustEqual PlanetSideGUID(76) + case _ => + ko + } + } + + "encode" in { + val msg = FacilityBenefitShieldChargeRequestMessage(PlanetSideGUID(76)) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string + } +} + diff --git a/common/src/test/scala/game/FavoritesMessageTest.scala b/common/src/test/scala/game/FavoritesMessageTest.scala index 74e25392..660d088d 100644 --- a/common/src/test/scala/game/FavoritesMessageTest.scala +++ b/common/src/test/scala/game/FavoritesMessageTest.scala @@ -26,7 +26,7 @@ class FavoritesMessageTest extends Specification { } "encode (for infantry)" in { - val msg = FavoritesMessage(LoadoutType.Infantry, PlanetSideGUID(3760), 0, "Agile (basic)", Option(1)) + val msg = FavoritesMessage(LoadoutType.Infantry, PlanetSideGUID(3760), 0, "Agile (basic)", 1) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector pkt mustEqual stringInfantry diff --git a/common/src/test/scala/objects/LoadoutTest.scala b/common/src/test/scala/objects/LoadoutTest.scala index 1f32386e..67d0f310 100644 --- a/common/src/test/scala/objects/LoadoutTest.scala +++ b/common/src/test/scala/objects/LoadoutTest.scala @@ -110,6 +110,42 @@ class LoadoutTest extends Specification { ldout1.subtype mustEqual 0 ldout2.subtype mustEqual 1 ldout3.subtype mustEqual 2 - ldout4.subtype mustEqual 3 + ldout4.subtype mustEqual InfantryLoadout.DetermineSubtype(player) //example + } + + "players have additional uniform subtype" in { + val player = CreatePlayer() + val slot = player.Slot(0) + slot.Equipment = None //only an unequipped slot can have its Equipment Size changed (Rifle -> Max) + + player.ExoSuit = ExoSuitType.Standard + val ldout0 = Loadout.Create(player, "standard").asInstanceOf[InfantryLoadout] + player.ExoSuit = ExoSuitType.Agile + val ldout1 = Loadout.Create(player, "agile").asInstanceOf[InfantryLoadout] + player.ExoSuit = ExoSuitType.Reinforced + val ldout2 = Loadout.Create(player, "rein").asInstanceOf[InfantryLoadout] + player.ExoSuit = ExoSuitType.Infiltration + val ldout7 = Loadout.Create(player, "inf").asInstanceOf[InfantryLoadout] + + Player.SuitSetup(player, ExoSuitType.MAX) + val ldout3 = Loadout.Create(player, "weaponless").asInstanceOf[InfantryLoadout] + slot.Equipment = None + slot.Equipment = Tool(trhev_dualcycler) + val ldout4 = Loadout.Create(player, "cycler").asInstanceOf[InfantryLoadout] + slot.Equipment = None + slot.Equipment = Tool(trhev_pounder) + val ldout5 = Loadout.Create(player, "pounder").asInstanceOf[InfantryLoadout] + slot.Equipment = None + slot.Equipment = Tool(trhev_burster) + val ldout6 = Loadout.Create(player, "burster").asInstanceOf[InfantryLoadout] + + InfantryLoadout.DetermineSubtypeB(ldout0.exosuit, ldout0.subtype) mustEqual 0 + InfantryLoadout.DetermineSubtypeB(ldout1.exosuit, ldout1.subtype) mustEqual 1 + InfantryLoadout.DetermineSubtypeB(ldout2.exosuit, ldout2.subtype) mustEqual 2 + InfantryLoadout.DetermineSubtypeB(ldout3.exosuit, ldout3.subtype) mustEqual 3 + InfantryLoadout.DetermineSubtypeB(ldout4.exosuit, ldout4.subtype) mustEqual 4 + InfantryLoadout.DetermineSubtypeB(ldout5.exosuit, ldout5.subtype) mustEqual 5 + InfantryLoadout.DetermineSubtypeB(ldout6.exosuit, ldout6.subtype) mustEqual 6 + InfantryLoadout.DetermineSubtypeB(ldout7.exosuit, ldout7.subtype) mustEqual 7 } } diff --git a/common/src/test/scala/objects/ServerObjectBuilderTest.scala b/common/src/test/scala/objects/ServerObjectBuilderTest.scala index 1f5b6dcf..49678d5f 100644 --- a/common/src/test/scala/objects/ServerObjectBuilderTest.scala +++ b/common/src/test/scala/objects/ServerObjectBuilderTest.scala @@ -208,25 +208,6 @@ class SpawnTubeObjectBuilderTest extends ActorTest { } } -class RepairRearmSiloObjectBuilderTest extends ActorTest { - import net.psforever.objects.GlobalDefinitions.repair_silo - import net.psforever.objects.serverobject.terminals.RepairRearmSilo - "LockerObjectBuilder" should { - "build" in { - val hub = ServerObjectBuilderTest.NumberPoolHub - val actor = system.actorOf(Props(classOf[ServerObjectBuilderTest.BuilderTestActor], ServerObjectBuilder(1, - RepairRearmSilo.Constructor(repair_silo)), hub), "silo") - actor ! "!" - - val reply = receiveOne(Duration.create(1000, "ms")) - assert(reply.isInstanceOf[RepairRearmSilo]) - assert(reply.asInstanceOf[RepairRearmSilo].HasGUID) - assert(reply.asInstanceOf[RepairRearmSilo].GUID == PlanetSideGUID(1)) - assert(reply == hub(1).get) - } - } -} - object ServerObjectBuilderTest { import net.psforever.objects.guid.source.LimitedNumberSource def NumberPoolHub : NumberPoolHub = { diff --git a/common/src/test/scala/objects/terminal/RepairRearmSiloTest.scala b/common/src/test/scala/objects/terminal/RepairRearmSiloTest.scala index eeb6fa33..516e834c 100644 --- a/common/src/test/scala/objects/terminal/RepairRearmSiloTest.scala +++ b/common/src/test/scala/objects/terminal/RepairRearmSiloTest.scala @@ -4,7 +4,7 @@ package objects.terminal import akka.actor.ActorRef import net.psforever.objects.serverobject.structures.{Building, StructureType} import net.psforever.objects._ -import net.psforever.objects.serverobject.terminals.{RepairRearmSilo, Terminal} +import net.psforever.objects.serverobject.terminals.Terminal import net.psforever.objects.zones.Zone import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID} import net.psforever.types.{CharacterGender, PlanetSideEmpire, TransactionType} @@ -13,7 +13,7 @@ import org.specs2.mutable.Specification class RepairRearmSiloTest extends Specification { "RepairRearmSilo" should { val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)) - val silo = RepairRearmSilo(GlobalDefinitions.repair_silo) + val silo = Terminal(GlobalDefinitions.repair_silo) silo.Owner = new Building(0, Zone.Nowhere, StructureType.Building) silo.Owner.Faction = PlanetSideEmpire.TR @@ -22,7 +22,7 @@ class RepairRearmSiloTest extends Specification { } "construct" in { - val obj = RepairRearmSilo(GlobalDefinitions.repair_silo) + val obj = Terminal(GlobalDefinitions.repair_silo) obj.Actor mustEqual ActorRef.noSender } diff --git a/pslogin/src/main/scala/Maps.scala b/pslogin/src/main/scala/Maps.scala index 7d0494dd..c1b62dfa 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, RepairRearmSilo, Terminal} +import net.psforever.objects.serverobject.terminals.{ProximityTerminal, Terminal} import net.psforever.objects.serverobject.tube.SpawnTube import net.psforever.types.Vector3 @@ -113,8 +113,10 @@ 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(2049, ProximityTerminal.Constructor(repair_silo)) //repair terminal A + LocalObject(2050, Terminal.Constructor(repair_silo)) //rearm terminal A + LocalObject(2061, ProximityTerminal.Constructor(repair_silo)) //repair terminal B + LocalObject(2062, Terminal.Constructor(repair_silo)) //rearm terminal B LocalObject(2239, Terminal.Constructor(spawn_terminal)) LocalObject(2244, Terminal.Constructor(spawn_terminal)) LocalObject(2245, Terminal.Constructor(spawn_terminal)) @@ -216,7 +218,9 @@ object Maps { ObjectToBuilding(1576, 2) ObjectToBuilding(1577, 2) ObjectToBuilding(1578, 2) + ObjectToBuilding(2049, 2) ObjectToBuilding(2050, 2) + ObjectToBuilding(2061, 2) ObjectToBuilding(2062, 2) ObjectToBuilding(2145, 2) ObjectToBuilding(2146, 2) @@ -432,6 +436,8 @@ object Maps { def Building2() : Unit = { //HART building C LocalBuilding(2, FoundationBuilder(Building.Structure(StructureType.Building))) + LocalObject(12, ProximityTerminal.Constructor(repair_silo)) //repair terminal A + LocalObject(13, Terminal.Constructor(repair_silo)) //rearm terminal A //ItemTransaction: ItemTransactionMessage(PlanetSideGUID(2050),Buy,3,25mmbullet,0,PlanetSideGUID(0)) LocalObject(186, Terminal.Constructor(cert_terminal)) LocalObject(187, Terminal.Constructor(cert_terminal)) LocalObject(188, Terminal.Constructor(cert_terminal)) @@ -479,6 +485,8 @@ object Maps { LocalObject(1087, Terminal.Constructor(implant_terminal_interface)) //TODO guid not correct LocalObject(1088, Terminal.Constructor(implant_terminal_interface)) //TODO guid not correct LocalObject(1089, Terminal.Constructor(implant_terminal_interface)) //TODO guid not correct + ObjectToBuilding(12, 2) + ObjectToBuilding(13, 2) ObjectToBuilding(186, 2) ObjectToBuilding(187, 2) ObjectToBuilding(188, 2) diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala index ca2fd7ae..2461e431 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -1104,7 +1104,7 @@ class WorldSessionActor extends Actor with MDCContextAware { vehicleService ! VehicleServiceMessage.UnscheduleDeconstruction(vehicle_guid) } sendResponse(PlanetsideAttributeMessage(vehicle_guid, 22, 0L)) //mount points on? - //sendResponse(PlanetsideAttributeMessage(vehicle_guid, 0, vehicle.Definition.MaxHealth))) + sendResponse(PlanetsideAttributeMessage(vehicle_guid, 0, 10))//vehicle.Definition.MaxHealth)) sendResponse(PlanetsideAttributeMessage(vehicle_guid, 68, 0L)) //??? sendResponse(PlanetsideAttributeMessage(vehicle_guid, 113, 0L)) //??? ReloadVehicleAccessPermissions(vehicle) @@ -2327,21 +2327,20 @@ 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) sendResponse(BindPlayerMessage(1, "@ams", true, true, 0, 0, 0, obj.Position)) } + else if(obj.Definition == GlobalDefinitions.repair_silo) { + FindLocalVehicle match { + case Some(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") + } + } else { sendResponse(UseItemMessage(avatar_guid, unk1, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType)) } @@ -2368,7 +2367,7 @@ class WorldSessionActor extends Actor with MDCContextAware { } case msg @ ProximityTerminalUseMessage(player_guid, object_guid, _) => - log.info(s"ProximityTerminal: $msg") + log.info(s"ProximityTerminalUse: $msg") continent.GUID(object_guid) match { case Some(obj : Terminal with ProximityUnit) => if(usingProximityTerminal.contains(object_guid)) { @@ -2378,7 +2377,7 @@ class WorldSessionActor extends Actor with MDCContextAware { StartUsingProximityUnit(obj) } case Some(obj) => ; - log.warn(s"ProximityTerminalUse: object is not a proximity terminal - $obj") + log.warn(s"ProximityTerminalUse: object does not have proximity effects - $obj") case None => log.warn(s"ProximityTerminalUse: no object with guid $object_guid found") } @@ -2438,14 +2437,16 @@ class WorldSessionActor extends Actor with MDCContextAware { else { None }) match { - case Some(owner : Player) => + case Some(owner : Player) => //InfantryLoadout avatar.SaveLoadout(owner, name, lineno) - case Some(owner : Vehicle) => + import InfantryLoadout._ + sendResponse(FavoritesMessage(list, player_guid, line, name, DetermineSubtypeB(player.ExoSuit, DetermineSubtype(player)))) + case Some(owner : Vehicle) => //VehicleLoadout avatar.SaveLoadout(owner, name, lineno) + sendResponse(FavoritesMessage(list, player_guid, line, name)) case Some(_) | None => log.error("FavoritesRequest: unexpected owner for favorites") } - sendResponse(FavoritesMessage(list, player_guid, line, name)) case FavoritesAction.Delete => avatar.DeleteLoadout(lineno) @@ -2637,6 +2638,9 @@ class WorldSessionActor extends Actor with MDCContextAware { sendResponse(PlanetsideAttributeMessage(object_guid, attribute_type, attribute_value)) } + case msg @ FacilityBenefitShieldChargeRequestMessage(guid) => + //log.info(s"ShieldChargeRequest: $msg") + case msg @ BattleplanMessage(char_id, player_name, zonr_id, diagrams) => log.info("Battleplan: "+msg) @@ -4193,6 +4197,10 @@ class WorldSessionActor extends Actor with MDCContextAware { SetDelayedProximityUnitReset(terminal) ProximityHealCrystal(terminal) + case GlobalDefinitions.repair_silo => + SetDelayedProximityUnitReset(terminal) + //TODO insert vehicle repair here; see ProximityMedicalTerminal for example + case _ => ; } }