mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-02-23 00:23:36 +00:00
Spud Gun (#572)
* initial spiker logic for charging mechanic; it's functional but doesn't work exactly by the numbers say it should * no damage degrade for radial damage; charge mode features, including damage on the projectile and fire mode on the weapon; the Spiker's damage output is pretty close to accurate * ammunition drain timer works correctly; no need for the progress completion function; new formatting sucks * dial back on fire mode changes; stop excessive weapon discharge case; comments * master merge; test fix (when did it change?) * test repair; fixed unintentional side-effect of instantiation of StanDamProf
This commit is contained in:
parent
b573530b25
commit
78f970a4ac
15 changed files with 552 additions and 167 deletions
|
|
@ -26,7 +26,7 @@ import net.psforever.objects.ce._
|
|||
import net.psforever.objects.definition._
|
||||
import net.psforever.objects.definition.converter.{CorpseConverter, DestroyedVehicleConverter}
|
||||
import net.psforever.objects.entity.{SimpleWorldEntity, WorldEntity}
|
||||
import net.psforever.objects.equipment.{EffectTarget, Equipment, FireModeSwitch, JammableUnit}
|
||||
import net.psforever.objects.equipment.{ChargeFireModeDefinition, EffectTarget, Equipment, FireModeSwitch, JammableUnit}
|
||||
import net.psforever.objects.guid.{GUIDTask, Task, TaskResolver}
|
||||
import net.psforever.objects.inventory.{Container, InventoryItem}
|
||||
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
||||
|
|
@ -127,8 +127,10 @@ object SessionActor {
|
|||
* must be a positive value
|
||||
* @param completionAction a finalizing action performed once the progress reaches 100(%)
|
||||
* @param tickAction an action that is performed for each increase of progress
|
||||
* @param tickTime how long between each `tickAction` (ms);
|
||||
* defaults to 250 milliseconds
|
||||
*/
|
||||
final case class ProgressEvent(delta: Float, completionAction: () => Unit, tickAction: Float => Boolean)
|
||||
final case class ProgressEvent(delta: Float, completionAction: () => Unit, tickAction: Float => Boolean, tickTime: Long = 250)
|
||||
|
||||
private final val zoningCountdownMessages: Seq[Int] = Seq(5, 10, 20)
|
||||
|
||||
|
|
@ -175,6 +177,8 @@ class SessionActor extends Actor with MDCContextAware {
|
|||
var progressBarValue: Option[Float] = None
|
||||
var shooting: Option[PlanetSideGUID] = None //ChangeFireStateMessage_Start
|
||||
var prefire: Option[PlanetSideGUID] = None //if WeaponFireMessage precedes ChangeFireStateMessage_Start
|
||||
var shootingStart: Long = 0
|
||||
var shootingStop: Long = 0
|
||||
var shotsWhileDead: Int = 0
|
||||
var accessedContainer: Option[PlanetSideGameObject with Container] = None
|
||||
var connectionState: Int = 25
|
||||
|
|
@ -543,8 +547,8 @@ class SessionActor extends Actor with MDCContextAware {
|
|||
self ! ProgressEvent(rate, finishedAction, stepAction)
|
||||
}
|
||||
|
||||
case ProgressEvent(delta, finishedAction, stepAction) =>
|
||||
HandleProgressChange(delta, finishedAction, stepAction)
|
||||
case ProgressEvent(delta, finishedAction, stepAction, tick) =>
|
||||
HandleProgressChange(delta, finishedAction, stepAction, tick)
|
||||
|
||||
case Door.DoorMessage(tplayer, msg, order) =>
|
||||
HandleDoorMessage(tplayer, msg, order)
|
||||
|
|
@ -2986,7 +2990,7 @@ class SessionActor extends Actor with MDCContextAware {
|
|||
* @param tickAction an optional action is is performed for each tick of progress;
|
||||
* also performs a continuity check to determine if the process has been disrupted
|
||||
*/
|
||||
def HandleProgressChange(delta: Float, completionAction: () => Unit, tickAction: Float => Boolean): Unit = {
|
||||
def HandleProgressChange(delta: Float, completionAction: () => Unit, tickAction: Float => Boolean, tick: Long): Unit = {
|
||||
progressBarUpdate.cancel()
|
||||
progressBarValue match {
|
||||
case Some(value) =>
|
||||
|
|
@ -3015,9 +3019,9 @@ class SessionActor extends Actor with MDCContextAware {
|
|||
progressBarValue = Some(next)
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
progressBarUpdate = context.system.scheduler.scheduleOnce(
|
||||
250 milliseconds,
|
||||
tick milliseconds,
|
||||
self,
|
||||
ProgressEvent(delta, completionAction, tickAction)
|
||||
ProgressEvent(delta, completionAction, tickAction, tick)
|
||||
)
|
||||
} else {
|
||||
progressBarValue = None
|
||||
|
|
@ -4051,6 +4055,7 @@ class SessionActor extends Actor with MDCContextAware {
|
|||
if (tool.Magazine > 0 || prefire.contains(item_guid)) {
|
||||
prefire = None
|
||||
shooting = Some(item_guid)
|
||||
shootingStart = System.currentTimeMillis()
|
||||
//special case - suppress the decimator's alternate fire mode, by projectile
|
||||
if (tool.Projectile != GlobalDefinitions.phoenix_missile_guided_projectile) {
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
|
|
@ -4058,6 +4063,17 @@ class SessionActor extends Actor with MDCContextAware {
|
|||
AvatarAction.ChangeFireState_Start(player.GUID, item_guid)
|
||||
)
|
||||
}
|
||||
//charge ammunition drain
|
||||
tool.FireMode match {
|
||||
case mode: ChargeFireModeDefinition =>
|
||||
progressBarValue = Some(0f)
|
||||
progressBarUpdate = context.system.scheduler.scheduleOnce(
|
||||
(mode.Time + mode.DrainInterval) milliseconds,
|
||||
self,
|
||||
ProgressEvent(1f, () => {}, Tools.ChargeFireMode(player, tool), mode.DrainInterval)
|
||||
)
|
||||
case _ => ;
|
||||
}
|
||||
} else {
|
||||
log.warn(
|
||||
s"ChangeFireState_Start: ${tool.Definition.Name} magazine is empty before trying to shoot bullet"
|
||||
|
|
@ -4067,6 +4083,7 @@ class SessionActor extends Actor with MDCContextAware {
|
|||
case Some(_) => //permissible, for now
|
||||
prefire = None
|
||||
shooting = Some(item_guid)
|
||||
shootingStart = System.currentTimeMillis()
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
continent.id,
|
||||
AvatarAction.ChangeFireState_Start(player.GUID, item_guid)
|
||||
|
|
@ -4079,6 +4096,7 @@ class SessionActor extends Actor with MDCContextAware {
|
|||
case msg @ ChangeFireStateMessage_Stop(item_guid) =>
|
||||
log.trace("ChangeFireState_Stop: " + msg)
|
||||
prefire = None
|
||||
shootingStop = System.currentTimeMillis()
|
||||
val weapon: Option[Equipment] = if (shooting.contains(item_guid)) {
|
||||
shooting = None
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
|
|
@ -4099,6 +4117,7 @@ class SessionActor extends Actor with MDCContextAware {
|
|||
continent.id,
|
||||
AvatarAction.ChangeFireState_Start(player.GUID, item_guid)
|
||||
)
|
||||
shootingStart = System.currentTimeMillis() - 1L
|
||||
}
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
continent.id,
|
||||
|
|
@ -4118,6 +4137,11 @@ class SessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
weapon match {
|
||||
case Some(tool: Tool) =>
|
||||
tool.FireMode match {
|
||||
case mode : ChargeFireModeDefinition =>
|
||||
sendResponse(QuantityUpdateMessage(tool.AmmoSlot.Box.GUID, tool.Magazine))
|
||||
case _ => ;
|
||||
}
|
||||
if (tool.Magazine == 0) {
|
||||
FireCycleCleanup(tool)
|
||||
}
|
||||
|
|
@ -4201,7 +4225,7 @@ class SessionActor extends Actor with MDCContextAware {
|
|||
log.warn(s"ReloadMessage: no ammunition could be found for $item_guid")
|
||||
case x :: xs =>
|
||||
val (deleteFunc, modifyFunc): (Equipment => Future[Any], (AmmoBox, Int) => Unit) = obj match {
|
||||
case (veh: Vehicle) =>
|
||||
case veh: Vehicle =>
|
||||
(RemoveOldEquipmentFromInventory(veh, taskResolver), ModifyAmmunitionInVehicle(veh))
|
||||
case o: PlanetSideServerObject with Container =>
|
||||
(RemoveOldEquipmentFromInventory(o, taskResolver), ModifyAmmunition(o))
|
||||
|
|
@ -5244,7 +5268,7 @@ class SessionActor extends Actor with MDCContextAware {
|
|||
unk6,
|
||||
unk7
|
||||
) =>
|
||||
//log.info(s"WeaponFire: $msg")
|
||||
log.info(s"WeaponFire: $msg")
|
||||
HandleWeaponFire(weapon_guid, projectile_guid, shot_origin)
|
||||
|
||||
case msg @ WeaponLazeTargetPositionMessage(weapon, pos1, pos2) =>
|
||||
|
|
@ -6811,6 +6835,7 @@ class SessionActor extends Actor with MDCContextAware {
|
|||
)
|
||||
prefire = None
|
||||
shooting = None
|
||||
shootingStop = System.currentTimeMillis()
|
||||
case None => ;
|
||||
}
|
||||
if (session.flying) {
|
||||
|
|
@ -9345,8 +9370,7 @@ class SessionActor extends Actor with MDCContextAware {
|
|||
case _ =>
|
||||
(obj.Orientation, obj.Definition.ObjectId, 300f)
|
||||
}
|
||||
val distanceToOwner =
|
||||
Vector3.DistanceSquared(shotOrigin, player.Position)
|
||||
val distanceToOwner = Vector3.DistanceSquared(shotOrigin, player.Position)
|
||||
if (distanceToOwner <= acceptableDistanceToOwner) {
|
||||
val projectile_info = tool.Projectile
|
||||
val projectile =
|
||||
|
|
@ -9357,9 +9381,15 @@ class SessionActor extends Actor with MDCContextAware {
|
|||
player,
|
||||
attribution,
|
||||
shotOrigin,
|
||||
angle
|
||||
angle,
|
||||
)
|
||||
projectiles(projectileIndex) = Some(projectile)
|
||||
val initialQuality = tool.FireMode match {
|
||||
case mode: ChargeFireModeDefinition =>
|
||||
ProjectileQuality.Modified((projectile.fire_time - shootingStart) / mode.Time.toFloat)
|
||||
case _ =>
|
||||
ProjectileQuality.Normal
|
||||
}
|
||||
projectiles(projectileIndex) = Some(projectile.quality(initialQuality))
|
||||
if (projectile_info.ExistsOnRemoteClients) {
|
||||
log.trace(
|
||||
s"WeaponFireMessage: ${projectile_info.Name} is a remote projectile"
|
||||
|
|
@ -9421,9 +9451,9 @@ class SessionActor extends Actor with MDCContextAware {
|
|||
avatarActor ! AvatarActor.ConsumeStamina(avatar.stamina)
|
||||
}
|
||||
avatarActor ! AvatarActor.SuspendStaminaRegeneration(3.seconds)
|
||||
prefire = shooting.orElse(Some(weaponGUID))
|
||||
tool.Discharge()
|
||||
}
|
||||
prefire = shooting.orElse(Some(weaponGUID))
|
||||
tool.Discharge() //always
|
||||
out
|
||||
case _ =>
|
||||
(None, None)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
package net.psforever.objects
|
||||
|
||||
import net.psforever.objects.avatar.Certification
|
||||
import net.psforever.objects.ballistics.{AggravatedDamage, AggravatedInfo, AggravatedTiming, Projectiles}
|
||||
import net.psforever.objects.ballistics._
|
||||
import net.psforever.objects.ce.{DeployableCategory, DeployedItem}
|
||||
import net.psforever.objects.definition._
|
||||
import net.psforever.objects.definition.converter._
|
||||
|
|
@ -23,8 +23,9 @@ import net.psforever.objects.serverobject.structures.{BuildingDefinition, WarpGa
|
|||
import net.psforever.objects.serverobject.turret.{FacilityTurretDefinition, TurretUpgrade}
|
||||
import net.psforever.objects.vehicles.{DestroyedVehicle, InternalTelepadDefinition, SeatArmorRestriction, UtilityType}
|
||||
import net.psforever.objects.vital.damage.{DamageCalculations, DamageModifiers}
|
||||
import net.psforever.objects.vital.{DamageType, StandardResolutions}
|
||||
import net.psforever.objects.vital.{DamageType, StandardDamageProfile, StandardResolutions}
|
||||
import net.psforever.types.{ExoSuitType, ImplantType, PlanetSideEmpire, Vector3}
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.concurrent.duration._
|
||||
|
||||
|
|
@ -3865,19 +3866,20 @@ object GlobalDefinitions {
|
|||
sparrow_secondary_projectile.Modifiers = DamageModifiers.RadialDegrade
|
||||
|
||||
spiker_projectile.Name = "spiker_projectile"
|
||||
// spiker_projectile.Damage0 = 75
|
||||
spiker_projectile.Damage0 = 20
|
||||
// spiker_projectile.Damage0_min = 20
|
||||
// spiker_projectile.Damage1 = 75
|
||||
spiker_projectile.Damage1 = 20
|
||||
// spiker_projectile.Damage1_min = 20
|
||||
spiker_projectile.Charging = ChargeDamage(4, StandardDamageProfile(damage0 = Some(20), damage1 = Some(20)))
|
||||
spiker_projectile.Damage0 = 75
|
||||
spiker_projectile.Damage1 = 75
|
||||
spiker_projectile.DamageAtEdge = 0.1f
|
||||
spiker_projectile.DamageRadius = 5f
|
||||
spiker_projectile.DamageRadius = 1f
|
||||
spiker_projectile.DamageRadiusMin = 1f
|
||||
spiker_projectile.ProjectileDamageType = DamageType.Splash
|
||||
spiker_projectile.InitialVelocity = 40
|
||||
spiker_projectile.Lifespan = 5f
|
||||
ProjectileDefinition.CalculateDerivedFields(spiker_projectile)
|
||||
spiker_projectile.Modifiers = List(
|
||||
DamageModifiers.SpikerChargeDamage,
|
||||
DamageModifiers.RadialDegrade
|
||||
)
|
||||
|
||||
spitfire_aa_ammo_projectile.Name = "spitfire_aa_ammo_projectile"
|
||||
spitfire_aa_ammo_projectile.Damage0 = 5
|
||||
|
|
@ -4214,8 +4216,8 @@ object GlobalDefinitions {
|
|||
isp.FireModes.head.AmmoTypeIndices += 0
|
||||
isp.FireModes.head.AmmoTypeIndices += 1
|
||||
isp.FireModes.head.AmmoSlotIndex = 0
|
||||
isp.FireModes.head.Chamber = 6 //8 shells x 6 pellets = 36
|
||||
isp.FireModes.head.Magazine = 8
|
||||
isp.FireModes.head.Chamber = 6 //8 shells x 6 pellets = 48
|
||||
isp.FireModes.head.Add.Damage0 = 1
|
||||
isp.FireModes.head.Add.Damage2 = 1
|
||||
isp.FireModes.head.Add.Damage3 = 1
|
||||
|
|
@ -4417,7 +4419,7 @@ object GlobalDefinitions {
|
|||
spiker.Size = EquipmentSize.Pistol
|
||||
spiker.AmmoTypes += ancient_ammo_combo
|
||||
spiker.ProjectileTypes += spiker_projectile
|
||||
spiker.FireModes += new FireModeDefinition
|
||||
spiker.FireModes += new ChargeFireModeDefinition(time = 1000, drainInterval = 500)
|
||||
spiker.FireModes.head.AmmoTypeIndices += 0
|
||||
spiker.FireModes.head.AmmoSlotIndex = 0
|
||||
spiker.FireModes.head.Magazine = 25
|
||||
|
|
@ -4682,8 +4684,8 @@ object GlobalDefinitions {
|
|||
pellet_gun.FireModes += new PelletFireModeDefinition
|
||||
pellet_gun.FireModes.head.AmmoTypeIndices += 0
|
||||
pellet_gun.FireModes.head.AmmoSlotIndex = 0
|
||||
pellet_gun.FireModes.head.Magazine = 1
|
||||
pellet_gun.FireModes.head.Chamber = 8 //1 shells * 8 pellets = 8
|
||||
pellet_gun.FireModes.head.Magazine = 1 //what is this?
|
||||
pellet_gun.FireModes.head.Chamber = 8 //1 shell * 8 pellets = 8
|
||||
pellet_gun.Tile = InventoryTile.Tile63
|
||||
|
||||
six_shooter.Name = "six_shooter"
|
||||
|
|
@ -4773,17 +4775,17 @@ object GlobalDefinitions {
|
|||
nchev_scattercannon.FireModes.head.AmmoTypeIndices += 0
|
||||
nchev_scattercannon.FireModes.head.AmmoSlotIndex = 0
|
||||
nchev_scattercannon.FireModes.head.Magazine = 40
|
||||
nchev_scattercannon.FireModes.head.Chamber = 10
|
||||
nchev_scattercannon.FireModes.head.Chamber = 10 //40 shells * 10 pellets = 400
|
||||
nchev_scattercannon.FireModes += new PelletFireModeDefinition
|
||||
nchev_scattercannon.FireModes(1).AmmoTypeIndices += 0
|
||||
nchev_scattercannon.FireModes(1).AmmoSlotIndex = 0
|
||||
nchev_scattercannon.FireModes(1).Magazine = 40
|
||||
nchev_scattercannon.FireModes(1).Chamber = 10
|
||||
nchev_scattercannon.FireModes(1).Chamber = 10 //40 shells * 10 pellets = 400
|
||||
nchev_scattercannon.FireModes += new PelletFireModeDefinition
|
||||
nchev_scattercannon.FireModes(2).AmmoTypeIndices += 0
|
||||
nchev_scattercannon.FireModes(2).AmmoSlotIndex = 0
|
||||
nchev_scattercannon.FireModes(2).Magazine = 40
|
||||
nchev_scattercannon.FireModes(2).Chamber = 10
|
||||
nchev_scattercannon.FireModes(2).Chamber = 10 //40 shells * 10 pellets = 400
|
||||
|
||||
nchev_falcon.Name = "nchev_falcon"
|
||||
nchev_falcon.Size = EquipmentSize.Max
|
||||
|
|
@ -5526,7 +5528,7 @@ object GlobalDefinitions {
|
|||
energy_gun_nc.FireModes.head.AmmoTypeIndices += 0
|
||||
energy_gun_nc.FireModes.head.AmmoSlotIndex = 0
|
||||
energy_gun_nc.FireModes.head.Magazine = 35
|
||||
energy_gun_nc.FireModes.head.Chamber = 9
|
||||
energy_gun_nc.FireModes.head.Chamber = 8 //35 shots * 8 pellets = 280
|
||||
|
||||
energy_gun_tr.Name = "energy_gun_tr"
|
||||
energy_gun_tr.Size = EquipmentSize.BaseTurretWeapon
|
||||
|
|
|
|||
|
|
@ -239,3 +239,5 @@ object Tool {
|
|||
def Definition: FireModeDefinition = fdef
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
37
src/main/scala/net/psforever/objects/Tools.scala
Normal file
37
src/main/scala/net/psforever/objects/Tools.scala
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) 2020 PSForever
|
||||
package net.psforever.objects
|
||||
|
||||
import net.psforever.objects.equipment.ChargeFireModeDefinition
|
||||
import net.psforever.packet.game.QuantityUpdateMessage
|
||||
import net.psforever.services.Service
|
||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||
|
||||
object Tools {
|
||||
/**
|
||||
*
|
||||
* @param player the player performing the revive action
|
||||
* @param tool the tool being used to execute the attack;
|
||||
* should have a selected chargeable fire mode
|
||||
* @param progress the current progress value
|
||||
* @see `ChargeFireModeDefinition`
|
||||
* @see `QuantityUpdateMessage`
|
||||
* @return `true`, if the next cycle of progress should occur;
|
||||
* `false`, otherwise
|
||||
*/
|
||||
def ChargeFireMode(player: Player, tool: Tool)(progress: Float): Boolean = {
|
||||
tool.FireMode match {
|
||||
case mode: ChargeFireModeDefinition if tool.Magazine > 0 =>
|
||||
val magazine = tool.Magazine -= mode.RoundsPerInterval
|
||||
player.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||
player.Name,
|
||||
AvatarAction.SendResponse(
|
||||
Service.defaultPlayerGUID,
|
||||
QuantityUpdateMessage(tool.AmmoSlot.Box.GUID, magazine)
|
||||
)
|
||||
)
|
||||
player.isAlive
|
||||
case _ =>
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright (c) 2020 PSForever
|
||||
package net.psforever.objects.ballistics
|
||||
|
||||
import net.psforever.objects.vital.StandardDamageProfile
|
||||
|
||||
final case class ChargeDamage(
|
||||
effect_count: Int,
|
||||
min: StandardDamageProfile
|
||||
)
|
||||
|
|
@ -43,7 +43,7 @@ final case class Projectile(
|
|||
shot_angle: Vector3,
|
||||
quality: ProjectileQuality = ProjectileQuality.Normal,
|
||||
id: Long = Projectile.idGenerator.getAndIncrement(),
|
||||
fire_time: Long = System.nanoTime
|
||||
fire_time: Long = System.currentTimeMillis()
|
||||
) extends PlanetSideGameObject {
|
||||
Position = shot_origin
|
||||
Orientation = shot_angle
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.definition
|
||||
|
||||
import net.psforever.objects.ballistics.{AggravatedDamage, Projectiles}
|
||||
import net.psforever.objects.ballistics.{AggravatedDamage, ChargeDamage, Projectiles}
|
||||
import net.psforever.objects.equipment.JammingUnit
|
||||
import net.psforever.objects.vital.damage.DamageModifiers
|
||||
import net.psforever.objects.vital.{DamageType, StandardDamageProfile}
|
||||
|
|
@ -38,8 +38,10 @@ class ProjectileDefinition(objectId: Int)
|
|||
private var lifespan: Float = 1f
|
||||
/** for radial damage, how much damage has been lost the further away from the impact point (m) */
|
||||
private var damageAtEdge: Float = 1f
|
||||
/** for radial damage, the radial distance of the explosion effect (m) */
|
||||
private var damageRadius: Float = 1f
|
||||
/** for radial damage, the distance of the explosion effect (m) */
|
||||
private var damageRadius: Float = 0f
|
||||
/** for radial damage, the distance before degradation of the explosion effect (m) */
|
||||
private var damageRadiusMin: Float = 1f
|
||||
/** for lashing damage, how far away a target will be affected by the projectile (m) */
|
||||
private var lashRadius : Float = 0f
|
||||
/** use a specific modifier as a part of damage calculations */
|
||||
|
|
@ -65,9 +67,11 @@ class ProjectileDefinition(objectId: Int)
|
|||
private var jammerProjectile: Boolean = false
|
||||
/** projectile takes the form of a type of "grenade";
|
||||
* grenades arc with gravity rather than travel in a relatively straight path */
|
||||
private var grenade_projectile : Boolean = false
|
||||
private var grenade_projectile: Boolean = false
|
||||
/** projectile tries to confers aggravated damage burn to its target */
|
||||
private var aggravated_damage : Option[AggravatedDamage] = None
|
||||
private var aggravated_damage: Option[AggravatedDamage] = None
|
||||
/** */
|
||||
private var charging: Option[ChargeDamage] = None
|
||||
//derived calculations
|
||||
/** the calculated distance at which the projectile have traveled far enough to despawn (m);
|
||||
* typically handled as the projectile no longer performing damage;
|
||||
|
|
@ -75,7 +79,8 @@ class ProjectileDefinition(objectId: Int)
|
|||
private var distanceMax: Float = 0f
|
||||
/** how far the projectile will travel while accelerating (m) */
|
||||
private var distanceFromAcceleration: Float = 0f
|
||||
/** how far the projectile will travel while no degrading (m) */
|
||||
/** how far the projectile will travel while not degrading (m);
|
||||
* this field is not to be used in the place of minimum radial damage */
|
||||
private var distanceNoDegrade: Float = 0f
|
||||
/** after acceleration, if any, what is the final speed of the projectile (m/s) */
|
||||
private var finalVelocity: Float = 0f
|
||||
|
|
@ -172,6 +177,13 @@ class ProjectileDefinition(objectId: Int)
|
|||
DamageRadius
|
||||
}
|
||||
|
||||
def DamageRadiusMin: Float = damageRadiusMin
|
||||
|
||||
def DamageRadiusMin_=(damageRadius: Float): Float = {
|
||||
this.damageRadiusMin = damageRadius
|
||||
DamageRadiusMin
|
||||
}
|
||||
|
||||
def LashRadius: Float = lashRadius
|
||||
|
||||
def LashRadius_=(radius: Float): Float = {
|
||||
|
|
@ -239,6 +251,15 @@ class ProjectileDefinition(objectId: Int)
|
|||
Aggravated
|
||||
}
|
||||
|
||||
def Charging : Option[ChargeDamage] = charging
|
||||
|
||||
def Charging_=(damage : ChargeDamage) : Option[ChargeDamage] = Charging_=(Some(damage))
|
||||
|
||||
def Charging_=(damage : Option[ChargeDamage]) : Option[ChargeDamage] = {
|
||||
charging = damage
|
||||
Charging
|
||||
}
|
||||
|
||||
def DistanceMax : Float = distanceMax //accessor only
|
||||
|
||||
def DistanceFromAcceleration: Float = distanceFromAcceleration //accessor only
|
||||
|
|
@ -253,6 +274,13 @@ object ProjectileDefinition {
|
|||
new ProjectileDefinition(projectileType.id)
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the secondary fields of the projectile's damage.
|
||||
* Depending on whether the appropriate fields are defined,
|
||||
* it may calculate for "damage over distance", typically associated with straight-fire direct hit projectiles,
|
||||
* or for "radial damage", typically associated with explosive splash projectiles.
|
||||
* @param pdef the projectile's definition, often called its profile
|
||||
*/
|
||||
def CalculateDerivedFields(pdef: ProjectileDefinition): Unit = {
|
||||
val (distanceMax, distanceFromAcceleration, finalVelocity): (Float, Float, Float) = if (pdef.Acceleration == 0) {
|
||||
(pdef.InitialVelocity * pdef.Lifespan, 0, pdef.InitialVelocity.toFloat)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
package net.psforever.objects.equipment
|
||||
|
||||
import net.psforever.objects.Tool
|
||||
import net.psforever.objects.vital.damage.{DamageModifiers, DamageProfile}
|
||||
import net.psforever.objects.vital.SpecificDamageProfile
|
||||
import net.psforever.objects.vital.damage.DamageModifiers
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
|
|
@ -41,7 +42,7 @@ class FireModeDefinition extends DamageModifiers {
|
|||
private var chamber: Int = 1
|
||||
|
||||
/** modifiers for each damage type */
|
||||
private val modifiers: FireModeDamageModifiers = new FireModeDamageModifiers
|
||||
private val modifiers: SpecificDamageProfile = new SpecificDamageProfile
|
||||
|
||||
def AmmoSlotIndex: Int = ammoSlotIndex
|
||||
|
||||
|
|
@ -91,7 +92,7 @@ class FireModeDefinition extends DamageModifiers {
|
|||
Chamber
|
||||
}
|
||||
|
||||
def Add: FireModeDamageModifiers = modifiers
|
||||
def Add: SpecificDamageProfile = modifiers
|
||||
|
||||
/**
|
||||
* Shoot a weapon, remove an anticipated amount of ammunition.
|
||||
|
|
@ -108,8 +109,8 @@ class FireModeDefinition extends DamageModifiers {
|
|||
}
|
||||
}
|
||||
|
||||
class PelletFireModeDefinition extends FireModeDefinition {
|
||||
|
||||
class PelletFireModeDefinition
|
||||
extends FireModeDefinition {
|
||||
/**
|
||||
* Shoot a weapon, remove an anticipated amount of ammunition.<br>
|
||||
* <br>
|
||||
|
|
@ -132,7 +133,8 @@ class PelletFireModeDefinition extends FireModeDefinition {
|
|||
}
|
||||
}
|
||||
|
||||
class InfiniteFireModeDefinition extends FireModeDefinition {
|
||||
class InfiniteFireModeDefinition
|
||||
extends FireModeDefinition {
|
||||
|
||||
/**
|
||||
* Shoot a weapon, remove an anticipated amount of ammunition.<br>
|
||||
|
|
@ -150,45 +152,19 @@ class InfiniteFireModeDefinition extends FireModeDefinition {
|
|||
override def Discharge(weapon: Tool, rounds: Option[Int] = None): Int = 1
|
||||
}
|
||||
|
||||
class FireModeDamageModifiers extends DamageProfile {
|
||||
private var damage0: Int = 0
|
||||
private var damage1: Int = 0
|
||||
private var damage2: Int = 0
|
||||
private var damage3: Int = 0
|
||||
private var damage4: Int = 0
|
||||
/**
|
||||
* Shoot a weapon, remove an anticipated amount of ammunition.<br>
|
||||
* <br>
|
||||
* Hold down the fire trigger to create a damage multiplier.
|
||||
* After the multiplier has reach complete/full, expend additional ammunition to sustain it.
|
||||
* @param time the duration until the charge is full (milliseconds)
|
||||
* @param drainInterval the curation between ticks of ammunition depletion after "full charge"
|
||||
*/
|
||||
class ChargeFireModeDefinition(private val time: Long, private val drainInterval: Long, private val roundsPerInterval: Int = 1)
|
||||
extends FireModeDefinition {
|
||||
def Time: Long = time
|
||||
|
||||
def Damage0: Int = damage0
|
||||
def DrainInterval: Long = drainInterval
|
||||
|
||||
def Damage0_=(damage: Int): Int = {
|
||||
damage0 = damage
|
||||
Damage0
|
||||
}
|
||||
|
||||
def Damage1: Int = damage1
|
||||
|
||||
def Damage1_=(damage: Int): Int = {
|
||||
damage1 = damage
|
||||
Damage1
|
||||
}
|
||||
|
||||
def Damage2: Int = damage2
|
||||
|
||||
def Damage2_=(damage: Int): Int = {
|
||||
damage2 = damage
|
||||
Damage2
|
||||
}
|
||||
|
||||
def Damage3: Int = damage3
|
||||
|
||||
def Damage3_=(damage: Int): Int = {
|
||||
damage3 = damage
|
||||
Damage3
|
||||
}
|
||||
|
||||
def Damage4: Int = damage4
|
||||
|
||||
def Damage4_=(damage: Int): Int = {
|
||||
damage4 = damage
|
||||
Damage4
|
||||
}
|
||||
def RoundsPerInterval: Int = roundsPerInterval
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright (c) 2020 PSForever
|
||||
package net.psforever.objects.vital
|
||||
|
||||
import net.psforever.objects.vital.damage.DamageProfile
|
||||
|
||||
class SpecificDamageProfile extends DamageProfile {
|
||||
private var damage0: Int = 0
|
||||
private var damage1: Int = 0
|
||||
private var damage2: Int = 0
|
||||
private var damage3: Int = 0
|
||||
private var damage4: Int = 0
|
||||
|
||||
def Damage0: Int = damage0
|
||||
|
||||
def Damage0_=(damage: Int): Int = {
|
||||
damage0 = damage
|
||||
Damage0
|
||||
}
|
||||
|
||||
def Damage1: Int = damage1
|
||||
|
||||
def Damage1_=(damage: Int): Int = {
|
||||
damage1 = damage
|
||||
Damage1
|
||||
}
|
||||
|
||||
def Damage2: Int = damage2
|
||||
|
||||
def Damage2_=(damage: Int): Int = {
|
||||
damage2 = damage
|
||||
Damage2
|
||||
}
|
||||
|
||||
def Damage3: Int = damage3
|
||||
|
||||
def Damage3_=(damage: Int): Int = {
|
||||
damage3 = damage
|
||||
Damage3
|
||||
}
|
||||
|
||||
def Damage4: Int = damage4
|
||||
|
||||
def Damage4_=(damage: Int): Int = {
|
||||
damage4 = damage
|
||||
Damage4
|
||||
}
|
||||
}
|
||||
|
||||
object SpecificDamageProfile {
|
||||
def apply(
|
||||
damage0: Int = 0,
|
||||
damage1: Int = 0,
|
||||
damage2: Int = 0,
|
||||
damage3: Int = 0,
|
||||
damage4: Int = 0
|
||||
): SpecificDamageProfile = {
|
||||
val obj = new SpecificDamageProfile
|
||||
obj.Damage0 = damage0
|
||||
obj.Damage1 = damage1
|
||||
obj.Damage2 = damage2
|
||||
obj.Damage3 = damage3
|
||||
obj.Damage4 = damage4
|
||||
obj
|
||||
}
|
||||
}
|
||||
|
|
@ -61,3 +61,21 @@ trait StandardDamageProfile extends DamageProfile {
|
|||
Damage4
|
||||
}
|
||||
}
|
||||
|
||||
object StandardDamageProfile {
|
||||
def apply(
|
||||
damage0: Option[Int] = None,
|
||||
damage1: Option[Int] = None,
|
||||
damage2: Option[Int] = None,
|
||||
damage3: Option[Int] = None,
|
||||
damage4: Option[Int] = None
|
||||
): StandardDamageProfile = {
|
||||
val obj = new StandardDamageProfile { }
|
||||
obj.Damage0 = damage0
|
||||
obj.Damage1 = damage1
|
||||
obj.Damage2 = damage2
|
||||
obj.Damage3 = damage3
|
||||
obj.Damage4 = damage4
|
||||
obj
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package net.psforever.objects.vital.damage
|
||||
|
||||
import net.psforever.objects.ballistics._
|
||||
import net.psforever.objects.equipment.ChargeFireModeDefinition
|
||||
import net.psforever.objects.vital.DamageType
|
||||
import net.psforever.types.{ExoSuitType, Vector3}
|
||||
|
||||
|
|
@ -97,12 +98,17 @@ object DamageModifiers {
|
|||
def Calculate: DamageModifiers.Format = function
|
||||
|
||||
private def function(damage: Int, data: ResolvedProjectile): Int = {
|
||||
val profile = data.projectile.profile
|
||||
val distance = Vector3.Distance(data.hit_pos, data.target.Position)
|
||||
val radius = profile.DamageRadius
|
||||
if (distance <= radius) {
|
||||
val base: Float = profile.DamageAtEdge
|
||||
(damage * ((1 - base) * ((radius - distance) / radius) + base)).toInt
|
||||
val profile = data.projectile.profile
|
||||
val distance = Vector3.Distance(data.hit_pos, data.target.Position)
|
||||
val radius = profile.DamageRadius
|
||||
val radiusMin = profile.DamageRadiusMin
|
||||
if (distance <= radiusMin) {
|
||||
damage
|
||||
} else if (distance <= radius) {
|
||||
//damage - (damage * profile.DamageAtEdge * (distance - radiusMin) / (radius - radiusMin)).toInt
|
||||
val base = profile.DamageAtEdge
|
||||
val radi = radius - radiusMin
|
||||
(damage * ((1 - base) * ((radi - (distance - radiusMin)) / radi) + base)).toInt
|
||||
} else {
|
||||
0
|
||||
}
|
||||
|
|
@ -418,4 +424,19 @@ object DamageModifiers {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
case object SpikerChargeDamage extends Mod {
|
||||
def Calculate: DamageModifiers.Format = formula
|
||||
|
||||
private def formula(damage: Int, data: ResolvedProjectile): Int = {
|
||||
val projectile = data.projectile
|
||||
(projectile.fire_mode, projectile.profile.Charging) match {
|
||||
case (_: ChargeFireModeDefinition, Some(info: ChargeDamage)) =>
|
||||
val chargeQuality = math.max(0f, math.min(projectile.quality.mod, 1f))
|
||||
data.damage_model.DamageUsing(info.min) + (damage * chargeQuality).toInt
|
||||
case _ =>
|
||||
damage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,107 +18,280 @@ object GamePacketOpcode extends Enumeration {
|
|||
type Type = Value
|
||||
val
|
||||
// OPCODES 0x00-0f
|
||||
Unknown0, // PPT_NULL in beta client
|
||||
LoginMessage, LoginRespMessage, ConnectToWorldRequestMessage, // found by searching for 83 F8 03 89 in IDA
|
||||
ConnectToWorldMessage, VNLWorldStatusMessage, UnknownMessage6, // PPT_TRANSFERTOWORLDREQUEST
|
||||
UnknownMessage7, // PPT_TRANSFERTOWORLDRESPONSE
|
||||
Unknown0, // PPT_NULL in beta client
|
||||
LoginMessage,
|
||||
LoginRespMessage,
|
||||
ConnectToWorldRequestMessage, // found by searching for 83 F8 03 89 in IDA
|
||||
ConnectToWorldMessage,
|
||||
VNLWorldStatusMessage,
|
||||
UnknownMessage6, // PPT_TRANSFERTOWORLDREQUEST
|
||||
UnknownMessage7, // PPT_TRANSFERTOWORLDRESPONSE
|
||||
// 0x08
|
||||
PlayerStateMessage, HitMessage, HitHint, DamageMessage, DestroyMessage, ReloadMessage, MountVehicleMsg,
|
||||
DismountVehicleMsg,
|
||||
PlayerStateMessage,
|
||||
HitMessage,
|
||||
HitHint,
|
||||
DamageMessage,
|
||||
DestroyMessage,
|
||||
ReloadMessage,
|
||||
MountVehicleMsg,
|
||||
DismountVehicleMsg,
|
||||
// OPCODES 0x10-1f
|
||||
UseItemMessage, MoveItemMessage, ChatMsg, CharacterNoRecordMessage, CharacterInfoMessage,
|
||||
UnknownMessage21, // PPT_DISCONNECT
|
||||
BindPlayerMessage, ObjectCreateMessage_Duplicate, // PPT_OBJECTCREATE
|
||||
UseItemMessage,
|
||||
MoveItemMessage,
|
||||
ChatMsg,
|
||||
CharacterNoRecordMessage,
|
||||
CharacterInfoMessage,
|
||||
UnknownMessage21, // PPT_DISCONNECT
|
||||
BindPlayerMessage,
|
||||
ObjectCreateMessage_Duplicate, // PPT_OBJECTCREATE
|
||||
// 0x18
|
||||
ObjectCreateMessage, // PPT_OBJECTCREATEDETAILED
|
||||
ObjectDeleteMessage, PingMsg, VehicleStateMessage, FrameVehicleStateMessage, GenericObjectStateMsg,
|
||||
ChildObjectStateMessage, ActionResultMessage,
|
||||
ObjectDeleteMessage,
|
||||
PingMsg,
|
||||
VehicleStateMessage,
|
||||
FrameVehicleStateMessage,
|
||||
GenericObjectStateMsg,
|
||||
ChildObjectStateMessage,
|
||||
ActionResultMessage,
|
||||
// OPCODES 0x20-2f
|
||||
UnknownMessage32, // PPT_ACTIONBEGIN
|
||||
ActionProgressMessage, ActionCancelMessage, ActionCancelAcknowledgeMessage, SetEmpireMessage, EmoteMsg,
|
||||
UnuseItemMessage, ObjectDetachMessage,
|
||||
ActionProgressMessage,
|
||||
ActionCancelMessage,
|
||||
ActionCancelAcknowledgeMessage,
|
||||
SetEmpireMessage,
|
||||
EmoteMsg,
|
||||
UnuseItemMessage,
|
||||
ObjectDetachMessage,
|
||||
// 0x28
|
||||
CreateShortcutMessage, ChangeShortcutBankMessage, ObjectAttachMessage, UnknownMessage43, // PPT_OBJECTEMPTY
|
||||
PlanetsideAttributeMessage, RequestDestroyMessage, UnknownMessage46, // PPT_EQUIPITEM
|
||||
CreateShortcutMessage,
|
||||
ChangeShortcutBankMessage,
|
||||
ObjectAttachMessage,
|
||||
UnknownMessage43, // PPT_OBJECTEMPTY
|
||||
PlanetsideAttributeMessage,
|
||||
RequestDestroyMessage,
|
||||
UnknownMessage46, // PPT_EQUIPITEM
|
||||
CharacterCreateRequestMessage,
|
||||
// OPCODES 0x30-3f
|
||||
CharacterRequestMessage, LoadMapMessage, SetCurrentAvatarMessage, ObjectHeldMessage, WeaponFireMessage,
|
||||
AvatarJumpMessage, PickupItemMessage, DropItemMessage,
|
||||
CharacterRequestMessage,
|
||||
LoadMapMessage,
|
||||
SetCurrentAvatarMessage,
|
||||
ObjectHeldMessage,
|
||||
WeaponFireMessage,
|
||||
AvatarJumpMessage,
|
||||
PickupItemMessage,
|
||||
DropItemMessage,
|
||||
// 0x38
|
||||
InventoryStateMessage, ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, UnknownMessage59,
|
||||
GenericCollisionMsg, QuantityUpdateMessage, ArmorChangedMessage, ProjectileStateMessage,
|
||||
InventoryStateMessage,
|
||||
ChangeFireStateMessage_Start,
|
||||
ChangeFireStateMessage_Stop,
|
||||
UnknownMessage59,
|
||||
GenericCollisionMsg,
|
||||
QuantityUpdateMessage,
|
||||
ArmorChangedMessage,
|
||||
ProjectileStateMessage,
|
||||
// OPCODES 0x40-4f
|
||||
MountVehicleCargoMsg, DismountVehicleCargoMsg, CargoMountPointStatusMessage, BeginZoningMessage,
|
||||
ItemTransactionMessage, ItemTransactionResultMessage, ChangeFireModeMessage, ChangeAmmoMessage,
|
||||
MountVehicleCargoMsg,
|
||||
DismountVehicleCargoMsg,
|
||||
CargoMountPointStatusMessage,
|
||||
BeginZoningMessage,
|
||||
ItemTransactionMessage,
|
||||
ItemTransactionResultMessage,
|
||||
ChangeFireModeMessage,
|
||||
ChangeAmmoMessage,
|
||||
// 0x48
|
||||
TimeOfDayMessage, UnknownMessage73, // PPT_PROJECTILE_EVENT_BLOCK
|
||||
SpawnRequestMessage, DeployRequestMessage, UnknownMessage76, // PPT_BUILDINGSTATECHANGED
|
||||
RepairMessage, ServerVehicleOverrideMsg, LashMessage,
|
||||
TimeOfDayMessage,
|
||||
UnknownMessage73, // PPT_PROJECTILE_EVENT_BLOCK
|
||||
SpawnRequestMessage,
|
||||
DeployRequestMessage,
|
||||
UnknownMessage76, // PPT_BUILDINGSTATECHANGED
|
||||
RepairMessage,
|
||||
ServerVehicleOverrideMsg,
|
||||
LashMessage,
|
||||
// OPCODES 0x50-5f
|
||||
TargetingInfoMessage, TriggerEffectMessage, WeaponDryFireMessage, DroppodLaunchRequestMessage, HackMessage,
|
||||
DroppodLaunchResponseMessage, GenericObjectActionMessage, AvatarVehicleTimerMessage,
|
||||
TargetingInfoMessage,
|
||||
TriggerEffectMessage,
|
||||
WeaponDryFireMessage,
|
||||
DroppodLaunchRequestMessage,
|
||||
HackMessage,
|
||||
DroppodLaunchResponseMessage,
|
||||
GenericObjectActionMessage,
|
||||
AvatarVehicleTimerMessage,
|
||||
// 0x58
|
||||
AvatarImplantMessage, UnknownMessage89, // PPT_SEARCHMESSAGE
|
||||
DelayedPathMountMsg, OrbitalShuttleTimeMsg, AIDamage, DeployObjectMessage, FavoritesRequest, FavoritesResponse,
|
||||
AvatarImplantMessage,
|
||||
UnknownMessage89, // PPT_SEARCHMESSAGE
|
||||
DelayedPathMountMsg,
|
||||
OrbitalShuttleTimeMsg,
|
||||
AIDamage,
|
||||
DeployObjectMessage,
|
||||
FavoritesRequest,
|
||||
FavoritesResponse,
|
||||
// OPCODES 0x60-6f
|
||||
FavoritesMessage, ObjectDetectedMessage, SplashHitMessage, SetChatFilterMessage, AvatarSearchCriteriaMessage,
|
||||
AvatarSearchResponse, WeaponJammedMessage, LinkDeadAwarenessMsg,
|
||||
FavoritesMessage,
|
||||
ObjectDetectedMessage,
|
||||
SplashHitMessage,
|
||||
SetChatFilterMessage,
|
||||
AvatarSearchCriteriaMessage,
|
||||
AvatarSearchResponse,
|
||||
WeaponJammedMessage,
|
||||
LinkDeadAwarenessMsg,
|
||||
// 0x68
|
||||
DroppodFreefallingMessage, AvatarFirstTimeEventMessage, AggravatedDamageMessage, TriggerSoundMessage, LootItemMessage,
|
||||
VehicleSubStateMessage, SquadMembershipRequest, SquadMembershipResponse,
|
||||
DroppodFreefallingMessage,
|
||||
AvatarFirstTimeEventMessage,
|
||||
AggravatedDamageMessage,
|
||||
TriggerSoundMessage,
|
||||
LootItemMessage,
|
||||
VehicleSubStateMessage,
|
||||
SquadMembershipRequest,
|
||||
SquadMembershipResponse,
|
||||
// OPCODES 0x70-7f
|
||||
SquadMemberEvent, PlatoonEvent, FriendsRequest, FriendsResponse, TriggerEnvironmentalDamageMessage,
|
||||
TrainingZoneMessage, DeployableObjectsInfoMessage, SquadState,
|
||||
SquadMemberEvent,
|
||||
PlatoonEvent,
|
||||
FriendsRequest,
|
||||
FriendsResponse,
|
||||
TriggerEnvironmentalDamageMessage,
|
||||
TrainingZoneMessage,
|
||||
DeployableObjectsInfoMessage,
|
||||
SquadState,
|
||||
// 0x78
|
||||
OxygenStateMessage, TradeMessage, UnknownMessage122, DamageFeedbackMessage, DismountBuildingMsg,
|
||||
UnknownMessage125, // PPT_MOUNTBUILDING
|
||||
UnknownMessage126, // PPT_INTENDEDDROPZONE
|
||||
OxygenStateMessage,
|
||||
TradeMessage,
|
||||
UnknownMessage122,
|
||||
DamageFeedbackMessage,
|
||||
DismountBuildingMsg,
|
||||
UnknownMessage125, // PPT_MOUNTBUILDING
|
||||
UnknownMessage126, // PPT_INTENDEDDROPZONE
|
||||
AvatarStatisticsMessage,
|
||||
// OPCODES 0x80-8f
|
||||
GenericObjectAction2Message, DestroyDisplayMessage, TriggerBotAction, SquadWaypointRequest, SquadWaypointEvent,
|
||||
OffshoreVehicleMessage, ObjectDeployedMessage, ObjectDeployedCountMessage,
|
||||
GenericObjectAction2Message,
|
||||
DestroyDisplayMessage,
|
||||
TriggerBotAction,
|
||||
SquadWaypointRequest,
|
||||
SquadWaypointEvent,
|
||||
OffshoreVehicleMessage,
|
||||
ObjectDeployedMessage,
|
||||
ObjectDeployedCountMessage,
|
||||
// 0x88
|
||||
WeaponDelayFireMessage, BugReportMessage, PlayerStasisMessage, UnknownMessage139, OutfitMembershipRequest,
|
||||
OutfitMembershipResponse, OutfitRequest, OutfitEvent,
|
||||
WeaponDelayFireMessage,
|
||||
BugReportMessage,
|
||||
PlayerStasisMessage,
|
||||
UnknownMessage139,
|
||||
OutfitMembershipRequest,
|
||||
OutfitMembershipResponse,
|
||||
OutfitRequest,
|
||||
OutfitEvent,
|
||||
// OPCODES 0x90-9f
|
||||
OutfitMemberEvent, OutfitMemberUpdate, PlanetsideStringAttributeMessage, DataChallengeMessage,
|
||||
DataChallengeMessageResp, WeatherMessage, SimDataChallenge, SimDataChallengeResp,
|
||||
OutfitMemberEvent,
|
||||
OutfitMemberUpdate,
|
||||
PlanetsideStringAttributeMessage,
|
||||
DataChallengeMessage,
|
||||
DataChallengeMessageResp,
|
||||
WeatherMessage,
|
||||
SimDataChallenge,
|
||||
SimDataChallengeResp,
|
||||
// 0x98
|
||||
OutfitListEvent, EmpireIncentivesMessage, InvalidTerrainMessage, SyncMessage, DebugDrawMessage, SoulMarkMessage,
|
||||
UplinkPositionEvent, HotSpotUpdateMessage,
|
||||
OutfitListEvent,
|
||||
EmpireIncentivesMessage,
|
||||
InvalidTerrainMessage,
|
||||
SyncMessage,
|
||||
DebugDrawMessage,
|
||||
SoulMarkMessage,
|
||||
UplinkPositionEvent,
|
||||
HotSpotUpdateMessage,
|
||||
// OPCODES 0xa0-af
|
||||
BuildingInfoUpdateMessage, FireHintMessage, UplinkRequest, UplinkResponse, WarpgateRequest, WarpgateResponse,
|
||||
DamageWithPositionMessage, GenericActionMessage,
|
||||
BuildingInfoUpdateMessage,
|
||||
FireHintMessage,
|
||||
UplinkRequest,
|
||||
UplinkResponse,
|
||||
WarpgateRequest,
|
||||
WarpgateResponse,
|
||||
DamageWithPositionMessage,
|
||||
GenericActionMessage,
|
||||
// 0xa8
|
||||
ContinentalLockUpdateMessage, AvatarGrenadeStateMessage, UnknownMessage170, UnknownMessage171,
|
||||
ReleaseAvatarRequestMessage, AvatarDeadStateMessage, CSAssistMessage, CSAssistCommentMessage,
|
||||
ContinentalLockUpdateMessage,
|
||||
AvatarGrenadeStateMessage,
|
||||
UnknownMessage170,
|
||||
UnknownMessage171,
|
||||
ReleaseAvatarRequestMessage,
|
||||
AvatarDeadStateMessage,
|
||||
CSAssistMessage,
|
||||
CSAssistCommentMessage,
|
||||
// OPCODES 0xb0-bf
|
||||
VoiceHostRequest, VoiceHostKill, VoiceHostInfo, BattleplanMessage, BattleExperienceMessage, TargetingImplantRequest,
|
||||
ZonePopulationUpdateMessage, DisconnectMessage,
|
||||
VoiceHostRequest,
|
||||
VoiceHostKill,
|
||||
VoiceHostInfo,
|
||||
BattleplanMessage,
|
||||
BattleExperienceMessage,
|
||||
TargetingImplantRequest,
|
||||
ZonePopulationUpdateMessage,
|
||||
DisconnectMessage,
|
||||
// 0xb8
|
||||
ExperienceAddedMessage, OrbitalStrikeWaypointMessage, KeepAliveMessage, MapObjectStateBlockMessage, SnoopMsg,
|
||||
PlayerStateMessageUpstream, PlayerStateShiftMessage, ZipLineMessage,
|
||||
ExperienceAddedMessage,
|
||||
OrbitalStrikeWaypointMessage,
|
||||
KeepAliveMessage,
|
||||
MapObjectStateBlockMessage,
|
||||
SnoopMsg,
|
||||
PlayerStateMessageUpstream,
|
||||
PlayerStateShiftMessage,
|
||||
ZipLineMessage,
|
||||
// OPCODES 0xc0-cf
|
||||
CaptureFlagUpdateMessage, VanuModuleUpdateMessage, FacilityBenefitShieldChargeRequestMessage,
|
||||
ProximityTerminalUseMessage, QuantityDeltaUpdateMessage, ChainLashMessage, ZoneInfoMessage,
|
||||
LongRangeProjectileInfoMessage,
|
||||
CaptureFlagUpdateMessage,
|
||||
VanuModuleUpdateMessage,
|
||||
FacilityBenefitShieldChargeRequestMessage,
|
||||
ProximityTerminalUseMessage,
|
||||
QuantityDeltaUpdateMessage,
|
||||
ChainLashMessage,
|
||||
ZoneInfoMessage,
|
||||
LongRangeProjectileInfoMessage,
|
||||
// 0xc8
|
||||
WeaponLazeTargetPositionMessage, ModuleLimitsMessage, OutfitBenefitMessage, EmpireChangeTimeMessage,
|
||||
ClockCalibrationMessage, DensityLevelUpdateMessage, ActOfGodMessage, AvatarAwardMessage,
|
||||
WeaponLazeTargetPositionMessage,
|
||||
ModuleLimitsMessage,
|
||||
OutfitBenefitMessage,
|
||||
EmpireChangeTimeMessage,
|
||||
ClockCalibrationMessage,
|
||||
DensityLevelUpdateMessage,
|
||||
ActOfGodMessage,
|
||||
AvatarAwardMessage,
|
||||
// OPCODES 0xd0-df
|
||||
UnknownMessage208, DisplayedAwardMessage, RespawnAMSInfoMessage, ComponentDamageMessage,
|
||||
GenericObjectActionAtPositionMessage, PropertyOverrideMessage, WarpgateLinkOverrideMessage, EmpireBenefitsMessage,
|
||||
UnknownMessage208,
|
||||
DisplayedAwardMessage,
|
||||
RespawnAMSInfoMessage,
|
||||
ComponentDamageMessage,
|
||||
GenericObjectActionAtPositionMessage,
|
||||
PropertyOverrideMessage,
|
||||
WarpgateLinkOverrideMessage,
|
||||
EmpireBenefitsMessage,
|
||||
// 0xd8
|
||||
ForceEmpireMessage, BroadcastWarpgateUpdateMessage, UnknownMessage218, SquadMainTerminalMessage,
|
||||
SquadMainTerminalResponseMessage, SquadOrderMessage, SquadOrderResponse, ZoneLockInfoMessage,
|
||||
ForceEmpireMessage,
|
||||
BroadcastWarpgateUpdateMessage,
|
||||
UnknownMessage218,
|
||||
SquadMainTerminalMessage,
|
||||
SquadMainTerminalResponseMessage,
|
||||
SquadOrderMessage,
|
||||
SquadOrderResponse,
|
||||
ZoneLockInfoMessage,
|
||||
// OPCODES 0xe0-ef
|
||||
SquadBindInfoMessage, AudioSequenceMessage, SquadFacilityBindInfoMessage, ZoneForcedCavernConnectionsMessage,
|
||||
MissionActionMessage, MissionKillTriggerMessage, ReplicationStreamMessage, SquadDefinitionActionMessage,
|
||||
SquadBindInfoMessage,
|
||||
AudioSequenceMessage,
|
||||
SquadFacilityBindInfoMessage,
|
||||
ZoneForcedCavernConnectionsMessage,
|
||||
MissionActionMessage,
|
||||
MissionKillTriggerMessage,
|
||||
ReplicationStreamMessage,
|
||||
SquadDefinitionActionMessage,
|
||||
// 0xe8
|
||||
SquadDetailDefinitionUpdateMessage, TacticsMessage, RabbitUpdateMessage, SquadInvitationRequestMessage,
|
||||
CharacterKnowledgeMessage, GameScoreUpdateMessage, UnknownMessage238, OrderTerminalBugMessage,
|
||||
SquadDetailDefinitionUpdateMessage,
|
||||
TacticsMessage,
|
||||
RabbitUpdateMessage,
|
||||
SquadInvitationRequestMessage,
|
||||
CharacterKnowledgeMessage,
|
||||
GameScoreUpdateMessage,
|
||||
UnknownMessage238,
|
||||
OrderTerminalBugMessage,
|
||||
// OPCODES 0xf0-f3
|
||||
QueueTimedHelpMessage, MailMessage, GameVarUpdate, ClientCheatedMessage // last known message type (243, 0xf3)
|
||||
QueueTimedHelpMessage,
|
||||
MailMessage,
|
||||
GameVarUpdate,
|
||||
ClientCheatedMessage // last known message type (243, 0xf3)
|
||||
= Value
|
||||
|
||||
private def noDecoder(opcode: GamePacketOpcode.Type) =
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package net.psforever.util
|
|||
import net.psforever.objects.definition.BasicDefinition
|
||||
import net.psforever.objects.{AmmoBox, GlobalDefinitions, Player, SimpleItem, Tool}
|
||||
import net.psforever.types.ExoSuitType
|
||||
|
||||
import scala.reflect.runtime.universe
|
||||
|
||||
// TODO definitions should be in an iterable format
|
||||
|
|
@ -225,10 +226,10 @@ object DefinitionUtil {
|
|||
def applyDefaultLoadout(player: Player): Unit = {
|
||||
val faction = player.Faction
|
||||
player.ExoSuit = ExoSuitType.Standard
|
||||
player.Slot(0).Equipment = Tool(GlobalDefinitions.StandardPistol(faction))
|
||||
player.Slot(0).Equipment = Tool(GlobalDefinitions.spiker)//StandardPistol(faction))
|
||||
player.Slot(2).Equipment = Tool(GlobalDefinitions.suppressor)
|
||||
player.Slot(4).Equipment = Tool(GlobalDefinitions.StandardMelee(faction))
|
||||
player.Slot(6).Equipment = AmmoBox(GlobalDefinitions.bullet_9mm)
|
||||
player.Slot(6).Equipment = AmmoBox(GlobalDefinitions.ancient_ammo_combo)
|
||||
player.Slot(9).Equipment = AmmoBox(GlobalDefinitions.bullet_9mm)
|
||||
player.Slot(12).Equipment = AmmoBox(GlobalDefinitions.bullet_9mm)
|
||||
player.Slot(33).Equipment = AmmoBox(GlobalDefinitions.bullet_9mm_AP)
|
||||
|
|
|
|||
|
|
@ -3,12 +3,7 @@ package objects
|
|||
|
||||
import net.psforever.objects.definition.ToolDefinition
|
||||
import net.psforever.objects.{GlobalDefinitions, Tool}
|
||||
import net.psforever.objects.equipment.{
|
||||
EquipmentSize,
|
||||
FireModeDefinition,
|
||||
InfiniteFireModeDefinition,
|
||||
PelletFireModeDefinition
|
||||
}
|
||||
import net.psforever.objects.equipment._
|
||||
import org.specs2.mutable._
|
||||
|
||||
class FireModeTest extends Specification {
|
||||
|
|
@ -129,4 +124,32 @@ class FireModeTest extends Specification {
|
|||
obj.Magazine mustEqual 1
|
||||
}
|
||||
}
|
||||
|
||||
"ChargeFireModeDefinition" should {
|
||||
"construct" in {
|
||||
val obj = new ChargeFireModeDefinition(1000, 500)
|
||||
obj.AmmoTypeIndices mustEqual Nil
|
||||
obj.AmmoSlotIndex mustEqual 0
|
||||
obj.Magazine mustEqual 1
|
||||
obj.RoundsPerShot mustEqual 1
|
||||
obj.Chamber mustEqual 1
|
||||
obj.Time mustEqual 1000L
|
||||
obj.DrainInterval mustEqual 500L
|
||||
}
|
||||
|
||||
"discharge" in {
|
||||
val obj = Tool(GlobalDefinitions.spiker)
|
||||
obj.FireMode.isInstanceOf[ChargeFireModeDefinition] mustEqual true
|
||||
obj.Magazine mustEqual 25
|
||||
obj.FireMode.RoundsPerShot mustEqual 1
|
||||
obj.FireMode.Chamber mustEqual 1
|
||||
|
||||
obj.Magazine mustEqual 25
|
||||
obj.Discharge()
|
||||
obj.Magazine mustEqual 24
|
||||
obj.Discharge()
|
||||
obj.Discharge()
|
||||
obj.Magazine mustEqual 22
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ class ProjectileTest extends Specification {
|
|||
obj.InitialVelocity mustEqual 1
|
||||
obj.Lifespan mustEqual 1f
|
||||
obj.DamageAtEdge mustEqual 1f
|
||||
obj.DamageRadius mustEqual 1f
|
||||
obj.DamageRadius mustEqual 0f
|
||||
obj.UseDamage1Subtract mustEqual false
|
||||
}
|
||||
|
||||
|
|
@ -269,7 +269,7 @@ class ProjectileTest extends Specification {
|
|||
obj.attribute_to mustEqual obj.tool_def.ObjectId
|
||||
obj.shot_origin mustEqual Vector3(1.2f, 3.4f, 5.6f)
|
||||
obj.shot_angle mustEqual Vector3(0.2f, 0.4f, 0.6f)
|
||||
obj.fire_time <= System.nanoTime mustEqual true
|
||||
obj.fire_time <= System.currentTimeMillis() mustEqual true
|
||||
obj.isResolved mustEqual false
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue