mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-07-13 15:34:45 +00:00
Merge pull request #1335 from psforever/empire_benefits_message_packet
EmpireBenefitsMessage packet
This commit is contained in:
commit
b8ea569b1c
11 changed files with 388 additions and 20 deletions
|
|
@ -2924,9 +2924,11 @@ class ZoningOperations(
|
||||||
0 seconds
|
0 seconds
|
||||||
} else {
|
} else {
|
||||||
//for other zones ...
|
//for other zones ...
|
||||||
|
//Searhus lock benefit also gives biolab faster respawn
|
||||||
|
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) => 0.5f
|
case b: Building if b.hasLatticeBenefit(LatticeBenefit.BioLaboratory) || (b.BuildingType == StructureType.Facility && !b.CaptureTerminalIsHacked && searhusBenefit) => 0.5f
|
||||||
case _ => 1f
|
case _ => 1f
|
||||||
}
|
}
|
||||||
//TODO cumulative death penalty
|
//TODO cumulative death penalty
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import net.psforever.objects.equipment.{Equipment, EquipmentSlot}
|
||||||
import net.psforever.objects.{PlanetSideGameObject, Vehicle}
|
import net.psforever.objects.{PlanetSideGameObject, Vehicle}
|
||||||
import net.psforever.packet.game.objectcreate._
|
import net.psforever.packet.game.objectcreate._
|
||||||
import net.psforever.types.{DriveState, PlanetSideGUID, VehicleFormat}
|
import net.psforever.types.{DriveState, PlanetSideGUID, VehicleFormat}
|
||||||
|
import net.psforever.zones.Zones
|
||||||
|
|
||||||
import scala.util.{Failure, Success, Try}
|
import scala.util.{Failure, Success, Try}
|
||||||
|
|
||||||
|
|
@ -14,6 +15,8 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() {
|
||||||
|
|
||||||
override def ConstructorData(obj: Vehicle): Try[VehicleData] = {
|
override def ConstructorData(obj: Vehicle): Try[VehicleData] = {
|
||||||
val health = StatConverter.Health(obj.Health, obj.MaxHealth)
|
val health = StatConverter.Health(obj.Health, obj.MaxHealth)
|
||||||
|
val boosted = if (Zones.zones.find(_.Number == 3).exists(_.benefitRecipient == obj.Faction)) true
|
||||||
|
else false
|
||||||
if (health > 0) { //active
|
if (health > 0) { //active
|
||||||
Success(
|
Success(
|
||||||
VehicleData(
|
VehicleData(
|
||||||
|
|
@ -32,7 +35,7 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() {
|
||||||
case None => PlanetSideGUID(0)
|
case None => PlanetSideGUID(0)
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
unk3 = false,
|
boostMaxHealth = boosted,
|
||||||
health,
|
health,
|
||||||
unk4 = false,
|
unk4 = false,
|
||||||
no_mount_points = false,
|
no_mount_points = false,
|
||||||
|
|
@ -59,7 +62,7 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() {
|
||||||
v5 = None,
|
v5 = None,
|
||||||
guid = PlanetSideGUID(0)
|
guid = PlanetSideGUID(0)
|
||||||
),
|
),
|
||||||
unk3 = false,
|
boostMaxHealth = boosted,
|
||||||
health = 0,
|
health = 0,
|
||||||
unk4 = false,
|
unk4 = false,
|
||||||
no_mount_points = true,
|
no_mount_points = true,
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.services.Service
|
import net.psforever.services.Service
|
||||||
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||||
import net.psforever.types.Vector3
|
import net.psforever.types.Vector3
|
||||||
|
import net.psforever.zones.Zones
|
||||||
|
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
@ -44,6 +45,12 @@ class VehicleSpawnControlLoadVehicle(pad: VehicleSpawnPad) extends VehicleSpawnC
|
||||||
) //appear below the trench and doors
|
) //appear below the trench and doors
|
||||||
vehicle.WhichSide = pad.WhichSide
|
vehicle.WhichSide = pad.WhichSide
|
||||||
vehicle.Cloaked = vehicle.Definition.CanCloak && driver.Cloaked
|
vehicle.Cloaked = vehicle.Definition.CanCloak && driver.Cloaked
|
||||||
|
// increase MaxHealth by 10% if driver has Cyssor empire armor benefit
|
||||||
|
if (Zones.zones.find(_.Number == 3).exists(_.benefitRecipient == driver.Faction)) {
|
||||||
|
val boosted = Math.round(vehicle.MaxHealth * 1.1).toInt
|
||||||
|
vehicle.MaxHealth = boosted
|
||||||
|
vehicle.Health = boosted
|
||||||
|
}
|
||||||
|
|
||||||
temp = Some(order)
|
temp = Some(order)
|
||||||
val result = ask(pad.Zone.Transport, Zone.Vehicle.Spawn(vehicle))
|
val result = ask(pad.Zone.Transport, Zone.Vehicle.Spawn(vehicle))
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ trait RepairableEntity extends Repairable {
|
||||||
*/
|
*/
|
||||||
protected def CanPerformRepairs(target: Repairable.Target, player: Player, item: Tool): Boolean = {
|
protected def CanPerformRepairs(target: Repairable.Target, player: Player, item: Tool): Boolean = {
|
||||||
val definition = target.Definition
|
val definition = target.Definition
|
||||||
definition.Repairable && target.Health < definition.MaxHealth && (definition.RepairIfDestroyed || !target.Destroyed) &&
|
definition.Repairable && target.Health < target.MaxHealth && (definition.RepairIfDestroyed || !target.Destroyed) &&
|
||||||
(target.Faction == player.Faction || target.Faction == PlanetSideEmpire.NEUTRAL) && item.Magazine > 0 &&
|
(target.Faction == player.Faction || target.Faction == PlanetSideEmpire.NEUTRAL) && item.Magazine > 0 &&
|
||||||
player.isAlive && Vector3.Distance(target.Position, player.Position) < definition.RepairDistance
|
player.isAlive && Vector3.Distance(target.Position, player.Position) < definition.RepairDistance
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,8 @@ import net.psforever.objects.vital.interaction.{DamageInteraction, DamageResult}
|
||||||
import net.psforever.objects.vital.prop.DamageWithPosition
|
import net.psforever.objects.vital.prop.DamageWithPosition
|
||||||
import net.psforever.objects.vital.Vitality
|
import net.psforever.objects.vital.Vitality
|
||||||
import net.psforever.objects.zones.blockmap.{BlockMap, SectorPopulation}
|
import net.psforever.objects.zones.blockmap.{BlockMap, SectorPopulation}
|
||||||
import net.psforever.packet.game.PropertyOverrideMessage
|
import net.psforever.packet.game.EmpireBenefitsMessage.{ZoneBenefit, ZoneLock, ZoneLockBenefit, ZoneLockZone}
|
||||||
|
import net.psforever.packet.game.{EmpireBenefitsMessage, PropertyOverrideMessage}
|
||||||
import net.psforever.services.Service
|
import net.psforever.services.Service
|
||||||
import net.psforever.zones.Zones
|
import net.psforever.zones.Zones
|
||||||
|
|
||||||
|
|
@ -682,11 +683,15 @@ class Zone(val id: String, val map: ZoneMap, zoneNumber: Int) {
|
||||||
|
|
||||||
if (perks.values.forall(_.isEmpty)) {/*do nothing*/}
|
if (perks.values.forall(_.isEmpty)) {/*do nothing*/}
|
||||||
else {
|
else {
|
||||||
val msg = PropertyOverrideMessage(List(PropertyOverrideMessage.GamePropertyScope(0, List(PropertyOverrideMessage.GamePropertyTarget(343,
|
val overrideMsg = PropertyOverrideMessage(List(PropertyOverrideMessage.GamePropertyScope(0, List(PropertyOverrideMessage.GamePropertyTarget(343,
|
||||||
List(PropertyOverrideMessage.GameProperty("purchase_exempt_vs", perks(PlanetSideEmpire.VS)),
|
List(PropertyOverrideMessage.GameProperty("purchase_exempt_vs", perks(PlanetSideEmpire.VS)),
|
||||||
PropertyOverrideMessage.GameProperty("purchase_exempt_tr", perks(PlanetSideEmpire.TR)),
|
PropertyOverrideMessage.GameProperty("purchase_exempt_tr", perks(PlanetSideEmpire.TR)),
|
||||||
PropertyOverrideMessage.GameProperty("purchase_exempt_nc", perks(PlanetSideEmpire.NC))))))))
|
PropertyOverrideMessage.GameProperty("purchase_exempt_nc", perks(PlanetSideEmpire.NC))))))))
|
||||||
building.Actor ! BuildingActor.HomeLockBenefits(msg)
|
building.Actor ! BuildingActor.HomeLockBenefits(overrideMsg)
|
||||||
|
}
|
||||||
|
val benefitMsg = BuildEmpireBenefits()
|
||||||
|
if (benefitMsg.zoneLocks.nonEmpty) {
|
||||||
|
building.Actor ! BuildingActor.HomeLockBenefits(benefitMsg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -716,12 +721,71 @@ class Zone(val id: String, val map: ZoneMap, zoneNumber: Int) {
|
||||||
|
|
||||||
if (perks.values.forall(_.isEmpty)) {/*do nothing*/}
|
if (perks.values.forall(_.isEmpty)) {/*do nothing*/}
|
||||||
else {
|
else {
|
||||||
val msg = PropertyOverrideMessage(List(PropertyOverrideMessage.GamePropertyScope(0, List(PropertyOverrideMessage.GamePropertyTarget(343,
|
val overrideMsg = PropertyOverrideMessage(List(PropertyOverrideMessage.GamePropertyScope(0, List(PropertyOverrideMessage.GamePropertyTarget(343,
|
||||||
List(PropertyOverrideMessage.GameProperty("purchase_exempt_vs", perks(PlanetSideEmpire.VS)),
|
List(PropertyOverrideMessage.GameProperty("purchase_exempt_vs", perks(PlanetSideEmpire.VS)),
|
||||||
PropertyOverrideMessage.GameProperty("purchase_exempt_tr", perks(PlanetSideEmpire.TR)),
|
PropertyOverrideMessage.GameProperty("purchase_exempt_tr", perks(PlanetSideEmpire.TR)),
|
||||||
PropertyOverrideMessage.GameProperty("purchase_exempt_nc", perks(PlanetSideEmpire.NC))))))))
|
PropertyOverrideMessage.GameProperty("purchase_exempt_nc", perks(PlanetSideEmpire.NC))))))))
|
||||||
PlayerControl.sendResponse(player.Zone, player.Name, msg)
|
PlayerControl.sendResponse(player.Zone, player.Name, overrideMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val benefitMsg = BuildEmpireBenefits()
|
||||||
|
if (benefitMsg.zoneLocks.nonEmpty) {
|
||||||
|
PlayerControl.sendResponse(player.Zone, player.Name, benefitMsg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def BuildEmpireBenefits(): EmpireBenefitsMessage = {
|
||||||
|
val locks = scala.collection.mutable.ArrayBuffer[ZoneLock]()
|
||||||
|
val benefits = scala.collection.mutable.ArrayBuffer[ZoneBenefit]()
|
||||||
|
val homeSets: Map[PlanetSideEmpire.Value, Set[Int]] = Map(
|
||||||
|
PlanetSideEmpire.TR -> Set(1, 2),
|
||||||
|
PlanetSideEmpire.VS -> Set(5, 6),
|
||||||
|
PlanetSideEmpire.NC -> Set(7, 10)
|
||||||
|
)
|
||||||
|
val benefitOfZones: Map[Int, Int] = Map(
|
||||||
|
3 -> 6, // Cyssor gives benefit 6 (+10% armor bonus to vehicles)
|
||||||
|
4 -> 1, // Ishundar gives benefit 1 (vehicle shields)
|
||||||
|
9 -> 3 // Searhus gives benefit 3 (faster respawn)
|
||||||
|
)
|
||||||
|
val homePerkBenefits: Map[PlanetSideEmpire.Value, Int] = Map(
|
||||||
|
PlanetSideEmpire.TR -> 7,
|
||||||
|
PlanetSideEmpire.NC -> 8,
|
||||||
|
PlanetSideEmpire.VS -> 9
|
||||||
|
)
|
||||||
|
def isLockedBy(homeSet: Set[Int], empire: PlanetSideEmpire.Value): Boolean =
|
||||||
|
Zones.zones.filter(z => homeSet.contains(z.Number)).forall(_.benefitRecipient == empire)
|
||||||
|
|
||||||
|
// home zone perks
|
||||||
|
homeSets.foreach { case (owner, set) =>
|
||||||
|
PlanetSideEmpire.values.filterNot(_ == PlanetSideEmpire.NEUTRAL).foreach { empire =>
|
||||||
|
if (owner != empire && isLockedBy(set, empire)) {
|
||||||
|
locks += ZoneLock(empire, s"lock-${owner.toString.toLowerCase}-homes")
|
||||||
|
benefits += ZoneBenefit(empire, ZoneLockBenefit(homePerkBenefits(owner)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
benefitOfZones.foreach { case (zoneNum, benefitId) =>
|
||||||
|
Zones.zones.find(_.Number == zoneNum).foreach { z =>
|
||||||
|
z.benefitRecipient match {
|
||||||
|
case PlanetSideEmpire.NEUTRAL =>
|
||||||
|
//nothing
|
||||||
|
case empire =>
|
||||||
|
locks += ZoneLock(empire, s"lock-z$zoneNum")
|
||||||
|
benefits += ZoneBenefit(empire, ZoneLockBenefit(benefitId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// all four islands together give benefit 4 (vehicle repair)
|
||||||
|
val islandZones: Set[Int] = Set(29, 30, 31, 32)
|
||||||
|
val islandBenefit: Int = 4
|
||||||
|
PlanetSideEmpire.values.filterNot(_ == PlanetSideEmpire.NEUTRAL).foreach { empire =>
|
||||||
|
if (isLockedBy(islandZones, empire)) {
|
||||||
|
locks += ZoneLock(empire, ZoneLockZone.i1_i2_i3_i4)
|
||||||
|
benefits += ZoneBenefit(empire, ZoneLockBenefit(islandBenefit))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EmpireBenefitsMessage(locks.toVector, benefits.toVector)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -557,7 +557,7 @@ object GamePacketOpcode extends Enumeration {
|
||||||
case 0xd4 => game.GenericObjectActionAtPositionMessage.decode
|
case 0xd4 => game.GenericObjectActionAtPositionMessage.decode
|
||||||
case 0xd5 => game.PropertyOverrideMessage.decode
|
case 0xd5 => game.PropertyOverrideMessage.decode
|
||||||
case 0xd6 => game.WarpgateLinkOverrideMessage.decode
|
case 0xd6 => game.WarpgateLinkOverrideMessage.decode
|
||||||
case 0xd7 => noDecoder(EmpireBenefitsMessage)
|
case 0xd7 => game.EmpireBenefitsMessage.decode
|
||||||
// 0xd8
|
// 0xd8
|
||||||
case 0xd8 => noDecoder(ForceEmpireMessage)
|
case 0xd8 => noDecoder(ForceEmpireMessage)
|
||||||
case 0xd9 => game.BroadcastWarpgateUpdateMessage.decode
|
case 0xd9 => game.BroadcastWarpgateUpdateMessage.decode
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
// Copyright (c) 2025 PSForever
|
||||||
|
package net.psforever.packet.game
|
||||||
|
|
||||||
|
import net.psforever.packet.game.EmpireBenefitsMessage.{ZoneBenefit, ZoneLock}
|
||||||
|
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
||||||
|
import net.psforever.types.PlanetSideEmpire
|
||||||
|
import scodec.Codec
|
||||||
|
import scodec.codecs._
|
||||||
|
|
||||||
|
import scala.language.implicitConversions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EmpireBenefitsMessage
|
||||||
|
*
|
||||||
|
* zoneLocks gives the client information about which empire locks what continent.
|
||||||
|
* This produces a chat message.
|
||||||
|
* zoneBenefits tells the client what empire has which benefits enabled.
|
||||||
|
* This has to match zoneLocks to work properly.
|
||||||
|
*/
|
||||||
|
final case class EmpireBenefitsMessage(
|
||||||
|
zoneLocks: Vector[ZoneLock],
|
||||||
|
zoneBenefits: Vector[ZoneBenefit]
|
||||||
|
) extends PlanetSideGamePacket {
|
||||||
|
type Packet = EmpireBenefitsMessage
|
||||||
|
def opcode = GamePacketOpcode.EmpireBenefitsMessage
|
||||||
|
def encode = EmpireBenefitsMessage.encode(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
object EmpireBenefitsMessage extends Marshallable[EmpireBenefitsMessage] {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZoneLockZone
|
||||||
|
*
|
||||||
|
* Available Types of Zones
|
||||||
|
*
|
||||||
|
* These zones can be used to notify the client of a lock.
|
||||||
|
*/
|
||||||
|
object ZoneLockZone extends Enumeration {
|
||||||
|
type Type = String
|
||||||
|
|
||||||
|
val i1: ZoneLockZone.Value = Value("lock-i1") // Extinction Continental Lock
|
||||||
|
val i2: ZoneLockZone.Value = Value("lock-i2") // Ascension Continental Lock
|
||||||
|
val i3: ZoneLockZone.Value = Value("lock-i3") // Desolation Continental Lock
|
||||||
|
val i4: ZoneLockZone.Value = Value("lock-i4") // Nexus Continental Lock
|
||||||
|
val i1_i2_i3_i4: ZoneLockZone.Value = Value("lock-i1-i2-i3-i4") // Oshur Cluster Lock
|
||||||
|
val z3: ZoneLockZone.Value = Value("lock-z3") // Cyssor Continental Lock
|
||||||
|
val z4: ZoneLockZone.Value = Value("lock-z4") // Ishundar Continental Lock
|
||||||
|
val z9: ZoneLockZone.Value = Value("lock-z9") // Searhus Continental Lock
|
||||||
|
val tr_homes: ZoneLockZone.Value = Value("lock-tr-homes") // TR Home Continent Lock
|
||||||
|
val nc_homes: ZoneLockZone.Value = Value("lock-nc-homes") // NC Home Continent Lock
|
||||||
|
val vs_homes: ZoneLockZone.Value = Value("lock-vs-homes") // VS Home Continent Lock
|
||||||
|
|
||||||
|
implicit def valueToType(v: ZoneLockZone.Value): Type = v.toString
|
||||||
|
implicit val codec: Codec[Type] = PacketHelpers.encodedStringAligned(6)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZoneLockBenefit
|
||||||
|
*
|
||||||
|
* Available Types of Benefits
|
||||||
|
*
|
||||||
|
* Benefits 0, 2 and 5 are unknown. Benefits for i1 to i4 are unknown and mapped incorrectly here.
|
||||||
|
*/
|
||||||
|
object ZoneLockBenefit extends Enumeration {
|
||||||
|
type Type = Value
|
||||||
|
|
||||||
|
val i1: ZoneLockBenefit.Value = Value(-1) // Extinction Continental Lock
|
||||||
|
val i2: ZoneLockBenefit.Value = Value(-2) // Ascension Continental Lock
|
||||||
|
val i3: ZoneLockBenefit.Value = Value(-3) // Desolation Continental Lock
|
||||||
|
val i4: ZoneLockBenefit.Value = Value(-4) // Nexus Continental Lock
|
||||||
|
|
||||||
|
// val unk0: ZoneLockBenefit.Value = Value(0)
|
||||||
|
val z4: ZoneLockBenefit.Value = Value(1) // Ishundar Continental Lock
|
||||||
|
// val unk2: ZoneLockBenefit.Value = Value(2)
|
||||||
|
val z9: ZoneLockBenefit.Value = Value(3) // Searhus Continental Lock
|
||||||
|
val i1_i2_i3_i4: ZoneLockBenefit.Value = Value(4) // Oshur Cluster Lock
|
||||||
|
// val unk5: ZoneLockBenefit.Value = Value(5)
|
||||||
|
val z3: ZoneLockBenefit.Value = Value(6) // Cyssor Continental Lock
|
||||||
|
val tr_homes: ZoneLockBenefit.Value = Value(7) // TR Home Continent Lock
|
||||||
|
val nc_homes: ZoneLockBenefit.Value = Value(8) // NC Home Continent Lock
|
||||||
|
val vs_homes: ZoneLockBenefit.Value = Value(9) // VS Home Continent Lock
|
||||||
|
|
||||||
|
implicit val codec: Codec[Type] = PacketHelpers.createEnumerationCodec(this, uint16L)
|
||||||
|
}
|
||||||
|
|
||||||
|
final case class ZoneLock(
|
||||||
|
empire: PlanetSideEmpire.Type,
|
||||||
|
zone: ZoneLockZone.Type,
|
||||||
|
)
|
||||||
|
|
||||||
|
final case class ZoneBenefit(
|
||||||
|
empire: PlanetSideEmpire.Type,
|
||||||
|
value: ZoneLockBenefit.Type
|
||||||
|
)
|
||||||
|
|
||||||
|
private implicit val zoneLockCodec: Codec[ZoneLock] = (
|
||||||
|
("empire" | PlanetSideEmpire.codec) ::
|
||||||
|
("zone" | ZoneLockZone.codec)
|
||||||
|
).as[ZoneLock]
|
||||||
|
|
||||||
|
private implicit val zoneBenefitCodec: Codec[ZoneBenefit] = (
|
||||||
|
("empire" | PlanetSideEmpire.codec) ::
|
||||||
|
("benefit" | ZoneLockBenefit.codec)
|
||||||
|
).as[ZoneBenefit]
|
||||||
|
|
||||||
|
implicit val codec: Codec[EmpireBenefitsMessage] = (
|
||||||
|
("zoneLocks" | vectorOfN(uint32L.xmap(_.toInt, _.toLong), zoneLockCodec)) ::
|
||||||
|
("zoneBenefits" | vectorOfN(uint32L.xmap(_.toInt, _.toLong), zoneBenefitCodec))
|
||||||
|
).as[EmpireBenefitsMessage]
|
||||||
|
}
|
||||||
|
|
@ -44,7 +44,7 @@ final case class VariantVehicleData(unk: Int) extends SpecificVehicleData(Vehicl
|
||||||
* -jammered - vehicles will not be jammered by setting this field<br>
|
* -jammered - vehicles will not be jammered by setting this field<br>
|
||||||
* -player_guid the vehicle's (official) owner;
|
* -player_guid the vehicle's (official) owner;
|
||||||
* a living player in the game world on the same continent as the vehicle who may mount the driver mount
|
* a living player in the game world on the same continent as the vehicle who may mount the driver mount
|
||||||
* @param unk3 na
|
* @param boostMaxHealth vehicle gets 10% more armor from vehicle armor benefit given by Cyssor empire lock
|
||||||
* @param health the amount of health the vehicle has, as a percentage of a filled bar (255)
|
* @param health the amount of health the vehicle has, as a percentage of a filled bar (255)
|
||||||
* @param unk4 na
|
* @param unk4 na
|
||||||
* @param no_mount_points do not display entry points for the seats
|
* @param no_mount_points do not display entry points for the seats
|
||||||
|
|
@ -65,7 +65,7 @@ final case class VariantVehicleData(unk: Int) extends SpecificVehicleData(Vehicl
|
||||||
final case class VehicleData(
|
final case class VehicleData(
|
||||||
pos: PlacementData,
|
pos: PlacementData,
|
||||||
data: CommonFieldData,
|
data: CommonFieldData,
|
||||||
unk3: Boolean,
|
boostMaxHealth: Boolean,
|
||||||
health: Int,
|
health: Int,
|
||||||
unk4: Boolean,
|
unk4: Boolean,
|
||||||
no_mount_points: Boolean,
|
no_mount_points: Boolean,
|
||||||
|
|
@ -106,7 +106,7 @@ object VehicleData extends Marshallable[VehicleData] {
|
||||||
cloak: Boolean,
|
cloak: Boolean,
|
||||||
inventory: Option[InventoryData]
|
inventory: Option[InventoryData]
|
||||||
): VehicleData = {
|
): VehicleData = {
|
||||||
VehicleData(pos, basic, unk3 = false, health, unk4 = false, no_mount_points = false, driveState, unk5 = false, unk6 = false, cloak = cloak, None, inventory)(
|
VehicleData(pos, basic, boostMaxHealth = false, health, unk4 = false, no_mount_points = false, driveState, unk5 = false, unk6 = false, cloak = cloak, None, inventory)(
|
||||||
VehicleFormat.Normal
|
VehicleFormat.Normal
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -128,7 +128,7 @@ object VehicleData extends Marshallable[VehicleData] {
|
||||||
format: UtilityVehicleData,
|
format: UtilityVehicleData,
|
||||||
inventory: Option[InventoryData]
|
inventory: Option[InventoryData]
|
||||||
): VehicleData = {
|
): VehicleData = {
|
||||||
VehicleData(pos, basic, unk3 = false, health, unk4 = false, no_mount_points = false, driveState, unk5 = false, unk6 = false, cloak = cloak, Some(format), inventory)(
|
VehicleData(pos, basic, boostMaxHealth = false, health, unk4 = false, no_mount_points = false, driveState, unk5 = false, unk6 = false, cloak = cloak, Some(format), inventory)(
|
||||||
VehicleFormat.Utility
|
VehicleFormat.Utility
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -150,7 +150,7 @@ object VehicleData extends Marshallable[VehicleData] {
|
||||||
format: VariantVehicleData,
|
format: VariantVehicleData,
|
||||||
inventory: Option[InventoryData]
|
inventory: Option[InventoryData]
|
||||||
): VehicleData = {
|
): VehicleData = {
|
||||||
VehicleData(pos, basic, unk3 = false, health, unk4 = false, no_mount_points = false, driveState, unk5 = false, unk6 = false, cloak = cloak, Some(format), inventory)(
|
VehicleData(pos, basic, boostMaxHealth = false, health, unk4 = false, no_mount_points = false, driveState, unk5 = false, unk6 = false, cloak = cloak, Some(format), inventory)(
|
||||||
VehicleFormat.Variant
|
VehicleFormat.Variant
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
182
src/test/scala/game/EmpireBenefitsMessageTest.scala
Normal file
182
src/test/scala/game/EmpireBenefitsMessageTest.scala
Normal file
|
|
@ -0,0 +1,182 @@
|
||||||
|
// Copyright (c) 2025 PSForever
|
||||||
|
package game
|
||||||
|
|
||||||
|
import net.psforever.packet._
|
||||||
|
import net.psforever.packet.game.EmpireBenefitsMessage
|
||||||
|
import net.psforever.packet.game.EmpireBenefitsMessage.{ZoneBenefit, ZoneLock, ZoneLockBenefit, ZoneLockZone}
|
||||||
|
import net.psforever.types.PlanetSideEmpire
|
||||||
|
import org.specs2.mutable._
|
||||||
|
import scodec.bits._
|
||||||
|
|
||||||
|
class EmpireBenefitsMessageTest extends Specification {
|
||||||
|
|
||||||
|
val sample1: ByteVector = ByteVector.fromValidHex(
|
||||||
|
"d7" + // header
|
||||||
|
"04000000" + // count uint32L
|
||||||
|
"21c06c6f636b2d7a3321c06c6f636b2d7a3464006c6f636b2d69312d69322d69332d6934a1c06c6f636b2d7a39" +
|
||||||
|
"04000000" + // count uint32L
|
||||||
|
"004000600410020300"
|
||||||
|
)
|
||||||
|
|
||||||
|
val sample2: ByteVector = ByteVector.fromValidHex(
|
||||||
|
"d7" +
|
||||||
|
"05000000 23406c6f636b2d76732d686f6d657321c06c6f636b2d7a3321c06c6f636b2d7a3461c06c6f636b2d7a3964006c6f636b2d69312d69322d69332d6934" +
|
||||||
|
"05000000 004000600024010300410000"
|
||||||
|
)
|
||||||
|
|
||||||
|
val sample3: ByteVector = ByteVector.fromValidHex(
|
||||||
|
"d7" +
|
||||||
|
"05000000 21c06c6f636b2d7a3321c06c6f636b2d7a3423406c6f636b2d6e632d686f6d657361c06c6f636b2d7a39a4006c6f636b2d69312d69322d69332d6934" +
|
||||||
|
"05000000 004000600020010300810000"
|
||||||
|
)
|
||||||
|
|
||||||
|
val sample4: ByteVector = ByteVector.fromValidHex(
|
||||||
|
"d7" +
|
||||||
|
"06000000 a3406c6f636b2d6e632d686f6d6573a3406c6f636b2d74722d686f6d6573a1c06c6f636b2d7a33a1c06c6f636b2d7a34a1c06c6f636b2d7a39a4006c6f636b2d69312d69322d69332d6934" +
|
||||||
|
"06000000 80402030081002060081c0208000"
|
||||||
|
)
|
||||||
|
|
||||||
|
private val sample1_expectedLocks = Vector(
|
||||||
|
ZoneLock(PlanetSideEmpire.TR, ZoneLockZone.z3),
|
||||||
|
ZoneLock(PlanetSideEmpire.TR, ZoneLockZone.z4),
|
||||||
|
ZoneLock(PlanetSideEmpire.NC, ZoneLockZone.i1_i2_i3_i4),
|
||||||
|
ZoneLock(PlanetSideEmpire.VS, ZoneLockZone.z9)
|
||||||
|
)
|
||||||
|
|
||||||
|
private val sample1_expectedBenefits = Vector(
|
||||||
|
ZoneBenefit(PlanetSideEmpire.TR, ZoneLockBenefit.z4),
|
||||||
|
ZoneBenefit(PlanetSideEmpire.TR, ZoneLockBenefit.z3),
|
||||||
|
ZoneBenefit(PlanetSideEmpire.NC, ZoneLockBenefit.i1_i2_i3_i4),
|
||||||
|
ZoneBenefit(PlanetSideEmpire.VS, ZoneLockBenefit.z9)
|
||||||
|
)
|
||||||
|
|
||||||
|
private val sample2_expectedLocks = Vector(
|
||||||
|
ZoneLock(PlanetSideEmpire.TR, ZoneLockZone.vs_homes),
|
||||||
|
ZoneLock(PlanetSideEmpire.TR, ZoneLockZone.z3),
|
||||||
|
ZoneLock(PlanetSideEmpire.TR, ZoneLockZone.z4),
|
||||||
|
ZoneLock(PlanetSideEmpire.NC, ZoneLockZone.z9),
|
||||||
|
ZoneLock(PlanetSideEmpire.NC, ZoneLockZone.i1_i2_i3_i4)
|
||||||
|
)
|
||||||
|
|
||||||
|
private val sample2_expectedBenefits = Vector(
|
||||||
|
ZoneBenefit(PlanetSideEmpire.TR, ZoneLockBenefit.z4),
|
||||||
|
ZoneBenefit(PlanetSideEmpire.TR, ZoneLockBenefit.z3),
|
||||||
|
ZoneBenefit(PlanetSideEmpire.TR, ZoneLockBenefit.vs_homes),
|
||||||
|
ZoneBenefit(PlanetSideEmpire.NC, ZoneLockBenefit.z9),
|
||||||
|
ZoneBenefit(PlanetSideEmpire.NC, ZoneLockBenefit.i1_i2_i3_i4)
|
||||||
|
)
|
||||||
|
|
||||||
|
private val sample3_expectedLocks = Vector(
|
||||||
|
ZoneLock(PlanetSideEmpire.TR, ZoneLockZone.z3),
|
||||||
|
ZoneLock(PlanetSideEmpire.TR, ZoneLockZone.z4),
|
||||||
|
ZoneLock(PlanetSideEmpire.TR, ZoneLockZone.nc_homes),
|
||||||
|
ZoneLock(PlanetSideEmpire.NC, ZoneLockZone.z9),
|
||||||
|
ZoneLock(PlanetSideEmpire.VS, ZoneLockZone.i1_i2_i3_i4)
|
||||||
|
)
|
||||||
|
|
||||||
|
private val sample3_expectedBenefits = Vector(
|
||||||
|
ZoneBenefit(PlanetSideEmpire.TR, ZoneLockBenefit.z4),
|
||||||
|
ZoneBenefit(PlanetSideEmpire.TR, ZoneLockBenefit.z3),
|
||||||
|
ZoneBenefit(PlanetSideEmpire.TR, ZoneLockBenefit.nc_homes),
|
||||||
|
ZoneBenefit(PlanetSideEmpire.NC, ZoneLockBenefit.z9),
|
||||||
|
ZoneBenefit(PlanetSideEmpire.VS, ZoneLockBenefit.i1_i2_i3_i4)
|
||||||
|
)
|
||||||
|
|
||||||
|
private val sample4_expectedLocks = Vector(
|
||||||
|
ZoneLock(PlanetSideEmpire.VS, ZoneLockZone.nc_homes),
|
||||||
|
ZoneLock(PlanetSideEmpire.VS, ZoneLockZone.tr_homes),
|
||||||
|
ZoneLock(PlanetSideEmpire.VS, ZoneLockZone.z3),
|
||||||
|
ZoneLock(PlanetSideEmpire.VS, ZoneLockZone.z4),
|
||||||
|
ZoneLock(PlanetSideEmpire.VS, ZoneLockZone.z9),
|
||||||
|
ZoneLock(PlanetSideEmpire.VS, ZoneLockZone.i1_i2_i3_i4)
|
||||||
|
)
|
||||||
|
|
||||||
|
private val sample4_expectedBenefits = Vector(
|
||||||
|
ZoneBenefit(PlanetSideEmpire.VS, ZoneLockBenefit.z4),
|
||||||
|
ZoneBenefit(PlanetSideEmpire.VS, ZoneLockBenefit.z9),
|
||||||
|
ZoneBenefit(PlanetSideEmpire.VS, ZoneLockBenefit.i1_i2_i3_i4),
|
||||||
|
ZoneBenefit(PlanetSideEmpire.VS, ZoneLockBenefit.z3),
|
||||||
|
ZoneBenefit(PlanetSideEmpire.VS, ZoneLockBenefit.tr_homes),
|
||||||
|
ZoneBenefit(PlanetSideEmpire.VS, ZoneLockBenefit.nc_homes)
|
||||||
|
)
|
||||||
|
|
||||||
|
"decode sample1" in {
|
||||||
|
PacketCoding.decodePacket(sample1).require match {
|
||||||
|
case EmpireBenefitsMessage(a, b) =>
|
||||||
|
a mustEqual sample1_expectedLocks
|
||||||
|
b mustEqual sample1_expectedBenefits
|
||||||
|
case _ =>
|
||||||
|
ko
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"encode sample1" in {
|
||||||
|
val msg = EmpireBenefitsMessage(
|
||||||
|
zoneLocks = sample1_expectedLocks,
|
||||||
|
zoneBenefits = sample1_expectedBenefits
|
||||||
|
)
|
||||||
|
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
|
pkt mustEqual sample1
|
||||||
|
}
|
||||||
|
|
||||||
|
"decode sample2" in {
|
||||||
|
PacketCoding.decodePacket(sample2).require match {
|
||||||
|
case EmpireBenefitsMessage(a, b) =>
|
||||||
|
a mustEqual sample2_expectedLocks
|
||||||
|
b mustEqual sample2_expectedBenefits
|
||||||
|
case _ =>
|
||||||
|
ko
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"encode sample2" in {
|
||||||
|
val msg = EmpireBenefitsMessage(
|
||||||
|
zoneLocks = sample2_expectedLocks,
|
||||||
|
zoneBenefits = sample2_expectedBenefits
|
||||||
|
)
|
||||||
|
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
|
pkt mustEqual sample2
|
||||||
|
}
|
||||||
|
|
||||||
|
"decode sample3" in {
|
||||||
|
PacketCoding.decodePacket(sample3).require match {
|
||||||
|
case EmpireBenefitsMessage(a, b) =>
|
||||||
|
a mustEqual sample3_expectedLocks
|
||||||
|
b mustEqual sample3_expectedBenefits
|
||||||
|
case _ =>
|
||||||
|
ko
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"encode sample3" in {
|
||||||
|
val msg = EmpireBenefitsMessage(
|
||||||
|
zoneLocks = sample3_expectedLocks,
|
||||||
|
zoneBenefits = sample3_expectedBenefits
|
||||||
|
)
|
||||||
|
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
|
pkt mustEqual sample3
|
||||||
|
}
|
||||||
|
|
||||||
|
"decode sample4" in {
|
||||||
|
PacketCoding.decodePacket(sample4).require match {
|
||||||
|
case EmpireBenefitsMessage(a, b) =>
|
||||||
|
a mustEqual sample4_expectedLocks
|
||||||
|
b mustEqual sample4_expectedBenefits
|
||||||
|
case _ =>
|
||||||
|
ko
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"encode sample4" in {
|
||||||
|
val msg = EmpireBenefitsMessage(
|
||||||
|
zoneLocks = sample4_expectedLocks,
|
||||||
|
zoneBenefits = sample4_expectedBenefits
|
||||||
|
)
|
||||||
|
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
|
pkt mustEqual sample4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -39,7 +39,7 @@ class MountedVehiclesTest extends Specification {
|
||||||
vdata.no_mount_points mustEqual false
|
vdata.no_mount_points mustEqual false
|
||||||
vdata.driveState mustEqual DriveState.Mobile
|
vdata.driveState mustEqual DriveState.Mobile
|
||||||
vdata.cloak mustEqual false
|
vdata.cloak mustEqual false
|
||||||
vdata.unk3 mustEqual false
|
vdata.boostMaxHealth mustEqual false
|
||||||
vdata.unk4 mustEqual false
|
vdata.unk4 mustEqual false
|
||||||
vdata.unk5 mustEqual false
|
vdata.unk5 mustEqual false
|
||||||
vdata.unk6 mustEqual false
|
vdata.unk6 mustEqual false
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ class UtilityVehiclesTest extends Specification {
|
||||||
ant.driveState mustEqual DriveState.Mobile
|
ant.driveState mustEqual DriveState.Mobile
|
||||||
ant.health mustEqual 255
|
ant.health mustEqual 255
|
||||||
ant.cloak mustEqual false
|
ant.cloak mustEqual false
|
||||||
ant.unk3 mustEqual false
|
ant.boostMaxHealth mustEqual false
|
||||||
ant.unk4 mustEqual false
|
ant.unk4 mustEqual false
|
||||||
ant.unk5 mustEqual false
|
ant.unk5 mustEqual false
|
||||||
ant.unk6 mustEqual false
|
ant.unk6 mustEqual false
|
||||||
|
|
@ -67,7 +67,7 @@ class UtilityVehiclesTest extends Specification {
|
||||||
ams.vehicle_format_data mustEqual Some(UtilityVehicleData(60))
|
ams.vehicle_format_data mustEqual Some(UtilityVehicleData(60))
|
||||||
ams.health mustEqual 236
|
ams.health mustEqual 236
|
||||||
ams.cloak mustEqual true
|
ams.cloak mustEqual true
|
||||||
ams.unk3 mustEqual false
|
ams.boostMaxHealth mustEqual false
|
||||||
ams.unk4 mustEqual false
|
ams.unk4 mustEqual false
|
||||||
ams.unk5 mustEqual false
|
ams.unk5 mustEqual false
|
||||||
ams.unk6 mustEqual true
|
ams.unk6 mustEqual true
|
||||||
|
|
@ -120,7 +120,7 @@ class UtilityVehiclesTest extends Specification {
|
||||||
case _ =>
|
case _ =>
|
||||||
ko
|
ko
|
||||||
}
|
}
|
||||||
ams.unk3 mustEqual false
|
ams.boostMaxHealth mustEqual false
|
||||||
ams.health mustEqual 255
|
ams.health mustEqual 255
|
||||||
ams.unk4 mustEqual false
|
ams.unk4 mustEqual false
|
||||||
ams.no_mount_points mustEqual false
|
ams.no_mount_points mustEqual false
|
||||||
|
|
@ -320,7 +320,7 @@ class UtilityVehiclesTest extends Specification {
|
||||||
Some(Vector3(27.3375f, -0.78749996f, 0.1125f))
|
Some(Vector3(27.3375f, -0.78749996f, 0.1125f))
|
||||||
),
|
),
|
||||||
CommonFieldData(PlanetSideEmpire.TR, false, false, false, None, false, Some(false), None, PlanetSideGUID(3087)),
|
CommonFieldData(PlanetSideEmpire.TR, false, false, false, None, false, Some(false), None, PlanetSideGUID(3087)),
|
||||||
unk3 = false,
|
boostMaxHealth = false,
|
||||||
health = 255,
|
health = 255,
|
||||||
unk4 = false,
|
unk4 = false,
|
||||||
no_mount_points = false,
|
no_mount_points = false,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue