mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-01-19 18:14:44 +00:00
Damage Fix, and Stuff (#235)
* redid splash damage radial degrade calculations; lasher damage fixed to 6/0 or 2/4 depending on armor; fixed direct hit distance for weapons that act like slash weapons; gave Falcon a valid projectile * delayed resource silo startup to avoid crash; discovered issue with MAX armor resulting from incorrect manipulation of inventory items during suit transfer * modifications to consider a specific modifier that exists on some vehicles and armored equipment called Subtract, a DamageProfile that reduces damage due to a set flag; manually controlling damage tick marks rather than relying only on HitHint (from client) * Tools now have default firemodes (temporary?); ammo gotten from loadouts is always full; loadouts and exo-suits juggle armor values differently on being changed; log messages for damage to players and vehicles * weapons with one (last) shot need support communicating that one (last) shot * fixing tests * correcting the codec for BindPlayerMessage * changed wording that identifies the damage log entries * switching exosuit no longer causes butterfingers * extending exosuit swap armor value changes to infantry loadout changes * ranges removed from non-vehicle containers * enabled partial damage functionality to facility turrets * BindPlayerMessage replacing BattleplanMessage for purposes of depicting the closest AMS spawn point; specific enums in relation to spawning in BPM and SpawnRequestMessage * rewrote exo-suit switching and loadout switching code, paying extra-special attention for the needs of MAX's * quick amendment for previous commit * switching from mount point check to seat checks in VehicleRemover; started refactoring of Cargo functions before realizing how complicated the full effort would be, so these changes are merely wrapping object identification by GUID * adding a minor server delay to terminal operations
This commit is contained in:
parent
7cec0bb577
commit
4eca226b5b
|
|
@ -85,6 +85,10 @@ class SpecialExoSuitDefinition(private val suitType : ExoSuitType.Value) extends
|
|||
obj.MaxArmor = MaxArmor
|
||||
obj.InventoryScale = InventoryScale
|
||||
obj.InventoryOffset = InventoryOffset
|
||||
obj.Subtract.Damage0 = Subtract.Damage0
|
||||
obj.Subtract.Damage1 = Subtract.Damage1
|
||||
obj.Subtract.Damage2 = Subtract.Damage2
|
||||
obj.Subtract.Damage3 = Subtract.Damage3
|
||||
obj.ResistanceDirectHit = ResistanceDirectHit
|
||||
obj.ResistanceSplash = ResistanceSplash
|
||||
obj.ResistanceAggravated = ResistanceAggravated
|
||||
|
|
@ -166,6 +170,7 @@ object ExoSuitDefinition {
|
|||
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
|
||||
|
|
|
|||
|
|
@ -555,11 +555,19 @@ object GlobalDefinitions {
|
|||
|
||||
val maelstrom = ToolDefinition(ObjectClass.maelstrom)
|
||||
|
||||
val phoenix = ToolDefinition(ObjectClass.phoenix) //decimator
|
||||
val phoenix = new ToolDefinition(ObjectClass.phoenix) {
|
||||
override def NextFireModeIndex(index : Int) : Int = index
|
||||
} //decimator
|
||||
|
||||
val striker = ToolDefinition(ObjectClass.striker)
|
||||
val striker = new ToolDefinition(ObjectClass.striker) {
|
||||
override def NextFireModeIndex(index : Int) : Int = index
|
||||
DefaultFireModeIndex = 1
|
||||
}
|
||||
|
||||
val hunterseeker = ToolDefinition(ObjectClass.hunterseeker) //phoenix
|
||||
val hunterseeker = new ToolDefinition(ObjectClass.hunterseeker) {
|
||||
override def NextFireModeIndex(index : Int) : Int = index
|
||||
DefaultFireModeIndex = 1
|
||||
} //phoenix
|
||||
|
||||
val lancer = ToolDefinition(ObjectClass.lancer)
|
||||
|
||||
|
|
@ -573,7 +581,7 @@ object GlobalDefinitions {
|
|||
|
||||
val bolt_driver = ToolDefinition(ObjectClass.bolt_driver)
|
||||
|
||||
val oicw = ToolDefinition(ObjectClass.oicw) //scorpion
|
||||
val oicw = ToolDefinition(ObjectClass.oicw)
|
||||
|
||||
val flamethrower = ToolDefinition(ObjectClass.flamethrower)
|
||||
|
||||
|
|
@ -718,7 +726,9 @@ object GlobalDefinitions {
|
|||
|
||||
val lightgunship_weapon_system = ToolDefinition(ObjectClass.lightgunship_weapon_system)
|
||||
|
||||
val wasp_weapon_system = ToolDefinition(ObjectClass.wasp_weapon_system)
|
||||
val wasp_weapon_system = new ToolDefinition(ObjectClass.wasp_weapon_system) {
|
||||
override def NextFireModeIndex(index : Int) : Int = index
|
||||
}
|
||||
|
||||
val liberator_weapon_system = ToolDefinition(ObjectClass.liberator_weapon_system)
|
||||
|
||||
|
|
@ -3924,6 +3934,7 @@ object GlobalDefinitions {
|
|||
nchev_falcon.Name = "nchev_falcon"
|
||||
nchev_falcon.Size = EquipmentSize.Max
|
||||
nchev_falcon.AmmoTypes += falcon_ammo
|
||||
nchev_falcon.ProjectileTypes += falcon_projectile
|
||||
nchev_falcon.FireModes += new FireModeDefinition
|
||||
nchev_falcon.FireModes.head.AmmoTypeIndices += 0
|
||||
nchev_falcon.FireModes.head.AmmoSlotIndex = 0
|
||||
|
|
@ -4763,6 +4774,7 @@ object GlobalDefinitions {
|
|||
threemanheavybuggy.TrunkOffset = 30
|
||||
threemanheavybuggy.AutoPilotSpeeds = (22, 8)
|
||||
threemanheavybuggy.DestroyedModel = Some(DestroyedVehicle.ThreeManHeavyBuggy)
|
||||
threemanheavybuggy.Subtract.Damage1 = 5
|
||||
|
||||
twomanheavybuggy.Name = "twomanheavybuggy"
|
||||
twomanheavybuggy.MaxHealth = 1800
|
||||
|
|
@ -4779,6 +4791,7 @@ object GlobalDefinitions {
|
|||
twomanheavybuggy.TrunkOffset = 30
|
||||
twomanheavybuggy.AutoPilotSpeeds = (22, 8)
|
||||
twomanheavybuggy.DestroyedModel = Some(DestroyedVehicle.TwoManHeavyBuggy)
|
||||
twomanheavybuggy.Subtract.Damage1 = 5
|
||||
|
||||
twomanhoverbuggy.Name = "twomanhoverbuggy"
|
||||
twomanhoverbuggy.MaxHealth = 1600
|
||||
|
|
@ -4795,6 +4808,7 @@ object GlobalDefinitions {
|
|||
twomanhoverbuggy.TrunkOffset = 30
|
||||
twomanhoverbuggy.AutoPilotSpeeds = (22, 10)
|
||||
twomanhoverbuggy.DestroyedModel = Some(DestroyedVehicle.TwoManHoverBuggy)
|
||||
twomanhoverbuggy.Subtract.Damage1 = 5
|
||||
|
||||
mediumtransport.Name = "mediumtransport"
|
||||
mediumtransport.MaxHealth = 2500
|
||||
|
|
@ -4818,6 +4832,7 @@ object GlobalDefinitions {
|
|||
mediumtransport.TrunkOffset = 30
|
||||
mediumtransport.AutoPilotSpeeds = (18, 6)
|
||||
mediumtransport.DestroyedModel = Some(DestroyedVehicle.MediumTransport)
|
||||
mediumtransport.Subtract.Damage1 = 7
|
||||
|
||||
battlewagon.Name = "battlewagon"
|
||||
battlewagon.MaxHealth = 2500
|
||||
|
|
@ -4868,6 +4883,7 @@ object GlobalDefinitions {
|
|||
thunderer.TrunkOffset = 30
|
||||
thunderer.AutoPilotSpeeds = (18, 6)
|
||||
thunderer.DestroyedModel = Some(DestroyedVehicle.MediumTransport)
|
||||
thunderer.Subtract.Damage1 = 7
|
||||
|
||||
aurora.Name = "aurora"
|
||||
aurora.MaxHealth = 2500
|
||||
|
|
@ -4891,6 +4907,7 @@ object GlobalDefinitions {
|
|||
aurora.TrunkOffset = 30
|
||||
aurora.AutoPilotSpeeds = (18, 6)
|
||||
aurora.DestroyedModel = Some(DestroyedVehicle.MediumTransport)
|
||||
aurora.Subtract.Damage1 = 7
|
||||
|
||||
apc_tr.Name = "apc_tr"
|
||||
apc_tr.MaxHealth = 6000
|
||||
|
|
@ -5043,6 +5060,7 @@ object GlobalDefinitions {
|
|||
lightning.TrunkOffset = 30
|
||||
lightning.AutoPilotSpeeds = (20, 8)
|
||||
lightning.DestroyedModel = Some(DestroyedVehicle.Lightning)
|
||||
lightning.Subtract.Damage1 = 7
|
||||
|
||||
prowler.Name = "prowler"
|
||||
prowler.MaxHealth = 4800
|
||||
|
|
@ -5062,6 +5080,7 @@ object GlobalDefinitions {
|
|||
prowler.TrunkOffset = 30
|
||||
prowler.AutoPilotSpeeds = (14, 6)
|
||||
prowler.DestroyedModel = Some(DestroyedVehicle.Prowler)
|
||||
prowler.Subtract.Damage1 = 9
|
||||
|
||||
vanguard.Name = "vanguard"
|
||||
vanguard.MaxHealth = 5400
|
||||
|
|
@ -5077,6 +5096,7 @@ object GlobalDefinitions {
|
|||
vanguard.TrunkOffset = 30
|
||||
vanguard.AutoPilotSpeeds = (16, 6)
|
||||
vanguard.DestroyedModel = Some(DestroyedVehicle.Vanguard)
|
||||
vanguard.Subtract.Damage1 = 9
|
||||
|
||||
magrider.Name = "magrider"
|
||||
magrider.MaxHealth = 4200
|
||||
|
|
@ -5094,6 +5114,7 @@ object GlobalDefinitions {
|
|||
magrider.TrunkOffset = 30
|
||||
magrider.AutoPilotSpeeds = (18, 6)
|
||||
magrider.DestroyedModel = Some(DestroyedVehicle.Magrider)
|
||||
magrider.Subtract.Damage1 = 9
|
||||
|
||||
val utilityConverter = new UtilityVehicleConverter
|
||||
ant.Name = "ant"
|
||||
|
|
@ -5110,6 +5131,7 @@ object GlobalDefinitions {
|
|||
ant.MaximumCapacitor = 1500
|
||||
ant.Packet = utilityConverter
|
||||
ant.DestroyedModel = Some(DestroyedVehicle.Ant)
|
||||
ant.Subtract.Damage1 = 5
|
||||
|
||||
ams.Name = "ams"
|
||||
ams.MaxHealth = 3000
|
||||
|
|
@ -5129,6 +5151,7 @@ object GlobalDefinitions {
|
|||
ams.AutoPilotSpeeds = (18, 6)
|
||||
ams.Packet = utilityConverter
|
||||
ams.DestroyedModel = Some(DestroyedVehicle.Ams)
|
||||
ams.Subtract.Damage1 = 10
|
||||
|
||||
val variantConverter = new VariantVehicleConverter
|
||||
router.Name = "router"
|
||||
|
|
@ -5147,6 +5170,7 @@ object GlobalDefinitions {
|
|||
router.AutoPilotSpeeds = (16, 6)
|
||||
router.Packet = variantConverter
|
||||
router.DestroyedModel = Some(DestroyedVehicle.Router)
|
||||
router.Subtract.Damage1 = 5
|
||||
|
||||
switchblade.Name = "switchblade"
|
||||
switchblade.MaxHealth = 1750
|
||||
|
|
@ -5164,6 +5188,8 @@ object GlobalDefinitions {
|
|||
switchblade.AutoPilotSpeeds = (22, 8)
|
||||
switchblade.Packet = variantConverter
|
||||
switchblade.DestroyedModel = Some(DestroyedVehicle.Switchblade)
|
||||
switchblade.Subtract.Damage0 = 5
|
||||
switchblade.Subtract.Damage1 = 5
|
||||
|
||||
flail.Name = "flail"
|
||||
flail.MaxHealth = 2400
|
||||
|
|
@ -5180,6 +5206,7 @@ object GlobalDefinitions {
|
|||
flail.AutoPilotSpeeds = (14, 6)
|
||||
flail.Packet = variantConverter
|
||||
flail.DestroyedModel = Some(DestroyedVehicle.Flail)
|
||||
flail.Subtract.Damage1 = 7
|
||||
|
||||
mosquito.Name = "mosquito"
|
||||
mosquito.MaxHealth = 665
|
||||
|
|
@ -5210,6 +5237,7 @@ object GlobalDefinitions {
|
|||
lightgunship.AutoPilotSpeeds = (0, 4)
|
||||
lightgunship.Packet = variantConverter
|
||||
lightgunship.DestroyedModel = Some(DestroyedVehicle.LightGunship)
|
||||
lightgunship.Subtract.Damage1 = 3
|
||||
|
||||
wasp.Name = "wasp"
|
||||
wasp.MaxHealth = 515
|
||||
|
|
@ -5247,6 +5275,7 @@ object GlobalDefinitions {
|
|||
liberator.AutoPilotSpeeds = (0, 4)
|
||||
liberator.Packet = variantConverter
|
||||
liberator.DestroyedModel = Some(DestroyedVehicle.Liberator)
|
||||
liberator.Subtract.Damage1 = 5
|
||||
|
||||
vulture.Name = "vulture"
|
||||
vulture.MaxHealth = 2500
|
||||
|
|
@ -5269,6 +5298,7 @@ object GlobalDefinitions {
|
|||
vulture.AutoPilotSpeeds = (0, 4)
|
||||
vulture.Packet = variantConverter
|
||||
vulture.DestroyedModel = Some(DestroyedVehicle.Liberator) //add_property vulture destroyedphysics liberator_destroyed
|
||||
vulture.Subtract.Damage1 = 5
|
||||
|
||||
dropship.Name = "dropship"
|
||||
dropship.MaxHealth = 5000
|
||||
|
|
@ -5323,6 +5353,7 @@ object GlobalDefinitions {
|
|||
dropship.AutoPilotSpeeds = (0, 4)
|
||||
dropship.Packet = variantConverter
|
||||
dropship.DestroyedModel = Some(DestroyedVehicle.Dropship)
|
||||
dropship.Subtract.Damage1 = 7
|
||||
|
||||
galaxy_gunship.Name = "galaxy_gunship"
|
||||
galaxy_gunship.MaxHealth = 6000
|
||||
|
|
@ -5354,6 +5385,7 @@ object GlobalDefinitions {
|
|||
galaxy_gunship.AutoPilotSpeeds = (0, 4)
|
||||
galaxy_gunship.Packet = variantConverter
|
||||
galaxy_gunship.DestroyedModel = Some(DestroyedVehicle.Dropship) //the adb calls out a galaxy_gunship_destroyed but no such asset exists
|
||||
galaxy_gunship.Subtract.Damage1 = 7
|
||||
|
||||
lodestar.Name = "lodestar"
|
||||
lodestar.MaxHealth = 5000
|
||||
|
|
@ -5367,6 +5399,7 @@ object GlobalDefinitions {
|
|||
lodestar.AutoPilotSpeeds = (0, 4)
|
||||
lodestar.Packet = variantConverter
|
||||
lodestar.DestroyedModel = Some(DestroyedVehicle.Lodestar)
|
||||
lodestar.Subtract.Damage1 = 7
|
||||
|
||||
phantasm.Name = "phantasm"
|
||||
phantasm.MaxHealth = 2500
|
||||
|
|
|
|||
|
|
@ -281,6 +281,8 @@ class Player(private val core : Avatar) extends PlanetSideGameObject
|
|||
ChangeSpecialAbility()
|
||||
}
|
||||
|
||||
def Subtract = exosuit.Subtract
|
||||
|
||||
def ResistanceDirectHit = exosuit.ResistanceDirectHit
|
||||
|
||||
def ResistanceSplash = exosuit.ResistanceSplash
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import scala.annotation.tailrec
|
|||
class Tool(private val toolDef : ToolDefinition) extends Equipment
|
||||
with FireModeSwitch[FireModeDefinition] {
|
||||
/** index of the current fire mode on the `ToolDefinition`'s list of fire modes */
|
||||
private var fireModeIndex : Int = 0
|
||||
private var fireModeIndex : Int = toolDef.DefaultFireModeIndex
|
||||
/** current ammunition slot being used by this fire mode */
|
||||
private var ammoSlots : List[Tool.FireModeSlot] = List.empty
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package net.psforever.objects.ballistics
|
|||
import net.psforever.objects.TurretDeployable
|
||||
import net.psforever.objects.ce.ComplexDeployable
|
||||
import net.psforever.objects.definition.{BaseDeployableDefinition, ObjectDefinition}
|
||||
import net.psforever.objects.vital.resistance.ResistanceProfile
|
||||
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
||||
|
||||
final case class ComplexDeployableSource(obj_def : ObjectDefinition with BaseDeployableDefinition,
|
||||
|
|
@ -22,6 +23,7 @@ final case class ComplexDeployableSource(obj_def : ObjectDefinition with BaseDep
|
|||
def Position = position
|
||||
def Orientation = orientation
|
||||
def Velocity = None
|
||||
def Modifiers = obj_def.asInstanceOf[ResistanceProfile]
|
||||
}
|
||||
|
||||
object ComplexDeployableSource {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package net.psforever.objects.ballistics
|
|||
import net.psforever.objects.PlanetSideGameObject
|
||||
import net.psforever.objects.ce.Deployable
|
||||
import net.psforever.objects.definition.{BaseDeployableDefinition, ObjectDefinition}
|
||||
import net.psforever.objects.vital.resistance.ResistanceProfile
|
||||
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
||||
|
||||
final case class DeployableSource(obj_def : ObjectDefinition with BaseDeployableDefinition,
|
||||
|
|
@ -20,6 +21,7 @@ final case class DeployableSource(obj_def : ObjectDefinition with BaseDeployable
|
|||
def Position = position
|
||||
def Orientation = orientation
|
||||
def Velocity = None
|
||||
def Modifiers = obj_def.asInstanceOf[ResistanceProfile]
|
||||
}
|
||||
|
||||
object DeployableSource {
|
||||
|
|
|
|||
|
|
@ -3,19 +3,21 @@ package net.psforever.objects.ballistics
|
|||
|
||||
import net.psforever.objects.PlanetSideGameObject
|
||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||
import net.psforever.objects.vital.resistance.ResistanceProfileMutators
|
||||
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
||||
|
||||
final case class ObjectSource(obj : PlanetSideGameObject with FactionAffinity,
|
||||
faction : PlanetSideEmpire.Value,
|
||||
position : Vector3,
|
||||
orientation : Vector3,
|
||||
velocity : Option[Vector3] = None) extends SourceEntry {
|
||||
velocity : Option[Vector3]) extends SourceEntry {
|
||||
override def Name = SourceEntry.NameFormat(obj.Definition.Name)
|
||||
override def Faction = faction
|
||||
def Definition = obj.Definition
|
||||
def Position = position
|
||||
def Orientation = orientation
|
||||
def Velocity = velocity
|
||||
def Modifiers = new ResistanceProfileMutators { }
|
||||
}
|
||||
|
||||
object ObjectSource {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package net.psforever.objects.ballistics
|
|||
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.objects.definition.ObjectDefinition
|
||||
import net.psforever.objects.vital.resistance.ResistanceProfile
|
||||
import net.psforever.types.{ExoSuitType, PlanetSideEmpire, Vector3}
|
||||
|
||||
final case class PlayerSource(name : String,
|
||||
|
|
@ -14,7 +15,8 @@ final case class PlayerSource(name : String,
|
|||
armor : Int,
|
||||
position : Vector3,
|
||||
orientation : Vector3,
|
||||
velocity : Option[Vector3] = None) extends SourceEntry {
|
||||
velocity : Option[Vector3],
|
||||
modifiers : ResistanceProfile) extends SourceEntry {
|
||||
override def Name = name
|
||||
override def Faction = faction
|
||||
def Definition = obj_def
|
||||
|
|
@ -25,11 +27,12 @@ final case class PlayerSource(name : String,
|
|||
def Position = position
|
||||
def Orientation = orientation
|
||||
def Velocity = velocity
|
||||
def Modifiers = modifiers
|
||||
}
|
||||
|
||||
object PlayerSource {
|
||||
def apply(tplayer : Player) : PlayerSource = {
|
||||
PlayerSource(tplayer.Name, tplayer.Definition, tplayer.Faction, tplayer.ExoSuit, tplayer.VehicleSeated.nonEmpty,
|
||||
tplayer.Health, tplayer.Armor, tplayer.Position, tplayer.Orientation, tplayer.Velocity)
|
||||
tplayer.Health, tplayer.Armor, tplayer.Position, tplayer.Orientation, tplayer.Velocity, tplayer.asInstanceOf[ResistanceProfile])
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import net.psforever.objects.definition.ObjectDefinition
|
|||
import net.psforever.objects.{PlanetSideGameObject, Player, TurretDeployable, Vehicle}
|
||||
import net.psforever.objects.entity.WorldEntity
|
||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||
import net.psforever.objects.vital.resistance.ResistanceProfile
|
||||
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
||||
|
||||
trait SourceEntry extends WorldEntity {
|
||||
|
|
@ -16,6 +17,7 @@ trait SourceEntry extends WorldEntity {
|
|||
def Position_=(pos : Vector3) = Position
|
||||
def Orientation_=(pos : Vector3) = Position
|
||||
def Velocity_=(pos : Option[Vector3]) = Velocity
|
||||
def Modifiers : ResistanceProfile
|
||||
}
|
||||
|
||||
object SourceEntry {
|
||||
|
|
@ -24,6 +26,7 @@ object SourceEntry {
|
|||
def Position = Vector3.Zero
|
||||
def Orientation = Vector3.Zero
|
||||
def Velocity = Some(Vector3.Zero)
|
||||
def Modifiers = null
|
||||
}
|
||||
|
||||
def apply(target : PlanetSideGameObject with FactionAffinity) : SourceEntry = {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package net.psforever.objects.ballistics
|
|||
|
||||
import net.psforever.objects.Vehicle
|
||||
import net.psforever.objects.definition.VehicleDefinition
|
||||
import net.psforever.objects.vital.resistance.ResistanceProfile
|
||||
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
||||
|
||||
final case class VehicleSource(obj_def : VehicleDefinition,
|
||||
|
|
@ -11,7 +12,8 @@ final case class VehicleSource(obj_def : VehicleDefinition,
|
|||
shields : Int,
|
||||
position : Vector3,
|
||||
orientation : Vector3,
|
||||
velocity : Option[Vector3] = None) extends SourceEntry {
|
||||
velocity : Option[Vector3],
|
||||
modifiers : ResistanceProfile) extends SourceEntry {
|
||||
override def Name = SourceEntry.NameFormat(obj_def.Name)
|
||||
override def Faction = faction
|
||||
def Definition : VehicleDefinition = obj_def
|
||||
|
|
@ -20,6 +22,7 @@ final case class VehicleSource(obj_def : VehicleDefinition,
|
|||
def Position = position
|
||||
def Orientation = orientation
|
||||
def Velocity = velocity
|
||||
def Modifiers = modifiers
|
||||
}
|
||||
|
||||
object VehicleSource {
|
||||
|
|
@ -31,7 +34,8 @@ object VehicleSource {
|
|||
obj.Shields,
|
||||
obj.Position,
|
||||
obj.Orientation,
|
||||
obj.Velocity
|
||||
obj.Velocity,
|
||||
obj.Definition.asInstanceOf[ResistanceProfile]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,13 @@ import net.psforever.objects.PlanetSideGameObject
|
|||
import net.psforever.objects.ce.{Deployable, DeployableCategory, DeployedItem}
|
||||
import net.psforever.objects.definition.converter.SmallDeployableConverter
|
||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||
import net.psforever.objects.vital.{DamageResistanceModel, NoResistanceSelection, StandardDeployableDamage}
|
||||
import net.psforever.objects.vital.resistance.ResistanceProfileMutators
|
||||
import net.psforever.objects.vital.{DamageResistanceModel, NoResistanceSelection, StandardDeployableDamage, StandardResistanceProfile}
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
trait BaseDeployableDefinition extends DamageResistanceModel {
|
||||
trait BaseDeployableDefinition extends DamageResistanceModel
|
||||
with ResistanceProfileMutators {
|
||||
private var category : DeployableCategory.Value = DeployableCategory.Boomers
|
||||
private var deployTime : Long = (1 second).toMillis //ms
|
||||
private var maxHealth : Int = 1
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
package net.psforever.objects.definition
|
||||
|
||||
import net.psforever.objects.ballistics.Projectiles
|
||||
import net.psforever.objects.vital.DamageType
|
||||
import net.psforever.objects.vital.damage.DamageProfile
|
||||
import net.psforever.objects.vital.{DamageType, StandardDamageProfile}
|
||||
|
||||
/**
|
||||
* The definition that outlines the damage-dealing characteristics of any projectile.
|
||||
|
|
@ -11,13 +10,8 @@ import net.psforever.objects.vital.damage.DamageProfile
|
|||
* @param objectId the object's identifier number
|
||||
*/
|
||||
class ProjectileDefinition(objectId : Int) extends ObjectDefinition(objectId)
|
||||
with DamageProfile {
|
||||
with StandardDamageProfile {
|
||||
private val projectileType : Projectiles.Value = Projectiles(objectId) //let throw NoSuchElementException
|
||||
private var damage0 : Int = 0
|
||||
private var damage1 : Option[Int] = None
|
||||
private var damage2 : Option[Int] = None
|
||||
private var damage3 : Option[Int] = None
|
||||
private var damage4 : Option[Int] = None
|
||||
private var acceleration : Int = 0
|
||||
private var accelerationUntil : Float = 0f
|
||||
private var damageType : DamageType.Value = DamageType.None
|
||||
|
|
@ -45,57 +39,6 @@ class ProjectileDefinition(objectId : Int) extends ObjectDefinition(objectId)
|
|||
UseDamage1Subtract
|
||||
}
|
||||
|
||||
def Damage0 : Int = damage0
|
||||
|
||||
def Damage0_=(damage : Int) : Int = {
|
||||
damage0 = damage
|
||||
damage0
|
||||
}
|
||||
|
||||
def Damage0_=(damage : Option[Int]) : Int = {
|
||||
damage0 = damage match {
|
||||
case Some(value) => value
|
||||
case None => 0 //can not be set to None
|
||||
}
|
||||
Damage0
|
||||
}
|
||||
|
||||
def Damage1 : Int = damage1.getOrElse(Damage0)
|
||||
|
||||
def Damage1_=(damage : Int) : Int = Damage1_=(Some(damage))
|
||||
|
||||
def Damage1_=(damage : Option[Int]) : Int = {
|
||||
this.damage1 = damage
|
||||
Damage1
|
||||
}
|
||||
|
||||
def Damage2 : Int = damage2.getOrElse(Damage1)
|
||||
|
||||
def Damage2_=(damage : Int) : Int = Damage2_=(Some(damage))
|
||||
|
||||
def Damage2_=(damage : Option[Int]) : Int = {
|
||||
this.damage2 = damage
|
||||
Damage2
|
||||
}
|
||||
|
||||
def Damage3 : Int = damage3.getOrElse(Damage2)
|
||||
|
||||
def Damage3_=(damage : Int) : Int = Damage3_=(Some(damage))
|
||||
|
||||
def Damage3_=(damage : Option[Int]) : Int = {
|
||||
this.damage3 = damage
|
||||
Damage3
|
||||
}
|
||||
|
||||
def Damage4 : Int = damage4.getOrElse(Damage3)
|
||||
|
||||
def Damage4_=(damage : Int) : Int = Damage4_=(Some(damage))
|
||||
|
||||
def Damage4_=(damage : Option[Int]) : Int = {
|
||||
this.damage4 = damage
|
||||
Damage4
|
||||
}
|
||||
|
||||
def Acceleration : Int = acceleration
|
||||
|
||||
def Acceleration_=(accel : Int) : Int = {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ class ToolDefinition(objectId : Int) extends EquipmentDefinition(objectId) {
|
|||
private val ammoTypes : mutable.ListBuffer[AmmoBoxDefinition] = new mutable.ListBuffer[AmmoBoxDefinition]
|
||||
private val projectileTypes : mutable.ListBuffer[ProjectileDefinition] = new mutable.ListBuffer[ProjectileDefinition]
|
||||
private val fireModes : mutable.ListBuffer[FireModeDefinition] = new mutable.ListBuffer[FireModeDefinition]
|
||||
private var defaultFireModeIndex : Option[Int] = None
|
||||
Name = "tool"
|
||||
Packet = ToolDefinition.converter
|
||||
|
||||
|
|
@ -20,6 +21,15 @@ class ToolDefinition(objectId : Int) extends EquipmentDefinition(objectId) {
|
|||
def FireModes : mutable.ListBuffer[FireModeDefinition] = fireModes
|
||||
|
||||
def NextFireModeIndex(index : Int) : Int = index + 1
|
||||
|
||||
def DefaultFireModeIndex : Int = defaultFireModeIndex.getOrElse(0)
|
||||
|
||||
def DefaultFireModeIndex_=(index : Int) : Int = DefaultFireModeIndex_=(Some(index))
|
||||
|
||||
def DefaultFireModeIndex_=(index : Option[Int]) : Int = {
|
||||
defaultFireModeIndex = index
|
||||
DefaultFireModeIndex
|
||||
}
|
||||
}
|
||||
|
||||
object ToolDefinition {
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ class VehicleDefinition(objectId : Int) extends ObjectDefinition(objectId)
|
|||
}
|
||||
|
||||
def Seats : mutable.HashMap[Int, SeatDefinition] = seats
|
||||
|
||||
def Cargo : mutable.HashMap[Int, CargoDefinition] = cargo
|
||||
|
||||
def MountPoints : mutable.HashMap[Int, Int] = mountPoints
|
||||
|
|
|
|||
|
|
@ -226,10 +226,12 @@ class GridInventory extends Container {
|
|||
else {
|
||||
val collisions : mutable.Set[InventoryItem] = mutable.Set[InventoryItem]()
|
||||
var curr = actualSlot
|
||||
val fixedItems = items.toMap
|
||||
val fixedGrid = grid.toList
|
||||
for(_ <- 0 until h) {
|
||||
for(col <- 0 until w) {
|
||||
if(grid(curr + col) > -1) {
|
||||
collisions += items(grid(curr + col))
|
||||
if(fixedGrid(curr + col) > -1) {
|
||||
collisions += fixedItems(fixedGrid(curr + col))
|
||||
}
|
||||
}
|
||||
curr += width
|
||||
|
|
|
|||
|
|
@ -71,16 +71,15 @@ object ResourceSilo {
|
|||
}
|
||||
|
||||
/**
|
||||
* Instantiate an configure a `Resource Silo` object
|
||||
* Instantiate and configure a `Resource Silo` object
|
||||
* @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;
|
||||
* not necessary for this object, but required by signature
|
||||
* @return the `Locker` object
|
||||
* @return the `ResourceSilo` object
|
||||
*/
|
||||
def Constructor(id : Int, context : ActorContext) : ResourceSilo = {
|
||||
val obj = ResourceSilo()
|
||||
obj.Actor = context.actorOf(Props(classOf[ResourceSiloControl], obj), s"${obj.Definition.Name}_$id")
|
||||
obj.Actor ! "startup"
|
||||
obj
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ class ResourceSiloControl(resourceSilo : ResourceSilo) extends Actor with Factio
|
|||
sender ! ResourceSilo.ResourceSiloMessage(player, msg, resourceSilo.Use(player, msg))
|
||||
case ResourceSilo.LowNtuWarning(enabled: Boolean) =>
|
||||
resourceSilo.LowNtuWarningOn = enabled
|
||||
log.trace(s"LowNtuWarning: Silo ${resourceSilo.GUID} low ntu warning set to ${enabled}")
|
||||
log.trace(s"LowNtuWarning: Silo ${resourceSilo.GUID} low ntu warning set to $enabled")
|
||||
avatarService ! AvatarServiceMessage(resourceSilo.Owner.asInstanceOf[Building].Zone.Id, AvatarAction.PlanetsideAttribute(PlanetSideGUID(resourceSilo.Owner.asInstanceOf[Building].ModelId), 47, if(resourceSilo.LowNtuWarningOn) 1 else 0))
|
||||
|
||||
case ResourceSilo.UpdateChargeLevel(amount: Int) =>
|
||||
|
|
@ -55,10 +55,10 @@ class ResourceSiloControl(resourceSilo : ResourceSilo) extends Actor with Factio
|
|||
}
|
||||
|
||||
|
||||
val ntuBarLevel = scala.math.round((resourceSilo.ChargeLevel.toFloat / resourceSilo.MaximumCharge.toFloat) * 10).toInt
|
||||
val ntuBarLevel = scala.math.round((resourceSilo.ChargeLevel.toFloat / resourceSilo.MaximumCharge.toFloat) * 10)
|
||||
// Only send updated capacitor display value to all clients if it has actually changed
|
||||
if(resourceSilo.CapacitorDisplay != ntuBarLevel) {
|
||||
log.trace(s"Silo ${resourceSilo.GUID} NTU bar level has changed from ${resourceSilo.CapacitorDisplay} to ${ntuBarLevel}")
|
||||
log.trace(s"Silo ${resourceSilo.GUID} NTU bar level has changed from ${resourceSilo.CapacitorDisplay} to $ntuBarLevel")
|
||||
resourceSilo.CapacitorDisplay = ntuBarLevel
|
||||
resourceSilo.Owner.Actor ! Building.SendMapUpdate(all_clients = true)
|
||||
avatarService ! AvatarServiceMessage(resourceSilo.Owner.asInstanceOf[Building].Zone.Id, AvatarAction.PlanetsideAttribute(resourceSilo.GUID, 45, resourceSilo.CapacitorDisplay))
|
||||
|
|
|
|||
|
|
@ -366,12 +366,12 @@ object EquipmentTerminalDefinition {
|
|||
(0 until tool.MaxAmmoSlot).foreach(index => {
|
||||
val slot = tool.AmmoSlots(index)
|
||||
slot.AmmoTypeIndex += obj.ammo(index).ammoIndex
|
||||
slot.Box = MakeAmmoBox(ammo(index), Some(obj.ammo(index).ammo.capacity))
|
||||
slot.Box = MakeAmmoBox(ammo(index), Some(slot.Definition.Magazine)) //Some(obj.ammo(index).ammo.capacity)
|
||||
})
|
||||
tool
|
||||
|
||||
case obj : ShorthandAmmoBox =>
|
||||
MakeAmmoBox(obj.definition, Some(obj.capacity))
|
||||
MakeAmmoBox(obj.definition) //Some(obj.capacity)
|
||||
|
||||
case obj : ShorthandConstructionItem =>
|
||||
MakeConstructionItem(obj.definition)
|
||||
|
|
|
|||
|
|
@ -3,14 +3,19 @@ package net.psforever.objects.serverobject.turret
|
|||
|
||||
import net.psforever.objects.serverobject.structures.Amenity
|
||||
import net.psforever.types.Vector3
|
||||
import net.psforever.objects.vital.{DamageResistanceModel, StandardResistanceProfile, Vitality}
|
||||
|
||||
class FacilityTurret(tDef : TurretDefinition) extends Amenity
|
||||
with WeaponTurret {
|
||||
with WeaponTurret
|
||||
with Vitality
|
||||
with StandardResistanceProfile {
|
||||
/** some turrets can be updated; they all start without updates */
|
||||
private var upgradePath : TurretUpgrade.Value = TurretUpgrade.None
|
||||
|
||||
WeaponTurret.LoadDefinition(this)
|
||||
|
||||
override def Health_=(toHealth : Int) = super.Health_=(math.max(1, toHealth)) //TODO properly handle destroyed facility turrets
|
||||
|
||||
def MaxHealth : Int = Definition.MaxHealth
|
||||
|
||||
def MountPoints : Map[Int, Int] = Definition.MountPoints.toMap
|
||||
|
|
@ -28,6 +33,8 @@ class FacilityTurret(tDef : TurretDefinition) extends Amenity
|
|||
Upgrade
|
||||
}
|
||||
|
||||
def DamageModel = Definition.asInstanceOf[DamageResistanceModel]
|
||||
|
||||
def Definition : TurretDefinition = tDef
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package net.psforever.objects.serverobject.turret
|
|||
import akka.actor.Actor
|
||||
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
|
||||
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
|
||||
import net.psforever.objects.vital.Vitality
|
||||
|
||||
/**
|
||||
* An `Actor` that handles messages being dispatched to a specific `MannedTurret`.<br>
|
||||
|
|
@ -38,6 +39,18 @@ class FacilityTurretControl(turret : FacilityTurret) extends Actor
|
|||
sender ! Mountable.MountMessages(user, Mountable.CanNotMount(turret, seat_num))
|
||||
}
|
||||
|
||||
case Vitality.Damage(damage_func) =>
|
||||
if(turret.Health > 0) {
|
||||
val originalHealth = turret.Health
|
||||
damage_func(turret)
|
||||
val health = turret.Health
|
||||
val damageToHealth = originalHealth - health
|
||||
val name = turret.Actor.toString
|
||||
val slashPoint = name.lastIndexOf("/")
|
||||
org.log4s.getLogger("DamageResolution").info(s"${name.substring(slashPoint+1, name.length-1)}: BEFORE=$originalHealth, AFTER=$health, CHANGE=$damageToHealth")
|
||||
sender ! Vitality.DamageResolution(turret)
|
||||
}
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ package net.psforever.objects.serverobject.turret
|
|||
|
||||
import net.psforever.objects.definition.{ObjectDefinition, ToolDefinition}
|
||||
import net.psforever.objects.vehicles.Turrets
|
||||
import net.psforever.objects.vital.{DamageResistanceModel, StandardResolutions, StandardVehicleDamage, StandardVehicleResistance}
|
||||
import net.psforever.objects.vital.resistance.ResistanceProfileMutators
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
|
|
@ -10,7 +12,9 @@ import scala.collection.mutable
|
|||
* The definition for any `MannedTurret`.
|
||||
* @param objectId the object's identifier number
|
||||
*/
|
||||
class TurretDefinition(private val objectId : Int) extends ObjectDefinition(objectId) {
|
||||
class TurretDefinition(private val objectId : Int) extends ObjectDefinition(objectId)
|
||||
with ResistanceProfileMutators
|
||||
with DamageResistanceModel {
|
||||
Turrets(objectId) //let throw NoSuchElementException
|
||||
|
||||
private var maxHealth : Int = 100
|
||||
|
|
@ -25,6 +29,9 @@ class TurretDefinition(private val objectId : Int) extends ObjectDefinition(obje
|
|||
/** creates internal ammunition reserves that can not become depleted
|
||||
* see `MannedTurret.TurretAmmoBox` for details */
|
||||
private var hasReserveAmmunition : Boolean = false
|
||||
Damage = StandardVehicleDamage
|
||||
Resistance = StandardVehicleResistance
|
||||
Model = StandardResolutions.FacilityTurrets
|
||||
|
||||
def MaxHealth : Int = maxHealth
|
||||
|
||||
|
|
|
|||
|
|
@ -63,7 +63,16 @@ class VehicleControl(vehicle : Vehicle) extends Actor
|
|||
|
||||
case Vitality.Damage(damage_func) =>
|
||||
if(vehicle.Health > 0) {
|
||||
val originalHealth = vehicle.Health
|
||||
val originalShields = vehicle.Shields
|
||||
damage_func(vehicle)
|
||||
val health = vehicle.Health
|
||||
val shields = vehicle.Shields
|
||||
val damageToHealth = originalHealth - health
|
||||
val damageToShields = originalShields - shields
|
||||
val name = vehicle.Actor.toString
|
||||
val slashPoint = name.lastIndexOf("/")
|
||||
org.log4s.getLogger("DamageResolution").info(s"${name.substring(slashPoint+1, name.length-1)}: BEFORE=$originalHealth/$originalShields, AFTER=$health/$shields, CHANGE=$damageToHealth/$damageToShields")
|
||||
sender ! Vitality.DamageResolution(vehicle)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.vital
|
||||
|
||||
import net.psforever.objects.vital.damage.DamageProfile
|
||||
|
||||
trait StandardDamageProfile extends DamageProfile {
|
||||
private var damage0 : Int = 0
|
||||
private var damage1 : Option[Int] = None
|
||||
private var damage2 : Option[Int] = None
|
||||
private var damage3 : Option[Int] = None
|
||||
private var damage4 : Option[Int] = None
|
||||
|
||||
def Damage0 : Int = damage0
|
||||
|
||||
def Damage0_=(damage : Int) : Int = {
|
||||
damage0 = damage
|
||||
damage0
|
||||
}
|
||||
|
||||
def Damage0_=(damage : Option[Int]) : Int = {
|
||||
damage0 = damage match {
|
||||
case Some(value) => value
|
||||
case None => 0 //can not be set to None
|
||||
}
|
||||
Damage0
|
||||
}
|
||||
|
||||
def Damage1 : Int = damage1.getOrElse(Damage0)
|
||||
|
||||
def Damage1_=(damage : Int) : Int = Damage1_=(Some(damage))
|
||||
|
||||
def Damage1_=(damage : Option[Int]) : Int = {
|
||||
this.damage1 = damage
|
||||
Damage1
|
||||
}
|
||||
|
||||
def Damage2 : Int = damage2.getOrElse(Damage1)
|
||||
|
||||
def Damage2_=(damage : Int) : Int = Damage2_=(Some(damage))
|
||||
|
||||
def Damage2_=(damage : Option[Int]) : Int = {
|
||||
this.damage2 = damage
|
||||
Damage2
|
||||
}
|
||||
|
||||
def Damage3 : Int = damage3.getOrElse(Damage2)
|
||||
|
||||
def Damage3_=(damage : Int) : Int = Damage3_=(Some(damage))
|
||||
|
||||
def Damage3_=(damage : Option[Int]) : Int = {
|
||||
this.damage3 = damage
|
||||
Damage3
|
||||
}
|
||||
|
||||
def Damage4 : Int = damage4.getOrElse(Damage3)
|
||||
|
||||
def Damage4_=(damage : Int) : Int = Damage4_=(Some(damage))
|
||||
|
||||
def Damage4_=(damage : Option[Int]) : Int = {
|
||||
this.damage4 = damage
|
||||
Damage4
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.vital
|
||||
|
||||
import net.psforever.objects.ballistics.ResolvedProjectile
|
||||
import net.psforever.objects.vital.damage._
|
||||
import net.psforever.objects.vital.damage.DamageCalculations._
|
||||
|
||||
|
|
@ -66,21 +65,35 @@ object AircraftSplashDamage extends DamageCalculations(
|
|||
DistanceFromExplosionToTarget
|
||||
)
|
||||
|
||||
object InfantryLashDamage extends NoDamageBase {
|
||||
override def Calculate(data : ResolvedProjectile) : Int = (InfantryHitDamage.Calculate(data) * 0.2f).toInt
|
||||
}
|
||||
object InfantrySplashDamageDirect extends DamageCalculations(
|
||||
SplashDamageWithRadialDegrade,
|
||||
DamageWithModifiers(DamageAgainstAircraft),
|
||||
NoDistance
|
||||
)
|
||||
|
||||
object MaxLashDamage extends NoDamageBase {
|
||||
override def Calculate(data : ResolvedProjectile) : Int = (MaxHitDamage.Calculate(data) * 0.2f).toInt
|
||||
}
|
||||
object InfantryLashDamage extends DamageCalculations(
|
||||
LashDamage,
|
||||
DamageWithModifiers(DamageAgainstExoSuit),
|
||||
DistanceBetweenTargetandSource
|
||||
)
|
||||
|
||||
object VehicleLashDamage extends NoDamageBase {
|
||||
override def Calculate(data : ResolvedProjectile) : Int = (VehicleHitDamage.Calculate(data) * 0.2f).toInt
|
||||
}
|
||||
object MaxLashDamage extends DamageCalculations(
|
||||
LashDamage,
|
||||
DamageWithModifiers(DamageAgainstMaxSuit),
|
||||
DistanceBetweenTargetandSource
|
||||
)
|
||||
|
||||
object AircraftLashDamage extends NoDamageBase {
|
||||
override def Calculate(data : ResolvedProjectile) : Int = (AircraftHitDamage.Calculate(data) * 0.2f).toInt
|
||||
}
|
||||
object VehicleLashDamage extends DamageCalculations(
|
||||
LashDamage,
|
||||
DamageWithModifiers(DamageAgainstVehicle),
|
||||
DistanceBetweenTargetandSource
|
||||
)
|
||||
|
||||
object AircraftLashDamage extends DamageCalculations(
|
||||
LashDamage,
|
||||
DamageWithModifiers(DamageAgainstAircraft),
|
||||
DistanceBetweenTargetandSource
|
||||
)
|
||||
|
||||
object NoDamageSelection extends DamageSelection {
|
||||
def Direct = None
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package net.psforever.objects.vital
|
||||
|
||||
import net.psforever.objects.PlanetSideGameObject
|
||||
import net.psforever.objects.vital.damage.DamageProfile
|
||||
import net.psforever.objects.vital.resistance.ResistanceProfile
|
||||
|
||||
/**
|
||||
|
|
@ -16,6 +17,8 @@ trait StandardResistanceProfile extends ResistanceProfile {
|
|||
assert(Definition.isInstanceOf[ResistanceProfile], s"$this object definition must extend ResistanceProfile")
|
||||
private val resistDef = Definition.asInstanceOf[ResistanceProfile] //cast only once
|
||||
|
||||
def Subtract : DamageProfile = resistDef.Subtract
|
||||
|
||||
def ResistanceDirectHit : Int = resistDef.ResistanceDirectHit
|
||||
|
||||
def ResistanceSplash : Int = resistDef.ResistanceDirectHit
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ object InfantrySplashResistance extends ResistanceCalculations[PlayerSource](
|
|||
|
||||
object InfantryLashResistance extends ResistanceCalculations[PlayerSource](
|
||||
ResistanceCalculations.ValidInfantryTarget,
|
||||
ResistanceCalculations.NoResistExtractor
|
||||
ResistanceCalculations.ExoSuitDirectExtractor
|
||||
)
|
||||
|
||||
object InfantryAggravatedResistance extends ResistanceCalculations[PlayerSource](
|
||||
|
|
|
|||
|
|
@ -23,9 +23,9 @@ object VehicleResolutions extends DamageResistCalculations(
|
|||
ResolutionCalculations.VehicleApplication
|
||||
)
|
||||
|
||||
object SimpleDeployableResolutions extends DamageResistCalculations(
|
||||
object SimpleResolutions extends DamageResistCalculations(
|
||||
ResolutionCalculations.VehicleDamageAfterResist,
|
||||
ResolutionCalculations.SimpleDeployableApplication
|
||||
ResolutionCalculations.SimpleApplication
|
||||
)
|
||||
|
||||
object ComplexDeployableResolutions extends DamageResistCalculations(
|
||||
|
|
@ -38,6 +38,7 @@ object StandardResolutions extends ResolutionSelection {
|
|||
def Max : ResolutionCalculations.Form = MaxResolutions.Calculate
|
||||
def Vehicle : ResolutionCalculations.Form = VehicleResolutions.Calculate
|
||||
def Aircraft : ResolutionCalculations.Form = VehicleResolutions.Calculate
|
||||
def SimpleDeployables : ResolutionCalculations.Form = SimpleDeployableResolutions.Calculate
|
||||
def SimpleDeployables : ResolutionCalculations.Form = SimpleResolutions.Calculate
|
||||
def ComplexDeployables : ResolutionCalculations.Form = ComplexDeployableResolutions.Calculate
|
||||
def FacilityTurrets : ResolutionCalculations.Form = SimpleResolutions.Calculate
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,9 +27,16 @@ abstract class DamageCalculations(damages : DamagesType,
|
|||
*/
|
||||
def Calculate(data : ResolvedProjectile) : Int = {
|
||||
val projectile = data.projectile
|
||||
val profile = projectile.profile
|
||||
val modifiers = if(profile.UseDamage1Subtract) {
|
||||
List(projectile.fire_mode.Modifiers, data.target.Modifiers.Subtract)
|
||||
}
|
||||
else {
|
||||
List(projectile.fire_mode.Modifiers)
|
||||
}
|
||||
damages(
|
||||
projectile,
|
||||
extractor(projectile.profile, List(projectile.fire_mode.Modifiers)),
|
||||
extractor(profile, modifiers),
|
||||
distanceFunc(data)
|
||||
)
|
||||
}
|
||||
|
|
@ -70,6 +77,17 @@ object DamageCalculations {
|
|||
//damage calculation functions
|
||||
def NoDamage(projectile : Projectile, rawDamage : Int, distance : Float) : Int = 0
|
||||
|
||||
/**
|
||||
* Use an unmodified damage value.
|
||||
* @param projectile information about the weapon discharge (itself);
|
||||
* unused
|
||||
* @param rawDamage the accumulated amount of damage
|
||||
* @param distance how far the source was from the target;
|
||||
* unused
|
||||
* @return the rawDamage value
|
||||
*/
|
||||
def SameHit(projectile : Projectile, rawDamage : Int, distance : Float) : Int = rawDamage
|
||||
|
||||
/**
|
||||
* Modify the base damage based on the degrade distance of the projectile type
|
||||
* and its maximum effective distance.
|
||||
|
|
@ -106,8 +124,26 @@ object DamageCalculations {
|
|||
val radius = projectile.profile.DamageRadius
|
||||
if(distance <= radius) {
|
||||
val base : Float = projectile.profile.DamageAtEdge
|
||||
val degrade : Float = (1 - base) * ((radius - distance) / radius) + base
|
||||
rawDamage + (rawDamage * degrade).toInt
|
||||
val degrade : Float = (1 - base) * ((radius - distance)/radius) + base
|
||||
(rawDamage * degrade).toInt
|
||||
}
|
||||
else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a flat lash damage value.
|
||||
* The target needs to be more than five meters away.
|
||||
* @param projectile information about the weapon discharge (itself)
|
||||
* @param rawDamage the accumulated amount of damage
|
||||
* @param distance how far the source was from the target
|
||||
* @return the modified damage value
|
||||
*/
|
||||
def LashDamage(projectile : Projectile, rawDamage : Int, distance : Float) : Int = {
|
||||
val profile = projectile.profile
|
||||
if(distance > 5 || distance <= profile.DistanceMax) {
|
||||
(rawDamage * 0.2f) toInt
|
||||
}
|
||||
else {
|
||||
0
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.vital.resistance
|
||||
|
||||
import net.psforever.objects.vital.DamageType
|
||||
import net.psforever.objects.vital.damage.DamageProfile
|
||||
import net.psforever.objects.vital.{DamageType, StandardDamageProfile}
|
||||
|
||||
/**
|
||||
* The different values for four common methods of modifying incoming damage.
|
||||
|
|
@ -9,6 +10,8 @@ import net.psforever.objects.vital.DamageType
|
|||
* This is for defining pure accessor functions.
|
||||
*/
|
||||
trait ResistanceProfile {
|
||||
def Subtract : DamageProfile
|
||||
|
||||
def ResistanceDirectHit : Int
|
||||
|
||||
def ResistanceSplash : Int
|
||||
|
|
@ -34,11 +37,25 @@ trait ResistanceProfile {
|
|||
* This is for defining both accessor and mutator functions.
|
||||
*/
|
||||
trait ResistanceProfileMutators extends ResistanceProfile {
|
||||
private var subtract : DamageProfile = new StandardDamageProfile {
|
||||
//subtract numbers are always negative modifiers
|
||||
override def Damage0_=(damage : Int) : Int = super.Damage0_=( if(damage < 1) damage else -damage)
|
||||
|
||||
override def Damage1_=(damage : Int) : Int = super.Damage1_=( if(damage < 1) damage else -damage)
|
||||
|
||||
override def Damage2_=(damage : Int) : Int = super.Damage2_=( if(damage < 1) damage else -damage)
|
||||
|
||||
override def Damage3_=(damage : Int) : Int = super.Damage3_=( if(damage < 1) damage else -damage)
|
||||
|
||||
override def Damage4_=(damage : Int) : Int = super.Damage4_=( if(damage < 1) damage else -damage)
|
||||
}
|
||||
private var resistanceDirectHit : Int = 0
|
||||
private var resistanceSplash : Int = 0
|
||||
private var resistanceAggravated : Int = 0
|
||||
private var radiationShielding : Float = 0f
|
||||
|
||||
def Subtract : DamageProfile = subtract
|
||||
|
||||
def ResistanceDirectHit : Int = resistanceDirectHit
|
||||
|
||||
def ResistanceDirectHit_=(resist : Int) : Int = {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package net.psforever.objects.vital.resolution
|
|||
import net.psforever.objects.{Player, TurretDeployable, Vehicle}
|
||||
import net.psforever.objects.ballistics.{PlayerSource, ResolvedProjectile}
|
||||
import net.psforever.objects.ce.{ComplexDeployable, SimpleDeployable}
|
||||
import net.psforever.objects.serverobject.turret.FacilityTurret
|
||||
import net.psforever.objects.vital.projectile.ProjectileCalculations
|
||||
|
||||
/**
|
||||
|
|
@ -159,12 +160,17 @@ object ResolutionCalculations {
|
|||
case _ => ;
|
||||
}
|
||||
|
||||
def SimpleDeployableApplication(damage : Int, data : ResolvedProjectile)(target : Any) : Unit = target match {
|
||||
def SimpleApplication(damage : Int, data : ResolvedProjectile)(target : Any) : Unit = target match {
|
||||
case ce : SimpleDeployable =>
|
||||
if(ce.Health > 0) {
|
||||
ce.Health -= damage
|
||||
ce.History(data)
|
||||
}
|
||||
case turret : FacilityTurret =>
|
||||
if(turret.Health > 0) {
|
||||
turret.Health -= damage
|
||||
turret.History(data)
|
||||
}
|
||||
case _ =>
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import net.psforever.objects.guid.actor.UniqueNumberSystem
|
|||
import net.psforever.objects.guid.selector.RandomSelector
|
||||
import net.psforever.objects.guid.source.LimitedNumberSource
|
||||
import net.psforever.objects.inventory.Container
|
||||
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
|
||||
import net.psforever.objects.serverobject.structures.{Amenity, Building}
|
||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||
import net.psforever.objects.serverobject.turret.FacilityTurret
|
||||
|
|
@ -358,6 +359,13 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
|||
case (None, _) | (_, None) => ; //let ZoneActor's sanity check catch this error
|
||||
}
|
||||
})
|
||||
//ntu management (eventually move to a generic building startup function)
|
||||
buildings.values
|
||||
.flatMap(_.Amenities.filter(_.Definition == GlobalDefinitions.resource_silo))
|
||||
.collect {
|
||||
case silo : ResourceSilo =>
|
||||
silo.Actor ! "startup"
|
||||
}
|
||||
}
|
||||
|
||||
private def CreateSpawnGroups() : Unit = {
|
||||
|
|
|
|||
|
|
@ -2,33 +2,45 @@
|
|||
package net.psforever.packet.game
|
||||
|
||||
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
||||
import net.psforever.types.Vector3
|
||||
import net.psforever.types.{SpawnGroup, Vector3}
|
||||
import scodec.Codec
|
||||
import scodec.codecs._
|
||||
|
||||
/**
|
||||
* The purpose of the `BindPlayerMessage` packet.<br>
|
||||
* <br>
|
||||
* `Bind` and `Unbind` are generally manual actions performed by the player.
|
||||
* `Available` is applied to automatic Advanced Mobile Spawn points and other "Bound" points at the time of redeployment.
|
||||
* `Lost` and `Unavailable` remove the status of being bound and have slightly different connotations.
|
||||
* Each generates a different a events chat message if logging it turned on.
|
||||
*/
|
||||
object BindStatus extends Enumeration(1) {
|
||||
type Type = Value
|
||||
|
||||
val
|
||||
Bind,
|
||||
Unbind,
|
||||
Lost,
|
||||
Available,
|
||||
Unavailable
|
||||
= Value
|
||||
|
||||
implicit val codec = PacketHelpers.createEnumerationCodec(this, uint8)
|
||||
}
|
||||
|
||||
/**
|
||||
* A packet dispatched to maintain a manually-set respawn location.<br>
|
||||
* <br>
|
||||
* The packet establishes the player's ability to spawn in an arbitrary location that is not a normal local option.
|
||||
* This process is called "binding."
|
||||
* This process is called "binding one's matrix."
|
||||
* In addition to player establishing the binding, the packet updates as conditions of the respawn location changes.<br>
|
||||
* <br>
|
||||
* If `logging` is turned on, packets will display different messages depending on context.
|
||||
* The bind descriptor will be used to flavor the events chat message.
|
||||
* As long as the event is marked to be logged, when the packet is received, a message is displayed in the events window.
|
||||
* If the logged action is applicable, the matrixing sound effect will be played too.
|
||||
* Not displaying events is occasionally warranted for aesthetics.
|
||||
* The game will always note if this is your first time binding.<br>
|
||||
* <br>
|
||||
* One common occurrence of this packet is during zone transport.
|
||||
* Specifically, a packet is dispatched after unloading the current zone but before beginning loading in the new zone.
|
||||
* It is preceded by all of the `ObjectDeleteMessage` packets and itself precedes the `LoadMapMessage` packet.<br>
|
||||
* <br>
|
||||
* Actions:<br>
|
||||
* `1` - bound to respawn point<br>
|
||||
* `2` - general unbound / unbinding from respawn point<br>
|
||||
* `3` - respawn point lost<br>
|
||||
* `4` - bound spawn point became available<br>
|
||||
* `5` - bound spawn point became unavailable (different from 3)<br>
|
||||
* The game will always note if this is your first time binding regardless of the state of this flag.<br>
|
||||
* <br>
|
||||
* Bind Descriptors:<br>
|
||||
* `@amp_station`<br>
|
||||
|
|
@ -41,22 +53,28 @@ import scodec.codecs._
|
|||
* Exploration:<br>
|
||||
* Find other bind descriptors.
|
||||
* @param action the purpose of the packet
|
||||
* @param bindDesc a description of the respawn binding point
|
||||
* @param unk1 na; usually set `true` if there is more data in the packet ...
|
||||
* @param bind_desc a text description of the respawn binding point
|
||||
* @param unk1 na;
|
||||
* usually set `true` if there is more data in the packet ...
|
||||
* @param logging true, to report on bind point change visible in the events window;
|
||||
* false, to render spawn change silent;
|
||||
* a first time event notification will always show
|
||||
* @param unk2 na; if a value, it is usually 40 (hex`28`)
|
||||
* @param unk3 na
|
||||
* some first time notifications will always display regardless of this flag
|
||||
* @param spawn_group the kind of spawn request that will be made;
|
||||
* affects the type of icon displayed;
|
||||
* will coincide with the value of `unk2` in `SpawnRequestMessage` when the spawn option is selected
|
||||
* @param zone_number the number of the zone in which to display this spawn option;
|
||||
* if `zone_number` is not the current zone, and the action is positive,
|
||||
* a small map of the alternate zone with selectable spawn point will become visible
|
||||
* @param unk4 na
|
||||
* @param pos a position associated with the binding
|
||||
* @param pos coordinates for any displayed deployment map icon;
|
||||
* `x` and `y` determine the position
|
||||
*/
|
||||
final case class BindPlayerMessage(action : Int,
|
||||
bindDesc : String,
|
||||
final case class BindPlayerMessage(action : BindStatus.Value,
|
||||
bind_desc : String,
|
||||
unk1 : Boolean,
|
||||
logging : Boolean,
|
||||
unk2 : Int,
|
||||
unk3 : Long,
|
||||
spawn_group : SpawnGroup.Value,
|
||||
zone_number : Long,
|
||||
unk4 : Long,
|
||||
pos : Vector3)
|
||||
extends PlanetSideGamePacket {
|
||||
|
|
@ -68,20 +86,18 @@ final case class BindPlayerMessage(action : Int,
|
|||
object BindPlayerMessage extends Marshallable[BindPlayerMessage] {
|
||||
/**
|
||||
* A common variant of this packet.
|
||||
* `16028004000000000000000000000000000000`
|
||||
*/
|
||||
val STANDARD = BindPlayerMessage(2, "", false, false, 2, 0, 0, Vector3(0, 0, 0))
|
||||
val Standard = BindPlayerMessage(BindStatus.Unbind, "", false, false, SpawnGroup.BoundAMS, 0, 0, Vector3.Zero)
|
||||
|
||||
private val spawnGroupCodec = PacketHelpers.createEnumerationCodec(SpawnGroup, uint4)
|
||||
|
||||
//TODO: there are two ignore(1) in this packet; are they in a good position?
|
||||
implicit val codec : Codec[BindPlayerMessage] = (
|
||||
("action" | uint8L) ::
|
||||
("bindDesc" | PacketHelpers.encodedString) ::
|
||||
("action" | BindStatus.codec) ::
|
||||
("bind_desc" | PacketHelpers.encodedString) ::
|
||||
("unk1" | bool) ::
|
||||
("logging" | bool) ::
|
||||
ignore(1) ::
|
||||
("unk2" | uint4L) ::
|
||||
ignore(1) ::
|
||||
("unk3" | uint32L) ::
|
||||
("spawn_group" | spawnGroupCodec) ::
|
||||
("zone_number" | uint32L) ::
|
||||
("unk4" | uint32L) ::
|
||||
("pos" | Vector3.codec_pos)
|
||||
).as[BindPlayerMessage]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.packet.game
|
||||
|
||||
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
|
||||
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
||||
import net.psforever.types.SpawnGroup
|
||||
import scodec.Codec
|
||||
import scodec.codecs._
|
||||
|
||||
|
|
@ -9,20 +10,16 @@ import scodec.codecs._
|
|||
* na
|
||||
* @param unk1 when defined, na;
|
||||
* non-zero when selecting the sanctuary option from a non-sanctuary continent deployment map
|
||||
* @param unk2 when defined, indicates type of spawn point by destination;
|
||||
* 0 is nothing;
|
||||
* 2 is ams;
|
||||
* 6 is towers;
|
||||
* 7 is facilities
|
||||
* @param spawn_type the type of spawn point destination
|
||||
* @param unk3 na
|
||||
* @param unk4 na
|
||||
* @param unk5 when defined, the continent number
|
||||
* @param zone_number when defined, the continent number
|
||||
*/
|
||||
final case class SpawnRequestMessage(unk1 : Int,
|
||||
unk2 : Long,
|
||||
spawn_type : SpawnGroup.Value,
|
||||
unk3 : Int,
|
||||
unk4 : Int,
|
||||
unk5 : Int)
|
||||
zone_number : Int)
|
||||
extends PlanetSideGamePacket {
|
||||
type Packet = SpawnRequestMessage
|
||||
def opcode = GamePacketOpcode.SpawnRequestMessage
|
||||
|
|
@ -30,11 +27,13 @@ final case class SpawnRequestMessage(unk1 : Int,
|
|||
}
|
||||
|
||||
object SpawnRequestMessage extends Marshallable[SpawnRequestMessage] {
|
||||
private val spawnGroupCodec = PacketHelpers.createLongEnumerationCodec(SpawnGroup, uint32L)
|
||||
|
||||
implicit val codec : Codec[SpawnRequestMessage] = (
|
||||
("unk1" | uint16L) ::
|
||||
("unk2" | uint32L) ::
|
||||
("spawn_type" | spawnGroupCodec) ::
|
||||
("unk3" | uint16L) ::
|
||||
("unk4" | uint16L) ::
|
||||
("unk5" | uintL(10))
|
||||
("zone_number" | uintL(10))
|
||||
).as[SpawnRequestMessage]
|
||||
}
|
||||
|
|
|
|||
39
common/src/main/scala/net/psforever/types/SpawnGroup.scala
Normal file
39
common/src/main/scala/net/psforever/types/SpawnGroup.scala
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.types
|
||||
|
||||
/**
|
||||
* The spawn group.<br>
|
||||
* <br>
|
||||
* The groups `Sanctuary`, `Tower`, and ,`Facility` are typically hard-defined by the client.
|
||||
* The groups `AMS` and the `Bound*` spawns can only be displayed on the deployment map
|
||||
* by sending a manual `BindPlayerMessage` packet to the client,
|
||||
* and the designated spawn group identifier is returned to the server if the spawn point that is created is selected.
|
||||
* The sanctuary spawn is also used as a fallback for an unknown spawn point
|
||||
* as going back to one's own sanctuary counts as a "safe spawn."<br>
|
||||
* <br>
|
||||
* The `Sanctuary` spawn is commonly accessible on a smaller map (of the sanctuary continent)
|
||||
* off to one side of the greater deployment map.
|
||||
* It does not generate an icon when manually set.
|
||||
* The icons produced by the normal and the bound tower and facility groups are not detailed.
|
||||
* The ones that are not designated as "bound" also do not display icons when manually set.
|
||||
* The AMS spawn group icons have an overhead AMS glyph and are smaller in radius, identical otherwise.
|
||||
*/
|
||||
object SpawnGroup extends Enumeration {
|
||||
type Type = Value
|
||||
|
||||
val
|
||||
Sanctuary,
|
||||
BoundAMS,
|
||||
AMS,
|
||||
Unknown3,
|
||||
BoundTower, //unused?
|
||||
BoundFacility,
|
||||
Tower,
|
||||
Facility,
|
||||
Unknown8,
|
||||
Unknown9,
|
||||
Unknown10,
|
||||
Unknown11,
|
||||
Unknown12
|
||||
= Value
|
||||
}
|
||||
|
|
@ -198,7 +198,7 @@ class VehicleService extends Actor {
|
|||
import net.psforever.objects.vehicles.UtilityType
|
||||
import net.psforever.objects.GlobalDefinitions
|
||||
zone.Vehicles
|
||||
.filter(veh => veh.Definition == GlobalDefinitions.ams && veh.DeploymentState == DriveState.Deployed)
|
||||
.filter(veh => veh.Health > 0 && veh.Definition == GlobalDefinitions.ams && veh.DeploymentState == DriveState.Deployed)
|
||||
.flatMap(veh => veh.Utilities.values.filter(util => util.UtilType == UtilityType.ams_respawn_tube) )
|
||||
.map(util => util().asInstanceOf[SpawnTube])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,8 +27,7 @@ class VehicleRemover extends RemoverActor {
|
|||
val zoneId = entry.zone.Id
|
||||
vehicle.Actor ! Vehicle.PrepareForDeletion
|
||||
//kick out all passengers
|
||||
vehicle.Definition.MountPoints.values.foreach(mount => {
|
||||
val seat = vehicle.Seat(mount).get
|
||||
vehicle.Seats.values.foreach(seat => {
|
||||
seat.Occupant match {
|
||||
case Some(tplayer) =>
|
||||
seat.Occupant = None
|
||||
|
|
|
|||
|
|
@ -4,27 +4,42 @@ package game
|
|||
import org.specs2.mutable._
|
||||
import net.psforever.packet._
|
||||
import net.psforever.packet.game._
|
||||
import net.psforever.types.Vector3
|
||||
import net.psforever.types.{SpawnGroup, Vector3}
|
||||
import scodec.bits._
|
||||
|
||||
class BindPlayerMessageTest extends Specification {
|
||||
val string_standard = hex"16028004000000000000000000000000000000"
|
||||
val string_ams = hex"16 05 8440616D73 08 28000000 00000000 00000 00000 0000"
|
||||
val string_tech = hex"16 01 8b40746563685f706c616e74 d4 28000000 38000000 00064 012b1 a044"
|
||||
val string_akkan = hex"16048440616d7388100000001400000214e171a8e33024"
|
||||
|
||||
"decode (standard)" in {
|
||||
PacketCoding.DecodePacket(string_standard).require match {
|
||||
case BindPlayerMessage(action, bindDesc, unk1, logging, unk2, unk3, unk4, pos) =>
|
||||
action mustEqual BindStatus.Unbind
|
||||
bindDesc mustEqual ""
|
||||
unk1 mustEqual false
|
||||
logging mustEqual false
|
||||
unk2 mustEqual SpawnGroup.BoundAMS
|
||||
unk3 mustEqual 0
|
||||
unk4 mustEqual 0
|
||||
pos mustEqual Vector3.Zero
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"decode (ams)" in {
|
||||
PacketCoding.DecodePacket(string_ams).require match {
|
||||
case BindPlayerMessage(action, bindDesc, unk1, logging, unk2, unk3, unk4, pos) =>
|
||||
action mustEqual 5
|
||||
bindDesc.length mustEqual 4
|
||||
action mustEqual BindStatus.Unavailable
|
||||
bindDesc mustEqual "@ams"
|
||||
unk1 mustEqual false
|
||||
logging mustEqual false
|
||||
unk2 mustEqual 4
|
||||
unk3 mustEqual 40
|
||||
unk2 mustEqual SpawnGroup.AMS
|
||||
unk3 mustEqual 10
|
||||
unk4 mustEqual 0
|
||||
pos.x mustEqual 0f
|
||||
pos.y mustEqual 0f
|
||||
pos.z mustEqual 0f
|
||||
pos mustEqual Vector3.Zero
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
|
|
@ -33,40 +48,60 @@ class BindPlayerMessageTest extends Specification {
|
|||
"decode (tech)" in {
|
||||
PacketCoding.DecodePacket(string_tech).require match {
|
||||
case BindPlayerMessage(action, bindDesc, unk1, logging, unk2, unk3, unk4, pos) =>
|
||||
action mustEqual 1
|
||||
bindDesc.length mustEqual 11
|
||||
action mustEqual BindStatus.Bind
|
||||
bindDesc mustEqual "@tech_plant"
|
||||
unk1 mustEqual true
|
||||
logging mustEqual true
|
||||
unk2 mustEqual 10
|
||||
unk3 mustEqual 40
|
||||
unk4 mustEqual 56
|
||||
pos.x mustEqual 2060.0f
|
||||
pos.y mustEqual 598.0078f
|
||||
pos.z mustEqual 274.5f
|
||||
unk2 mustEqual SpawnGroup.BoundFacility
|
||||
unk3 mustEqual 10
|
||||
unk4 mustEqual 14
|
||||
pos mustEqual Vector3(4610.0f, 6292, 69.625f)
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"decode (akkan)" in {
|
||||
PacketCoding.DecodePacket(string_akkan).require match {
|
||||
case BindPlayerMessage(action, bindDesc, unk1, logging, unk2, unk3, unk4, pos) =>
|
||||
action mustEqual BindStatus.Available
|
||||
bindDesc mustEqual "@ams"
|
||||
unk1 mustEqual true
|
||||
logging mustEqual false
|
||||
unk2 mustEqual SpawnGroup.AMS
|
||||
unk3 mustEqual 4
|
||||
unk4 mustEqual 5
|
||||
pos mustEqual Vector3(2673.039f, 4423.547f, 39.1875f)
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"encode (standard)" in {
|
||||
val msg = BindPlayerMessage.Standard
|
||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||
|
||||
pkt mustEqual string_standard
|
||||
}
|
||||
|
||||
"encode (ams)" in {
|
||||
val msg = BindPlayerMessage(5, "@ams", false, false, 4, 40, 0, Vector3(0, 0, 0))
|
||||
val msg = BindPlayerMessage(BindStatus.Unavailable, "@ams", false, false, SpawnGroup.AMS, 10, 0, Vector3.Zero)
|
||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||
|
||||
pkt mustEqual string_ams
|
||||
}
|
||||
|
||||
"encode (tech)" in {
|
||||
val msg = BindPlayerMessage(1, "@tech_plant", true, true, 10, 40, 56, Vector3(2060.0f, 598.0078f, 274.5f))
|
||||
val msg = BindPlayerMessage(BindStatus.Bind, "@tech_plant", true, true, SpawnGroup.BoundFacility, 10, 14, Vector3(4610.0f, 6292, 69.625f))
|
||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||
|
||||
pkt mustEqual string_tech
|
||||
}
|
||||
|
||||
"standard" in {
|
||||
val msg = BindPlayerMessage.STANDARD
|
||||
"encode (akkan)" in {
|
||||
val msg = BindPlayerMessage(BindStatus.Available, "@ams", true, false, SpawnGroup.AMS, 4, 5, Vector3(2673.039f, 4423.547f, 39.1875f))
|
||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||
|
||||
pkt mustEqual hex"16028004000000000000000000000000000000"
|
||||
pkt mustEqual string_akkan
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package game
|
|||
import org.specs2.mutable._
|
||||
import net.psforever.packet._
|
||||
import net.psforever.packet.game._
|
||||
import net.psforever.types.SpawnGroup
|
||||
import scodec.bits._
|
||||
|
||||
class SpawnRequestMessageTest extends Specification {
|
||||
|
|
@ -13,7 +14,7 @@ class SpawnRequestMessageTest extends Specification {
|
|||
PacketCoding.DecodePacket(string).require match {
|
||||
case SpawnRequestMessage(unk1,unk2,unk3,unk4,unk5) =>
|
||||
unk1 mustEqual 0
|
||||
unk2 mustEqual 7
|
||||
unk2 mustEqual SpawnGroup.Facility
|
||||
unk3 mustEqual 0
|
||||
unk4 mustEqual 0
|
||||
unk5 mustEqual 2
|
||||
|
|
@ -23,7 +24,7 @@ class SpawnRequestMessageTest extends Specification {
|
|||
}
|
||||
|
||||
"encode" in {
|
||||
val msg = SpawnRequestMessage(0, 7, 0, 0, 2)
|
||||
val msg = SpawnRequestMessage(0, SpawnGroup.Facility, 0, 0, 2)
|
||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||
|
||||
pkt mustEqual string
|
||||
|
|
|
|||
|
|
@ -106,12 +106,12 @@ class DamageCalculationsTests extends Specification {
|
|||
|
||||
"calculate splash damage from components (near)" in {
|
||||
val result = DamageWithModifiers(DamageAgainstVehicle)(proj_prof, List(wep_prof))
|
||||
SplashDamageWithRadialDegrade(projectile, result, 0) mustEqual 264
|
||||
SplashDamageWithRadialDegrade(projectile, result, 0) mustEqual 132
|
||||
}
|
||||
|
||||
"calculate splash damage from components (medium)" in {
|
||||
val result = DamageWithModifiers(DamageAgainstVehicle)(proj_prof, List(wep_prof))
|
||||
SplashDamageWithRadialDegrade(projectile, result, 5) mustEqual 145
|
||||
SplashDamageWithRadialDegrade(projectile, result, 5) mustEqual 13
|
||||
}
|
||||
|
||||
"calculate splash damage from components (far)" in {
|
||||
|
|
@ -341,7 +341,7 @@ class DamageModelTests extends Specification {
|
|||
val func : (Any)=>Unit = resprojectile.damage_model.Calculate(resprojectile, ProjectileResolution.Splash)
|
||||
|
||||
func(tplayer)
|
||||
tplayer.Health mustEqual 81
|
||||
tplayer.Health mustEqual 98
|
||||
tplayer.Armor mustEqual 35
|
||||
}
|
||||
|
||||
|
|
@ -410,7 +410,7 @@ class DamageModelTests extends Specification {
|
|||
val func : (Any)=>Unit = resprojectile.damage_model.Calculate(resprojectile, ProjectileResolution.Splash)
|
||||
|
||||
func(vehicle)
|
||||
vehicle.Health mustEqual 632
|
||||
vehicle.Health mustEqual 641
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ class EquipmentTest extends Specification {
|
|||
obj.Size = EquipmentSize.Rifle
|
||||
obj.AmmoTypes += GlobalDefinitions.shotgun_shell
|
||||
obj.AmmoTypes += GlobalDefinitions.shotgun_shell_AP
|
||||
obj.AmmoTypes += GlobalDefinitions.shotgun_shell_AP
|
||||
obj.FireModes += new FireModeDefinition
|
||||
obj.FireModes.head.AmmoTypeIndices += 0
|
||||
obj.FireModes.head.AmmoTypeIndices += 1
|
||||
|
|
@ -163,6 +164,29 @@ class EquipmentTest extends Specification {
|
|||
obj.AmmoType mustEqual Ammo.hellfire_ammo
|
||||
}
|
||||
|
||||
"default fire mode (dual magazine feed)" in {
|
||||
val obj = ToolDefinition(1076)
|
||||
obj.AmmoTypes += GlobalDefinitions.shotgun_shell
|
||||
obj.AmmoTypes += GlobalDefinitions.shotgun_shell_AP
|
||||
obj.ProjectileTypes += GlobalDefinitions.shotgun_shell_projectile
|
||||
obj.ProjectileTypes += GlobalDefinitions.shotgun_shell_AP_projectile
|
||||
obj.FireModes += new FireModeDefinition
|
||||
obj.FireModes.head.AmmoTypeIndices += 0
|
||||
obj.FireModes.head.AmmoSlotIndex = 0
|
||||
obj.FireModes += new FireModeDefinition
|
||||
obj.FireModes(1).AmmoTypeIndices += 1
|
||||
obj.FireModes(1).AmmoSlotIndex = 1
|
||||
|
||||
val tool0 = Tool(obj)
|
||||
tool0.FireModeIndex mustEqual 0
|
||||
tool0.ProjectileType mustEqual GlobalDefinitions.shotgun_shell_projectile.ProjectileType
|
||||
|
||||
obj.DefaultFireModeIndex = 1
|
||||
val tool1 = Tool(obj)
|
||||
tool1.FireModeIndex mustEqual 1
|
||||
tool1.ProjectileType mustEqual GlobalDefinitions.shotgun_shell_AP_projectile.ProjectileType
|
||||
}
|
||||
|
||||
"multiple fire modes" in {
|
||||
//explanation: sample_weapon has two fire modes; each fire mode has a different ammunition type
|
||||
val obj : Tool = Tool(punisher)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue