mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-01-20 02:54:46 +00:00
MAX Capacitors (#297)
* fix isAnchored / isOverdrived faction check * Faction specific MAX definitions * GenericActionMessage documentation * MAX Capacitor functionality and changes to damage resolution for NC MAX shield
This commit is contained in:
parent
d168c40093
commit
28beea4e30
|
|
@ -26,23 +26,26 @@ import scala.collection.mutable
|
|||
import scala.concurrent.duration._
|
||||
|
||||
object GlobalDefinitions {
|
||||
/*
|
||||
characters
|
||||
*/
|
||||
// Characters
|
||||
val avatar = new AvatarDefinition(121)
|
||||
/*
|
||||
exo-suits
|
||||
*/
|
||||
val Standard = ExoSuitDefinition(ExoSuitType.Standard)
|
||||
|
||||
|
||||
val Agile = ExoSuitDefinition(ExoSuitType.Agile)
|
||||
|
||||
|
||||
val Reinforced = ExoSuitDefinition(ExoSuitType.Reinforced)
|
||||
|
||||
|
||||
val Infiltration = ExoSuitDefinition(ExoSuitType.Infiltration)
|
||||
|
||||
val MAX = SpecialExoSuitDefinition(ExoSuitType.MAX)
|
||||
|
||||
val VSMAX = SpecialExoSuitDefinition(ExoSuitType.MAX)
|
||||
|
||||
val TRMAX = SpecialExoSuitDefinition(ExoSuitType.MAX)
|
||||
|
||||
val NCMAX = SpecialExoSuitDefinition(ExoSuitType.MAX)
|
||||
init_exosuit()
|
||||
|
||||
/*
|
||||
Implants
|
||||
*/
|
||||
|
|
@ -1527,7 +1530,7 @@ object GlobalDefinitions {
|
|||
Standard.ResistanceSplash = 15
|
||||
Standard.ResistanceAggravated = 8
|
||||
|
||||
Agile.Name = "lite_armor"
|
||||
Agile.Name = "agile"
|
||||
Agile.MaxArmor = 100
|
||||
Agile.InventoryScale = InventoryTile.Tile99
|
||||
Agile.InventoryOffset = 6
|
||||
|
|
@ -1539,7 +1542,7 @@ object GlobalDefinitions {
|
|||
Agile.ResistanceSplash = 25
|
||||
Agile.ResistanceAggravated = 10
|
||||
|
||||
Reinforced.Name = "med_armor"
|
||||
Reinforced.Name = "reinforced"
|
||||
Reinforced.Permissions = List(CertificationType.ReinforcedExoSuit)
|
||||
Reinforced.MaxArmor = 200
|
||||
Reinforced.InventoryScale = InventoryTile.Tile1209
|
||||
|
|
@ -1561,18 +1564,39 @@ object GlobalDefinitions {
|
|||
Infiltration.Holster(0, EquipmentSize.Pistol)
|
||||
Infiltration.Holster(4, EquipmentSize.Melee)
|
||||
|
||||
MAX.Permissions = List(CertificationType.AIMAX,CertificationType.AVMAX, CertificationType.AAMAX, CertificationType.UniMAX)
|
||||
MAX.MaxArmor = 650
|
||||
MAX.InventoryScale = InventoryTile.Tile1612
|
||||
MAX.InventoryOffset = 6
|
||||
MAX.Holster(0, EquipmentSize.Max)
|
||||
MAX.Holster(4, EquipmentSize.Melee)
|
||||
MAX.Subtract.Damage1 = -2
|
||||
MAX.ResistanceDirectHit = 6
|
||||
MAX.ResistanceSplash = 35
|
||||
MAX.ResistanceAggravated = 10
|
||||
MAX.Damage = StandardMaxDamage
|
||||
MAX.Model = StandardResolutions.Max
|
||||
def CommonMaxConfig(max : SpecialExoSuitDefinition): Unit = {
|
||||
max.Permissions = List(CertificationType.AIMAX,CertificationType.AVMAX, CertificationType.AAMAX, CertificationType.UniMAX)
|
||||
max.MaxArmor = 650
|
||||
max.InventoryScale = InventoryTile.Tile1612
|
||||
max.InventoryOffset = 6
|
||||
max.Holster(0, EquipmentSize.Max)
|
||||
max.Holster(4, EquipmentSize.Melee)
|
||||
max.Subtract.Damage1 = -2
|
||||
max.ResistanceDirectHit = 6
|
||||
max.ResistanceSplash = 35
|
||||
max.ResistanceAggravated = 10
|
||||
max.Damage = StandardMaxDamage
|
||||
max.Model = StandardResolutions.Max
|
||||
}
|
||||
|
||||
CommonMaxConfig(VSMAX)
|
||||
VSMAX.MaxCapacitor = 50
|
||||
VSMAX.CapacitorRechargeDelayMillis = 5000
|
||||
VSMAX.CapacitorRechargePerSecond = 3
|
||||
VSMAX.CapacitorDrainPerSecond = 20
|
||||
|
||||
CommonMaxConfig(TRMAX)
|
||||
TRMAX.MaxCapacitor = 300
|
||||
TRMAX.CapacitorRechargeDelayMillis = 10000
|
||||
TRMAX.CapacitorRechargePerSecond = 10
|
||||
TRMAX.CapacitorDrainPerSecond = 30
|
||||
|
||||
CommonMaxConfig(NCMAX)
|
||||
NCMAX.MaxCapacitor = 400
|
||||
NCMAX.CapacitorRechargeDelayMillis = 10000
|
||||
NCMAX.CapacitorRechargePerSecond = 4
|
||||
NCMAX.CapacitorDrainPerSecond = 4
|
||||
|
||||
}
|
||||
/**
|
||||
* Initialize `AmmoBoxDefinition` globals.
|
||||
|
|
|
|||
|
|
@ -27,6 +27,12 @@ class Player(private val core : Avatar) extends PlanetSideGameObject
|
|||
private var health : Int = 0
|
||||
private var stamina : Int = 0
|
||||
private var armor : Int = 0
|
||||
|
||||
private var capacitor : Float = 0f
|
||||
private var capacitorState : CapacitorStateType.Value = CapacitorStateType.Idle
|
||||
private var capacitorLastUsedMillis : Long = 0
|
||||
private var capacitorLastChargedMillis : Long = 0
|
||||
|
||||
private var maxHealth : Int = 100 //TODO affected by empire benefits, territory benefits, and bops
|
||||
private var maxStamina : Int = 100 //does anything affect this?
|
||||
|
||||
|
|
@ -87,6 +93,7 @@ class Player(private val core : Avatar) extends PlanetSideGameObject
|
|||
Health = MaxHealth
|
||||
Stamina = MaxStamina
|
||||
Armor = MaxArmor
|
||||
Capacitor = 0
|
||||
ResetAllImplants()
|
||||
}
|
||||
isAlive
|
||||
|
|
@ -151,6 +158,44 @@ class Player(private val core : Avatar) extends PlanetSideGameObject
|
|||
|
||||
def MaxArmor : Int = exosuit.MaxArmor
|
||||
|
||||
def Capacitor : Float = capacitor
|
||||
|
||||
def Capacitor_=(value : Float) : Float = {
|
||||
val newValue = math.min(math.max(0, value), ExoSuitDef.MaxCapacitor)
|
||||
|
||||
if(newValue < capacitor) {
|
||||
capacitorLastUsedMillis = System.currentTimeMillis()
|
||||
capacitorLastChargedMillis = 0
|
||||
}
|
||||
else if(newValue > capacitor && newValue < ExoSuitDef.MaxCapacitor) {
|
||||
capacitorLastChargedMillis = System.currentTimeMillis()
|
||||
capacitorLastUsedMillis = 0
|
||||
}
|
||||
else if(newValue > capacitor && newValue == ExoSuitDef.MaxCapacitor) {
|
||||
capacitorLastChargedMillis = 0
|
||||
capacitorLastUsedMillis = 0
|
||||
capacitorState = CapacitorStateType.Idle
|
||||
}
|
||||
|
||||
capacitor = newValue
|
||||
capacitor
|
||||
}
|
||||
|
||||
def CapacitorState : CapacitorStateType.Value = capacitorState
|
||||
def CapacitorState_=(value : CapacitorStateType.Value) : CapacitorStateType.Value = {
|
||||
value match {
|
||||
case CapacitorStateType.Charging => capacitorLastChargedMillis = System.currentTimeMillis()
|
||||
case CapacitorStateType.Discharging => capacitorLastUsedMillis = System.currentTimeMillis()
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
capacitorState = value
|
||||
capacitorState
|
||||
}
|
||||
|
||||
def CapacitorLastUsedMillis = capacitorLastUsedMillis
|
||||
def CapacitorLastChargedMillis = capacitorLastChargedMillis
|
||||
|
||||
def VisibleSlots : Set[Int] = if(exosuit.SuitType == ExoSuitType.MAX) {
|
||||
Set(0)
|
||||
}
|
||||
|
|
@ -290,9 +335,10 @@ class Player(private val core : Avatar) extends PlanetSideGameObject
|
|||
def LastDrawnSlot : Int = lastDrawnSlot
|
||||
|
||||
def ExoSuit : ExoSuitType.Value = exosuit.SuitType
|
||||
def ExoSuitDef : ExoSuitDefinition = exosuit
|
||||
|
||||
def ExoSuit_=(suit : ExoSuitType.Value) : Unit = {
|
||||
val eSuit = ExoSuitDefinition.Select(suit)
|
||||
val eSuit = ExoSuitDefinition.Select(suit, Faction)
|
||||
exosuit = eSuit
|
||||
Player.SuitSetup(this, eSuit)
|
||||
ChangeSpecialAbility()
|
||||
|
|
@ -509,9 +555,9 @@ class Player(private val core : Avatar) extends PlanetSideGameObject
|
|||
SpecialExoSuitDefinition.Mode.Normal
|
||||
}
|
||||
|
||||
def isAnchored : Boolean = ExoSuit == ExoSuitType.MAX && Faction == PlanetSideEmpire.NC && UsingSpecial == SpecialExoSuitDefinition.Mode.Anchored
|
||||
def isAnchored : Boolean = ExoSuit == ExoSuitType.MAX && Faction == PlanetSideEmpire.TR && UsingSpecial == SpecialExoSuitDefinition.Mode.Anchored
|
||||
|
||||
def isOverdrived : Boolean = ExoSuit == ExoSuitType.MAX && Faction == PlanetSideEmpire.NC && UsingSpecial == SpecialExoSuitDefinition.Mode.Overdrive
|
||||
def isOverdrived : Boolean = ExoSuit == ExoSuitType.MAX && Faction == PlanetSideEmpire.TR && UsingSpecial == SpecialExoSuitDefinition.Mode.Overdrive
|
||||
|
||||
def isShielded : Boolean = ExoSuit == ExoSuitType.MAX && Faction == PlanetSideEmpire.NC && UsingSpecial == SpecialExoSuitDefinition.Mode.Shielded
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import net.psforever.objects.equipment.EquipmentSize
|
|||
import net.psforever.objects.inventory.InventoryTile
|
||||
import net.psforever.objects.vital._
|
||||
import net.psforever.objects.vital.resistance.ResistanceProfileMutators
|
||||
import net.psforever.types.{CertificationType, ExoSuitType}
|
||||
import net.psforever.types.{CertificationType, ExoSuitType, PlanetSideEmpire}
|
||||
|
||||
/**
|
||||
* A definition for producing the personal armor the player wears.
|
||||
|
|
@ -21,6 +21,10 @@ class ExoSuitDefinition(private val suitType : ExoSuitType.Value) extends BasicD
|
|||
protected val holsters : Array[EquipmentSize.Value] = Array.fill[EquipmentSize.Value](5)(EquipmentSize.Blocked)
|
||||
protected var inventoryScale : InventoryTile = InventoryTile.Tile11 //override with custom InventoryTile
|
||||
protected var inventoryOffset : Int = 0
|
||||
protected var maxCapacitor : Int = 0
|
||||
protected var capacitorRechargeDelayMillis : Int = 0
|
||||
protected var capacitorRechargePerSecond : Int = 0
|
||||
protected var capacitorDrainPerSecond : Int = 0
|
||||
Name = "exo-suit"
|
||||
Damage = StandardInfantryDamage
|
||||
Resistance = StandardInfantryResistance
|
||||
|
|
@ -35,6 +39,34 @@ class ExoSuitDefinition(private val suitType : ExoSuitType.Value) extends BasicD
|
|||
MaxArmor
|
||||
}
|
||||
|
||||
def MaxCapacitor : Int = maxCapacitor
|
||||
|
||||
def MaxCapacitor_=(value : Int) : Int = {
|
||||
maxCapacitor = value
|
||||
maxCapacitor
|
||||
}
|
||||
|
||||
def CapacitorRechargeDelayMillis : Int = capacitorRechargeDelayMillis
|
||||
|
||||
def CapacitorRechargeDelayMillis_=(value : Int) : Int = {
|
||||
capacitorRechargeDelayMillis = value
|
||||
capacitorRechargeDelayMillis
|
||||
}
|
||||
|
||||
def CapacitorRechargePerSecond : Int = capacitorRechargePerSecond
|
||||
|
||||
def CapacitorRechargePerSecond_=(value : Int) : Int = {
|
||||
capacitorRechargePerSecond = value
|
||||
capacitorRechargePerSecond
|
||||
}
|
||||
|
||||
def CapacitorDrainPerSecond : Int = capacitorDrainPerSecond
|
||||
|
||||
def CapacitorDrainPerSecond_=(value : Int) : Int = {
|
||||
capacitorDrainPerSecond = value
|
||||
capacitorDrainPerSecond
|
||||
}
|
||||
|
||||
def InventoryScale : InventoryTile = inventoryScale
|
||||
|
||||
def InventoryScale_=(scale : InventoryTile) : InventoryTile = {
|
||||
|
|
@ -96,6 +128,10 @@ class SpecialExoSuitDefinition(private val suitType : ExoSuitType.Value) extends
|
|||
val obj = new SpecialExoSuitDefinition(SuitType)
|
||||
obj.Permissions = Permissions
|
||||
obj.MaxArmor = MaxArmor
|
||||
obj.MaxCapacitor = MaxCapacitor
|
||||
obj.CapacitorRechargePerSecond = CapacitorRechargePerSecond
|
||||
obj.CapacitorDrainPerSecond = CapacitorDrainPerSecond
|
||||
obj.CapacitorRechargeDelayMillis = CapacitorRechargeDelayMillis
|
||||
obj.InventoryScale = InventoryScale
|
||||
obj.InventoryOffset = InventoryOffset
|
||||
obj.Subtract.Damage0 = Subtract.Damage0
|
||||
|
|
@ -138,14 +174,19 @@ object ExoSuitDefinition {
|
|||
/**
|
||||
* A function to retrieve the correct defintion of an exo-suit from the type of exo-suit.
|
||||
* @param suit the `Enumeration` corresponding to this exo-suit
|
||||
* @param faction the faction the player belongs to for this exosuit
|
||||
* @return the exo-suit definition
|
||||
*/
|
||||
def Select(suit : ExoSuitType.Value) : ExoSuitDefinition = {
|
||||
def Select(suit : ExoSuitType.Value, faction : PlanetSideEmpire.Value) : ExoSuitDefinition = {
|
||||
suit match {
|
||||
case ExoSuitType.Agile => GlobalDefinitions.Agile.Use
|
||||
case ExoSuitType.Infiltration => GlobalDefinitions.Infiltration.Use
|
||||
case ExoSuitType.MAX => GlobalDefinitions.MAX.Use
|
||||
case ExoSuitType.Agile => GlobalDefinitions.Agile.Use
|
||||
case ExoSuitType.Reinforced => GlobalDefinitions.Reinforced.Use
|
||||
case ExoSuitType.MAX => faction match {
|
||||
case PlanetSideEmpire.TR => GlobalDefinitions.TRMAX.Use
|
||||
case PlanetSideEmpire.NC => GlobalDefinitions.NCMAX.Use
|
||||
case PlanetSideEmpire.VS => GlobalDefinitions.VSMAX.Use
|
||||
}
|
||||
case _ => GlobalDefinitions.Standard.Use
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,13 +106,13 @@ object ResistanceCalculations {
|
|||
//extractors
|
||||
def NoResistExtractor(target : SourceEntry) : Int = 0
|
||||
|
||||
def ExoSuitDirectExtractor(target : PlayerSource) : Int = ExoSuitDefinition.Select(target.ExoSuit).ResistanceDirectHit
|
||||
def ExoSuitDirectExtractor(target : PlayerSource) : Int = ExoSuitDefinition.Select(target.ExoSuit, target.Faction).ResistanceDirectHit
|
||||
|
||||
def ExoSuitSplashExtractor(target : PlayerSource) : Int = ExoSuitDefinition.Select(target.ExoSuit).ResistanceSplash
|
||||
def ExoSuitSplashExtractor(target : PlayerSource) : Int = ExoSuitDefinition.Select(target.ExoSuit, target.Faction).ResistanceSplash
|
||||
|
||||
def ExoSuitAggravatedExtractor(target : PlayerSource) : Int = ExoSuitDefinition.Select(target.ExoSuit).ResistanceAggravated
|
||||
def ExoSuitAggravatedExtractor(target : PlayerSource) : Int = ExoSuitDefinition.Select(target.ExoSuit, target.Faction).ResistanceAggravated
|
||||
|
||||
def ExoSuitRadiationExtractor(target : PlayerSource) : Float = ExoSuitDefinition.Select(target.ExoSuit).RadiationShielding
|
||||
def ExoSuitRadiationExtractor(target : PlayerSource) : Float = ExoSuitDefinition.Select(target.ExoSuit, target.Faction).RadiationShielding
|
||||
|
||||
def VehicleDirectExtractor(target : VehicleSource) : Int = target.Definition.ResistanceDirectHit
|
||||
|
||||
|
|
|
|||
|
|
@ -109,27 +109,53 @@ object ResolutionCalculations {
|
|||
|
||||
def NoApplication(damageValue : Int, data : ResolvedProjectile)(target : Any) : Unit = { }
|
||||
|
||||
def SubtractWithRemainder(current : Int, damage : Int) : (Int, Int) = {
|
||||
val a = Math.max(0, current - damage)
|
||||
val remainingDamage = Math.abs(current - damage - a)
|
||||
|
||||
(a, remainingDamage)
|
||||
}
|
||||
|
||||
/**
|
||||
* The expanded `(Any)=>Unit` function for infantry.
|
||||
* Apply the damage values to the health field and personal armor field for an infantry target.
|
||||
* Apply the damage values to the capacitor (if shielded NC max), health field and personal armor field for an infantry target.
|
||||
* @param damageValues a tuple containing damage values for: health, personal armor
|
||||
* @param data the historical `ResolvedProjectile` information
|
||||
* @param target the `Player` object to be affected by these damage values (at some point)
|
||||
*/
|
||||
def InfantryApplication(damageValues : (Int, Int), data : ResolvedProjectile)(target : Any) : Unit = target match {
|
||||
case player : Player =>
|
||||
val (a, b) = damageValues
|
||||
var (a, b) = damageValues
|
||||
var result = (0, 0)
|
||||
//TODO Personal Shield implant test should go here and modify the values a and b
|
||||
if(player.isAlive && !(a == 0 && b == 0)) {
|
||||
player.History(data)
|
||||
if(player.Armor - b < 0) {
|
||||
player.Health = player.Health - a - (b - player.Armor)
|
||||
player.Armor = 0
|
||||
}
|
||||
else {
|
||||
player.Armor = player.Armor - b
|
||||
player.Health = player.Health - a
|
||||
if(player.Capacitor.toInt > 0 && player.isShielded) {
|
||||
// Subtract armour damage from capacitor
|
||||
result = SubtractWithRemainder(player.Capacitor.toInt, b)
|
||||
player.Capacitor = result._1
|
||||
b = result._2
|
||||
|
||||
// Then follow up with health damage if any capacitor is left
|
||||
result = SubtractWithRemainder(player.Capacitor.toInt, a)
|
||||
player.Capacitor = result._1
|
||||
a = result._2
|
||||
}
|
||||
|
||||
// Subtract any remaining armour damage from armour
|
||||
result = SubtractWithRemainder(player.Armor, b)
|
||||
player.Armor = result._1
|
||||
b = result._2
|
||||
|
||||
// Then bleed through to health if armour ran out
|
||||
result = SubtractWithRemainder(player.Health, b)
|
||||
player.Health = result._1
|
||||
b = result._2
|
||||
|
||||
// Finally, apply health damage to health
|
||||
result = SubtractWithRemainder(player.Health, a)
|
||||
player.Health = result._1
|
||||
a = result._2
|
||||
}
|
||||
case _ =>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,10 +34,15 @@ import scodec.codecs._
|
|||
* 45 - ?<br>
|
||||
* <br>
|
||||
* Actions (when sent from client):<br>
|
||||
* 15 - Max anchor
|
||||
* 16 - Max unanchor
|
||||
* 20 - Client requests MAX special effect (NC shield and TR overdrive. VS jump jets are handled by the jump_thrust boolean on PlayerStateMessageUpstream)
|
||||
* 21 - Disable MAX special effect (NC shield)
|
||||
* 29 - AFK<br>
|
||||
* 30 - back in game<br>
|
||||
* 36 - turn on "Looking for Squad"<br>
|
||||
* 37 - turn off "Looking for Squad"
|
||||
*
|
||||
* @param action what this packet does
|
||||
*/
|
||||
final case class GenericActionMessage(action : Int)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
package net.psforever.types
|
||||
|
||||
object CapacitorStateType extends Enumeration {
|
||||
type Type = Value
|
||||
|
||||
val Idle = Value(0)
|
||||
val Charging = Value(1)
|
||||
val ChargeDelay = Value(2)
|
||||
val Discharging = Value(3)
|
||||
}
|
||||
|
|
@ -223,7 +223,7 @@ class ResolutionCalculationsTests extends Specification {
|
|||
InfantryDamageAfterResist(100,100)(50, 10) mustEqual (40,10)
|
||||
}
|
||||
|
||||
"calculate health and armor damage, with bonus damage, for infantry target" in {
|
||||
"calculate health and armor damage, with bleed through damage, for infantry target" in {
|
||||
//health = 100, armor = 5 -> resist 10 but only have 5, so rollover extra -> damages (40+5, 5)
|
||||
InfantryDamageAfterResist(100,5)(50, 10) mustEqual (45,5)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects
|
||||
|
||||
import net.psforever.objects.GlobalDefinitions
|
||||
import net.psforever.objects.definition.{ExoSuitDefinition, SpecialExoSuitDefinition}
|
||||
import net.psforever.objects.equipment._
|
||||
import net.psforever.objects.inventory.InventoryTile
|
||||
import net.psforever.types.ExoSuitType
|
||||
import net.psforever.types.{ExoSuitType, PlanetSideEmpire}
|
||||
import org.specs2.mutable._
|
||||
|
||||
class ExoSuitTest extends Specification {
|
||||
|
|
@ -127,15 +128,47 @@ class ExoSuitTest extends Specification {
|
|||
|
||||
"ExoSuitDefinition.Select" should {
|
||||
"produce common, shared instances of exo suits" in {
|
||||
ExoSuitDefinition.Select(ExoSuitType.Standard) eq ExoSuitDefinition.Select(ExoSuitType.Standard)
|
||||
ExoSuitDefinition.Select(ExoSuitType.Agile) eq ExoSuitDefinition.Select(ExoSuitType.Agile)
|
||||
ExoSuitDefinition.Select(ExoSuitType.Reinforced) eq ExoSuitDefinition.Select(ExoSuitType.Reinforced)
|
||||
ExoSuitDefinition.Select(ExoSuitType.Infiltration) eq ExoSuitDefinition.Select(ExoSuitType.Infiltration)
|
||||
ExoSuitDefinition.Select(ExoSuitType.Standard, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(ExoSuitType.Standard, PlanetSideEmpire.VS)
|
||||
ExoSuitDefinition.Select(ExoSuitType.Agile, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(ExoSuitType.Agile, PlanetSideEmpire.VS)
|
||||
ExoSuitDefinition.Select(ExoSuitType.Reinforced, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(ExoSuitType.Reinforced, PlanetSideEmpire.VS)
|
||||
ExoSuitDefinition.Select(ExoSuitType.Infiltration, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(ExoSuitType.Infiltration, PlanetSideEmpire.VS)
|
||||
}
|
||||
|
||||
"produce common, shared instances of exo suits across factions" in {
|
||||
ExoSuitDefinition.Select(ExoSuitType.Standard, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(ExoSuitType.Standard, PlanetSideEmpire.TR)
|
||||
ExoSuitDefinition.Select(ExoSuitType.Standard, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(ExoSuitType.Standard, PlanetSideEmpire.NC)
|
||||
|
||||
ExoSuitDefinition.Select(ExoSuitType.Agile, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(ExoSuitType.Agile, PlanetSideEmpire.TR)
|
||||
ExoSuitDefinition.Select(ExoSuitType.Agile, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(ExoSuitType.Agile, PlanetSideEmpire.NC)
|
||||
|
||||
ExoSuitDefinition.Select(ExoSuitType.Reinforced, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(ExoSuitType.Reinforced, PlanetSideEmpire.TR)
|
||||
ExoSuitDefinition.Select(ExoSuitType.Reinforced, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(ExoSuitType.Reinforced, PlanetSideEmpire.NC)
|
||||
|
||||
ExoSuitDefinition.Select(ExoSuitType.Infiltration, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(ExoSuitType.Infiltration, PlanetSideEmpire.TR)
|
||||
ExoSuitDefinition.Select(ExoSuitType.Infiltration, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(ExoSuitType.Infiltration, PlanetSideEmpire.NC)
|
||||
}
|
||||
|
||||
"can select max for TR" in {
|
||||
val obj = ExoSuitDefinition.Select(ExoSuitType.MAX, PlanetSideEmpire.TR)
|
||||
obj.isInstanceOf[SpecialExoSuitDefinition] mustEqual true
|
||||
obj.MaxCapacitor mustEqual 300
|
||||
}
|
||||
|
||||
"can select max for VS" in {
|
||||
val obj = ExoSuitDefinition.Select(ExoSuitType.MAX, PlanetSideEmpire.VS)
|
||||
obj.isInstanceOf[SpecialExoSuitDefinition] mustEqual true
|
||||
obj.MaxCapacitor mustEqual 50
|
||||
}
|
||||
|
||||
"can select max for NC" in {
|
||||
val obj = ExoSuitDefinition.Select(ExoSuitType.MAX, PlanetSideEmpire.NC)
|
||||
obj.isInstanceOf[SpecialExoSuitDefinition] mustEqual true
|
||||
obj.MaxCapacitor mustEqual 400
|
||||
}
|
||||
|
||||
"produces unique instances of the mechanized assault exo suit" in {
|
||||
val obj = ExoSuitDefinition.Select(ExoSuitType.MAX)
|
||||
obj ne ExoSuitDefinition.Select(ExoSuitType.MAX)
|
||||
val obj = ExoSuitDefinition.Select(ExoSuitType.MAX, PlanetSideEmpire.VS)
|
||||
obj ne ExoSuitDefinition.Select(ExoSuitType.MAX, PlanetSideEmpire.VS)
|
||||
obj.isInstanceOf[SpecialExoSuitDefinition] mustEqual true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1269,14 +1269,30 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
if(player.isAlive) {
|
||||
val originalHealth = player.Health
|
||||
val originalArmor = player.Armor
|
||||
val originalCapacitor = player.Capacitor.toInt
|
||||
resolution_function(target)
|
||||
val health = player.Health
|
||||
val armor = player.Armor
|
||||
val capacitor = player.Capacitor.toInt
|
||||
val damageToHealth = originalHealth - health
|
||||
val damageToArmor = originalArmor - armor
|
||||
damageLog.info(s"${player.Name}-infantry: BEFORE=$originalHealth/$originalArmor, AFTER=$health/$armor, CHANGE=$damageToHealth/$damageToArmor")
|
||||
if(damageToHealth != 0 || damageToArmor != 0) {
|
||||
val damageToCapacitor = originalCapacitor - capacitor
|
||||
damageLog.info(s"${player.Name}-infantry: BEFORE=$originalHealth/$originalArmor/$originalCapacitor, AFTER=$health/$armor/$capacitor, CHANGE=$damageToHealth/$damageToArmor/$damageToCapacitor")
|
||||
if(damageToHealth != 0 || damageToArmor != 0 || damageToCapacitor != 0) {
|
||||
val playerGUID = player.GUID
|
||||
if(damageToHealth > 0) {
|
||||
sendResponse(PlanetsideAttributeMessage(playerGUID, 0, health))
|
||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(playerGUID, 0, health))
|
||||
}
|
||||
|
||||
if(damageToArmor > 0) {
|
||||
sendResponse(PlanetsideAttributeMessage(playerGUID, 4, armor))
|
||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(playerGUID, 4, armor))
|
||||
}
|
||||
|
||||
if(damageToCapacitor > 0) {
|
||||
sendResponse(PlanetsideAttributeMessage(playerGUID, 7, capacitor))
|
||||
}
|
||||
sendResponse(PlanetsideAttributeMessage(playerGUID, 0, health))
|
||||
sendResponse(PlanetsideAttributeMessage(playerGUID, 4, armor))
|
||||
continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(playerGUID, 0, health))
|
||||
|
|
@ -2067,7 +2083,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
val fallbackSubtype = 0
|
||||
//a loadout with a prohibited exo-suit type will result in a fallback exo-suit type
|
||||
val (nextSuit : ExoSuitType.Value, nextSubtype : Int) =
|
||||
if(ExoSuitDefinition.Select(exosuit).Permissions match {
|
||||
if(ExoSuitDefinition.Select(exosuit, player.Faction).Permissions match {
|
||||
case Nil =>
|
||||
true
|
||||
case permissions if subtype != 0 =>
|
||||
|
|
@ -2122,7 +2138,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
)
|
||||
}
|
||||
else {
|
||||
val newSuitDef = ExoSuitDefinition.Select(nextSuit)
|
||||
val newSuitDef = ExoSuitDefinition.Select(nextSuit, player.Faction)
|
||||
val (afterInventory, extra) = GridInventory.recoverInventory(
|
||||
inventory.filterNot(dropPred),
|
||||
tplayer.Inventory
|
||||
|
|
@ -3911,6 +3927,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
else {
|
||||
player.Stamina > 0
|
||||
}
|
||||
|
||||
CapacitorTick(jump_thrust)
|
||||
}
|
||||
else {
|
||||
timeDL = 0
|
||||
|
|
@ -5347,7 +5365,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
tool.ToFireMode = convertFireModeIndex
|
||||
sendResponse(ChangeFireModeMessage(tool.GUID, convertFireModeIndex))
|
||||
case _ =>
|
||||
log.info(s"GenericObject: $player is MAX with an unexpected weapon - ${definition.Name}")
|
||||
log.warn(s"GenericObject: $player is MAX with an unexpected weapon - ${definition.Name}")
|
||||
}
|
||||
}
|
||||
else if(action == 16) { //max deployment
|
||||
|
|
@ -5365,7 +5383,25 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
tool.ToFireMode = convertFireModeIndex
|
||||
sendResponse(ChangeFireModeMessage(tool.GUID, convertFireModeIndex))
|
||||
case _ =>
|
||||
log.info(s"GenericObject: $player is MAX with an unexpected weapon - ${definition.Name}")
|
||||
log.warn(s"GenericObject: $player is MAX with an unexpected weapon - ${definition.Name}")
|
||||
}
|
||||
}
|
||||
else if (action == 20) {
|
||||
if(player.ExoSuit == ExoSuitType.MAX) {
|
||||
ToggleMaxSpecialState(enable = true)
|
||||
} else {
|
||||
log.warn("Got GenericActionMessage 20 but can't handle it")
|
||||
}
|
||||
}
|
||||
else if (action == 21) {
|
||||
if(player.ExoSuit == ExoSuitType.MAX) {
|
||||
player.Faction match {
|
||||
case PlanetSideEmpire.NC =>
|
||||
ToggleMaxSpecialState(enable = false)
|
||||
case _ => log.warn(s"Player ${player.Name} tried to cancel an uncancellable MAX special ability")
|
||||
}
|
||||
} else {
|
||||
log.warn("Got GenericActionMessage 21 but can't handle it")
|
||||
}
|
||||
}
|
||||
else if(action == 36) { //Looking For Squad ON
|
||||
|
|
@ -5462,6 +5498,10 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
|
||||
case msg @ WeaponFireMessage(seq_time, weapon_guid, projectile_guid, shot_origin, unk1, unk2, unk3, unk4, unk5, unk6, unk7) =>
|
||||
log.info(s"WeaponFire: $msg")
|
||||
if(player.isShielded) {
|
||||
// Cancel NC MAX shield if it's active
|
||||
ToggleMaxSpecialState(enable = false)
|
||||
}
|
||||
FindContainedWeapon match {
|
||||
case (Some(obj), Some(tool : Tool)) =>
|
||||
if(tool.Magazine <= 0) { //safety: enforce ammunition depletion
|
||||
|
|
@ -7807,6 +7847,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
val player_guid = tplayer.GUID
|
||||
val pos = tplayer.Position
|
||||
val respawnTimer = 300000 //milliseconds
|
||||
ToggleMaxSpecialState(enable = false)
|
||||
tplayer.Die
|
||||
deadState = DeadState.Dead
|
||||
timeDL = 0
|
||||
|
|
@ -10102,6 +10143,75 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
squadUpdateCounter = (squadUpdateCounter + 1) % queuedSquadActions.length
|
||||
}
|
||||
|
||||
def CapacitorTick(jump_thrust : Boolean): Unit = {
|
||||
if(player.ExoSuit == ExoSuitType.MAX) {
|
||||
//Discharge
|
||||
if(jump_thrust || player.isOverdrived || player.isShielded) {
|
||||
if(player.CapacitorState == CapacitorStateType.Discharging) {
|
||||
// Previous tick was already discharging, calculate how much energy to drain from time between the two ticks
|
||||
val timeDiff = (System.currentTimeMillis() - player.CapacitorLastUsedMillis).toFloat / 1000
|
||||
val drainAmount = player.ExoSuitDef.CapacitorDrainPerSecond.toFloat * timeDiff
|
||||
player.Capacitor -= drainAmount
|
||||
sendResponse(PlanetsideAttributeMessage(player.GUID, 7, player.Capacitor.toInt))
|
||||
} else {
|
||||
// Start discharging
|
||||
player.CapacitorState = CapacitorStateType.Discharging
|
||||
}
|
||||
}
|
||||
// Charge
|
||||
else if(player.Capacitor < player.ExoSuitDef.MaxCapacitor
|
||||
&& (player.CapacitorState == CapacitorStateType.Idle || player.CapacitorState == CapacitorStateType.Charging || (player.CapacitorState == CapacitorStateType.ChargeDelay && System.currentTimeMillis() - player.CapacitorLastUsedMillis > player.ExoSuitDef.CapacitorRechargeDelayMillis)))
|
||||
{
|
||||
if(player.CapacitorState == CapacitorStateType.Charging) {
|
||||
val timeDiff = (System.currentTimeMillis() - player.CapacitorLastChargedMillis).toFloat / 1000
|
||||
val chargeAmount = player.ExoSuitDef.CapacitorRechargePerSecond * timeDiff
|
||||
player.Capacitor += chargeAmount
|
||||
sendResponse(PlanetsideAttributeMessage(player.GUID, 7, player.Capacitor.toInt))
|
||||
} else {
|
||||
player.CapacitorState = CapacitorStateType.Charging
|
||||
}
|
||||
}
|
||||
|
||||
if(player.Faction == PlanetSideEmpire.VS) {
|
||||
// Start charge delay for VS when not boosting
|
||||
if(!jump_thrust && player.CapacitorState == CapacitorStateType.Discharging ) {
|
||||
player.CapacitorState = CapacitorStateType.ChargeDelay
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Start charge delay for other factions if capacitor is empty or special ability is off
|
||||
if(player.CapacitorState == CapacitorStateType.Discharging && (player.Capacitor == 0 || (!player.isOverdrived && !player.isShielded))) {
|
||||
player.CapacitorState = CapacitorStateType.ChargeDelay
|
||||
ToggleMaxSpecialState(enable = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(player.CapacitorState != CapacitorStateType.Idle) {
|
||||
player.CapacitorState = CapacitorStateType.Idle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def ToggleMaxSpecialState(enable : Boolean): Unit = {
|
||||
if(player.ExoSuit == ExoSuitType.MAX) {
|
||||
if(enable) {
|
||||
player.Faction match {
|
||||
case PlanetSideEmpire.TR => if(player.Capacitor == player.ExoSuitDef.MaxCapacitor) player.UsingSpecial = SpecialExoSuitDefinition.Mode.Overdrive
|
||||
case PlanetSideEmpire.NC => if(player.Capacitor > 0) player.UsingSpecial = SpecialExoSuitDefinition.Mode.Shielded
|
||||
case _ => log.warn(s"Player ${player.Name} tried to use a MAX special ability but their faction doesn't have one")
|
||||
}
|
||||
|
||||
if(player.UsingSpecial == SpecialExoSuitDefinition.Mode.Overdrive || player.UsingSpecial == SpecialExoSuitDefinition.Mode.Shielded) {
|
||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttributeToAll(player.GUID, 8, 1))
|
||||
}
|
||||
}
|
||||
else {
|
||||
player.UsingSpecial = SpecialExoSuitDefinition.Mode.Normal
|
||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttributeToAll(player.GUID, 8, 0))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The main purpose of this method is to determine which targets will receive "locked on" warnings from remote projectiles.
|
||||
* For a given series of globally unique identifiers, indicating targets,
|
||||
|
|
|
|||
Loading…
Reference in a new issue