diff --git a/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala b/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala index 80376a530..ddeff7e31 100644 --- a/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala +++ b/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala @@ -2924,9 +2924,11 @@ class ZoningOperations( 0 seconds } else { //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 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 } //TODO cumulative death penalty diff --git a/src/main/scala/net/psforever/objects/definition/converter/VehicleConverter.scala b/src/main/scala/net/psforever/objects/definition/converter/VehicleConverter.scala index b363fcee4..fa0a41787 100644 --- a/src/main/scala/net/psforever/objects/definition/converter/VehicleConverter.scala +++ b/src/main/scala/net/psforever/objects/definition/converter/VehicleConverter.scala @@ -5,6 +5,7 @@ import net.psforever.objects.equipment.{Equipment, EquipmentSlot} import net.psforever.objects.{PlanetSideGameObject, Vehicle} import net.psforever.packet.game.objectcreate._ import net.psforever.types.{DriveState, PlanetSideGUID, VehicleFormat} +import net.psforever.zones.Zones import scala.util.{Failure, Success, Try} @@ -14,6 +15,8 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() { override def ConstructorData(obj: Vehicle): Try[VehicleData] = { 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 Success( VehicleData( @@ -32,7 +35,7 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() { case None => PlanetSideGUID(0) } ), - unk3 = false, + boostMaxHealth = boosted, health, unk4 = false, no_mount_points = false, @@ -59,7 +62,7 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() { v5 = None, guid = PlanetSideGUID(0) ), - unk3 = false, + boostMaxHealth = boosted, health = 0, unk4 = false, no_mount_points = true, diff --git a/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlLoadVehicle.scala b/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlLoadVehicle.scala index 8e4d07bc1..7bbb1123c 100644 --- a/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlLoadVehicle.scala +++ b/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlLoadVehicle.scala @@ -10,6 +10,7 @@ import net.psforever.objects.zones.Zone import net.psforever.services.Service import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} import net.psforever.types.Vector3 +import net.psforever.zones.Zones import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration._ @@ -44,6 +45,12 @@ class VehicleSpawnControlLoadVehicle(pad: VehicleSpawnPad) extends VehicleSpawnC ) //appear below the trench and doors vehicle.WhichSide = pad.WhichSide 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) val result = ask(pad.Zone.Transport, Zone.Vehicle.Spawn(vehicle)) diff --git a/src/main/scala/net/psforever/objects/serverobject/repair/RepairableEntity.scala b/src/main/scala/net/psforever/objects/serverobject/repair/RepairableEntity.scala index 3efb93c97..232a3c8c5 100644 --- a/src/main/scala/net/psforever/objects/serverobject/repair/RepairableEntity.scala +++ b/src/main/scala/net/psforever/objects/serverobject/repair/RepairableEntity.scala @@ -58,7 +58,7 @@ trait RepairableEntity extends Repairable { */ protected def CanPerformRepairs(target: Repairable.Target, player: Player, item: Tool): Boolean = { 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 && player.isAlive && Vector3.Distance(target.Position, player.Position) < definition.RepairDistance } diff --git a/src/main/scala/net/psforever/objects/zones/Zone.scala b/src/main/scala/net/psforever/objects/zones/Zone.scala index 0b69cc36a..ccbd14a2e 100644 --- a/src/main/scala/net/psforever/objects/zones/Zone.scala +++ b/src/main/scala/net/psforever/objects/zones/Zone.scala @@ -56,7 +56,8 @@ import net.psforever.objects.vital.interaction.{DamageInteraction, DamageResult} import net.psforever.objects.vital.prop.DamageWithPosition import net.psforever.objects.vital.Vitality import net.psforever.objects.zones.blockmap.{BlockMap, SectorPopulation} -import net.psforever.packet.game.PropertyOverrideMessage +import net.psforever.packet.game.EmpireBenefitsMessage.{ZoneBenefits, ZoneLocks} +import net.psforever.packet.game.{EmpireBenefitsMessage, PropertyOverrideMessage} import net.psforever.services.Service 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*/} 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)), PropertyOverrideMessage.GameProperty("purchase_exempt_tr", perks(PlanetSideEmpire.TR)), PropertyOverrideMessage.GameProperty("purchase_exempt_nc", perks(PlanetSideEmpire.NC)))))))) - building.Actor ! BuildingActor.HomeLockBenefits(msg) + building.Actor ! BuildingActor.HomeLockBenefits(overrideMsg) + } + val benefitMsg = BuildEmpireBenefits() + if (benefitMsg.entriesA.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*/} 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)), PropertyOverrideMessage.GameProperty("purchase_exempt_tr", perks(PlanetSideEmpire.TR)), 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.entriesA.nonEmpty) { + PlayerControl.sendResponse(player.Zone, player.Name, benefitMsg) + } + } + + def BuildEmpireBenefits(): EmpireBenefitsMessage = { + val locks = scala.collection.mutable.ArrayBuffer[ZoneLocks]() + val benefits = scala.collection.mutable.ArrayBuffer[ZoneBenefits]() + 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 += ZoneLocks(empire.id, s"lock-${owner.toString.toLowerCase}-homes") + benefits += ZoneBenefits(empire.id, homePerkBenefits(owner)) + } + } + } + + benefitOfZones.foreach { case (zoneNum, benefitId) => + Zones.zones.find(_.Number == zoneNum).foreach { z => + z.benefitRecipient match { + case PlanetSideEmpire.NEUTRAL => + //nothing + case empire => + locks += ZoneLocks(empire.id, s"lock-z$zoneNum") + benefits += ZoneBenefits(empire.id, 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 += ZoneLocks(empire.id, "lock-i1-i2-i3-i4") + benefits += ZoneBenefits(empire.id, islandBenefit) + } + } + EmpireBenefitsMessage(locks.toVector, benefits.toVector) } } diff --git a/src/main/scala/net/psforever/packet/game/objectcreate/VehicleData.scala b/src/main/scala/net/psforever/packet/game/objectcreate/VehicleData.scala index 67d102c91..f6524b324 100644 --- a/src/main/scala/net/psforever/packet/game/objectcreate/VehicleData.scala +++ b/src/main/scala/net/psforever/packet/game/objectcreate/VehicleData.scala @@ -44,7 +44,7 @@ final case class VariantVehicleData(unk: Int) extends SpecificVehicleData(Vehicl * -jammered - vehicles will not be jammered by setting this field
* -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 - * @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 unk4 na * @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( pos: PlacementData, data: CommonFieldData, - unk3: Boolean, + boostMaxHealth: Boolean, health: Int, unk4: Boolean, no_mount_points: Boolean, @@ -106,7 +106,7 @@ object VehicleData extends Marshallable[VehicleData] { cloak: Boolean, inventory: Option[InventoryData] ): 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 ) } @@ -128,7 +128,7 @@ object VehicleData extends Marshallable[VehicleData] { format: UtilityVehicleData, inventory: Option[InventoryData] ): 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 ) } @@ -150,7 +150,7 @@ object VehicleData extends Marshallable[VehicleData] { format: VariantVehicleData, inventory: Option[InventoryData] ): 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 ) }