mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-14 16:04:41 +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._
|
||||||
import net.psforever.objects.definition.converter.{CorpseConverter, DestroyedVehicleConverter}
|
import net.psforever.objects.definition.converter.{CorpseConverter, DestroyedVehicleConverter}
|
||||||
import net.psforever.objects.entity.{SimpleWorldEntity, WorldEntity}
|
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.guid.{GUIDTask, Task, TaskResolver}
|
||||||
import net.psforever.objects.inventory.{Container, InventoryItem}
|
import net.psforever.objects.inventory.{Container, InventoryItem}
|
||||||
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
||||||
|
|
@ -127,8 +127,10 @@ object SessionActor {
|
||||||
* must be a positive value
|
* must be a positive value
|
||||||
* @param completionAction a finalizing action performed once the progress reaches 100(%)
|
* @param completionAction a finalizing action performed once the progress reaches 100(%)
|
||||||
* @param tickAction an action that is performed for each increase of progress
|
* @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)
|
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 progressBarValue: Option[Float] = None
|
||||||
var shooting: Option[PlanetSideGUID] = None //ChangeFireStateMessage_Start
|
var shooting: Option[PlanetSideGUID] = None //ChangeFireStateMessage_Start
|
||||||
var prefire: Option[PlanetSideGUID] = None //if WeaponFireMessage precedes 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 shotsWhileDead: Int = 0
|
||||||
var accessedContainer: Option[PlanetSideGameObject with Container] = None
|
var accessedContainer: Option[PlanetSideGameObject with Container] = None
|
||||||
var connectionState: Int = 25
|
var connectionState: Int = 25
|
||||||
|
|
@ -543,8 +547,8 @@ class SessionActor extends Actor with MDCContextAware {
|
||||||
self ! ProgressEvent(rate, finishedAction, stepAction)
|
self ! ProgressEvent(rate, finishedAction, stepAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
case ProgressEvent(delta, finishedAction, stepAction) =>
|
case ProgressEvent(delta, finishedAction, stepAction, tick) =>
|
||||||
HandleProgressChange(delta, finishedAction, stepAction)
|
HandleProgressChange(delta, finishedAction, stepAction, tick)
|
||||||
|
|
||||||
case Door.DoorMessage(tplayer, msg, order) =>
|
case Door.DoorMessage(tplayer, msg, order) =>
|
||||||
HandleDoorMessage(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;
|
* @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
|
* 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()
|
progressBarUpdate.cancel()
|
||||||
progressBarValue match {
|
progressBarValue match {
|
||||||
case Some(value) =>
|
case Some(value) =>
|
||||||
|
|
@ -3015,9 +3019,9 @@ class SessionActor extends Actor with MDCContextAware {
|
||||||
progressBarValue = Some(next)
|
progressBarValue = Some(next)
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
progressBarUpdate = context.system.scheduler.scheduleOnce(
|
progressBarUpdate = context.system.scheduler.scheduleOnce(
|
||||||
250 milliseconds,
|
tick milliseconds,
|
||||||
self,
|
self,
|
||||||
ProgressEvent(delta, completionAction, tickAction)
|
ProgressEvent(delta, completionAction, tickAction, tick)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
progressBarValue = None
|
progressBarValue = None
|
||||||
|
|
@ -4051,6 +4055,7 @@ class SessionActor extends Actor with MDCContextAware {
|
||||||
if (tool.Magazine > 0 || prefire.contains(item_guid)) {
|
if (tool.Magazine > 0 || prefire.contains(item_guid)) {
|
||||||
prefire = None
|
prefire = None
|
||||||
shooting = Some(item_guid)
|
shooting = Some(item_guid)
|
||||||
|
shootingStart = System.currentTimeMillis()
|
||||||
//special case - suppress the decimator's alternate fire mode, by projectile
|
//special case - suppress the decimator's alternate fire mode, by projectile
|
||||||
if (tool.Projectile != GlobalDefinitions.phoenix_missile_guided_projectile) {
|
if (tool.Projectile != GlobalDefinitions.phoenix_missile_guided_projectile) {
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(
|
continent.AvatarEvents ! AvatarServiceMessage(
|
||||||
|
|
@ -4058,6 +4063,17 @@ class SessionActor extends Actor with MDCContextAware {
|
||||||
AvatarAction.ChangeFireState_Start(player.GUID, item_guid)
|
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 {
|
} else {
|
||||||
log.warn(
|
log.warn(
|
||||||
s"ChangeFireState_Start: ${tool.Definition.Name} magazine is empty before trying to shoot bullet"
|
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
|
case Some(_) => //permissible, for now
|
||||||
prefire = None
|
prefire = None
|
||||||
shooting = Some(item_guid)
|
shooting = Some(item_guid)
|
||||||
|
shootingStart = System.currentTimeMillis()
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(
|
continent.AvatarEvents ! AvatarServiceMessage(
|
||||||
continent.id,
|
continent.id,
|
||||||
AvatarAction.ChangeFireState_Start(player.GUID, item_guid)
|
AvatarAction.ChangeFireState_Start(player.GUID, item_guid)
|
||||||
|
|
@ -4079,6 +4096,7 @@ class SessionActor extends Actor with MDCContextAware {
|
||||||
case msg @ ChangeFireStateMessage_Stop(item_guid) =>
|
case msg @ ChangeFireStateMessage_Stop(item_guid) =>
|
||||||
log.trace("ChangeFireState_Stop: " + msg)
|
log.trace("ChangeFireState_Stop: " + msg)
|
||||||
prefire = None
|
prefire = None
|
||||||
|
shootingStop = System.currentTimeMillis()
|
||||||
val weapon: Option[Equipment] = if (shooting.contains(item_guid)) {
|
val weapon: Option[Equipment] = if (shooting.contains(item_guid)) {
|
||||||
shooting = None
|
shooting = None
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(
|
continent.AvatarEvents ! AvatarServiceMessage(
|
||||||
|
|
@ -4099,6 +4117,7 @@ class SessionActor extends Actor with MDCContextAware {
|
||||||
continent.id,
|
continent.id,
|
||||||
AvatarAction.ChangeFireState_Start(player.GUID, item_guid)
|
AvatarAction.ChangeFireState_Start(player.GUID, item_guid)
|
||||||
)
|
)
|
||||||
|
shootingStart = System.currentTimeMillis() - 1L
|
||||||
}
|
}
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(
|
continent.AvatarEvents ! AvatarServiceMessage(
|
||||||
continent.id,
|
continent.id,
|
||||||
|
|
@ -4118,6 +4137,11 @@ class SessionActor extends Actor with MDCContextAware {
|
||||||
}
|
}
|
||||||
weapon match {
|
weapon match {
|
||||||
case Some(tool: Tool) =>
|
case Some(tool: Tool) =>
|
||||||
|
tool.FireMode match {
|
||||||
|
case mode : ChargeFireModeDefinition =>
|
||||||
|
sendResponse(QuantityUpdateMessage(tool.AmmoSlot.Box.GUID, tool.Magazine))
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
if (tool.Magazine == 0) {
|
if (tool.Magazine == 0) {
|
||||||
FireCycleCleanup(tool)
|
FireCycleCleanup(tool)
|
||||||
}
|
}
|
||||||
|
|
@ -4201,7 +4225,7 @@ class SessionActor extends Actor with MDCContextAware {
|
||||||
log.warn(s"ReloadMessage: no ammunition could be found for $item_guid")
|
log.warn(s"ReloadMessage: no ammunition could be found for $item_guid")
|
||||||
case x :: xs =>
|
case x :: xs =>
|
||||||
val (deleteFunc, modifyFunc): (Equipment => Future[Any], (AmmoBox, Int) => Unit) = obj match {
|
val (deleteFunc, modifyFunc): (Equipment => Future[Any], (AmmoBox, Int) => Unit) = obj match {
|
||||||
case (veh: Vehicle) =>
|
case veh: Vehicle =>
|
||||||
(RemoveOldEquipmentFromInventory(veh, taskResolver), ModifyAmmunitionInVehicle(veh))
|
(RemoveOldEquipmentFromInventory(veh, taskResolver), ModifyAmmunitionInVehicle(veh))
|
||||||
case o: PlanetSideServerObject with Container =>
|
case o: PlanetSideServerObject with Container =>
|
||||||
(RemoveOldEquipmentFromInventory(o, taskResolver), ModifyAmmunition(o))
|
(RemoveOldEquipmentFromInventory(o, taskResolver), ModifyAmmunition(o))
|
||||||
|
|
@ -5244,7 +5268,7 @@ class SessionActor extends Actor with MDCContextAware {
|
||||||
unk6,
|
unk6,
|
||||||
unk7
|
unk7
|
||||||
) =>
|
) =>
|
||||||
//log.info(s"WeaponFire: $msg")
|
log.info(s"WeaponFire: $msg")
|
||||||
HandleWeaponFire(weapon_guid, projectile_guid, shot_origin)
|
HandleWeaponFire(weapon_guid, projectile_guid, shot_origin)
|
||||||
|
|
||||||
case msg @ WeaponLazeTargetPositionMessage(weapon, pos1, pos2) =>
|
case msg @ WeaponLazeTargetPositionMessage(weapon, pos1, pos2) =>
|
||||||
|
|
@ -6811,6 +6835,7 @@ class SessionActor extends Actor with MDCContextAware {
|
||||||
)
|
)
|
||||||
prefire = None
|
prefire = None
|
||||||
shooting = None
|
shooting = None
|
||||||
|
shootingStop = System.currentTimeMillis()
|
||||||
case None => ;
|
case None => ;
|
||||||
}
|
}
|
||||||
if (session.flying) {
|
if (session.flying) {
|
||||||
|
|
@ -9345,8 +9370,7 @@ class SessionActor extends Actor with MDCContextAware {
|
||||||
case _ =>
|
case _ =>
|
||||||
(obj.Orientation, obj.Definition.ObjectId, 300f)
|
(obj.Orientation, obj.Definition.ObjectId, 300f)
|
||||||
}
|
}
|
||||||
val distanceToOwner =
|
val distanceToOwner = Vector3.DistanceSquared(shotOrigin, player.Position)
|
||||||
Vector3.DistanceSquared(shotOrigin, player.Position)
|
|
||||||
if (distanceToOwner <= acceptableDistanceToOwner) {
|
if (distanceToOwner <= acceptableDistanceToOwner) {
|
||||||
val projectile_info = tool.Projectile
|
val projectile_info = tool.Projectile
|
||||||
val projectile =
|
val projectile =
|
||||||
|
|
@ -9357,9 +9381,15 @@ class SessionActor extends Actor with MDCContextAware {
|
||||||
player,
|
player,
|
||||||
attribution,
|
attribution,
|
||||||
shotOrigin,
|
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) {
|
if (projectile_info.ExistsOnRemoteClients) {
|
||||||
log.trace(
|
log.trace(
|
||||||
s"WeaponFireMessage: ${projectile_info.Name} is a remote projectile"
|
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.ConsumeStamina(avatar.stamina)
|
||||||
}
|
}
|
||||||
avatarActor ! AvatarActor.SuspendStaminaRegeneration(3.seconds)
|
avatarActor ! AvatarActor.SuspendStaminaRegeneration(3.seconds)
|
||||||
|
prefire = shooting.orElse(Some(weaponGUID))
|
||||||
|
tool.Discharge()
|
||||||
}
|
}
|
||||||
prefire = shooting.orElse(Some(weaponGUID))
|
|
||||||
tool.Discharge() //always
|
|
||||||
out
|
out
|
||||||
case _ =>
|
case _ =>
|
||||||
(None, None)
|
(None, None)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
package net.psforever.objects
|
package net.psforever.objects
|
||||||
|
|
||||||
import net.psforever.objects.avatar.Certification
|
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.ce.{DeployableCategory, DeployedItem}
|
||||||
import net.psforever.objects.definition._
|
import net.psforever.objects.definition._
|
||||||
import net.psforever.objects.definition.converter._
|
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.serverobject.turret.{FacilityTurretDefinition, TurretUpgrade}
|
||||||
import net.psforever.objects.vehicles.{DestroyedVehicle, InternalTelepadDefinition, SeatArmorRestriction, UtilityType}
|
import net.psforever.objects.vehicles.{DestroyedVehicle, InternalTelepadDefinition, SeatArmorRestriction, UtilityType}
|
||||||
import net.psforever.objects.vital.damage.{DamageCalculations, DamageModifiers}
|
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 net.psforever.types.{ExoSuitType, ImplantType, PlanetSideEmpire, Vector3}
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
|
@ -3865,19 +3866,20 @@ object GlobalDefinitions {
|
||||||
sparrow_secondary_projectile.Modifiers = DamageModifiers.RadialDegrade
|
sparrow_secondary_projectile.Modifiers = DamageModifiers.RadialDegrade
|
||||||
|
|
||||||
spiker_projectile.Name = "spiker_projectile"
|
spiker_projectile.Name = "spiker_projectile"
|
||||||
// spiker_projectile.Damage0 = 75
|
spiker_projectile.Charging = ChargeDamage(4, StandardDamageProfile(damage0 = Some(20), damage1 = Some(20)))
|
||||||
spiker_projectile.Damage0 = 20
|
spiker_projectile.Damage0 = 75
|
||||||
// spiker_projectile.Damage0_min = 20
|
spiker_projectile.Damage1 = 75
|
||||||
// spiker_projectile.Damage1 = 75
|
|
||||||
spiker_projectile.Damage1 = 20
|
|
||||||
// spiker_projectile.Damage1_min = 20
|
|
||||||
spiker_projectile.DamageAtEdge = 0.1f
|
spiker_projectile.DamageAtEdge = 0.1f
|
||||||
spiker_projectile.DamageRadius = 5f
|
spiker_projectile.DamageRadius = 5f
|
||||||
spiker_projectile.DamageRadius = 1f
|
spiker_projectile.DamageRadiusMin = 1f
|
||||||
spiker_projectile.ProjectileDamageType = DamageType.Splash
|
spiker_projectile.ProjectileDamageType = DamageType.Splash
|
||||||
spiker_projectile.InitialVelocity = 40
|
spiker_projectile.InitialVelocity = 40
|
||||||
spiker_projectile.Lifespan = 5f
|
spiker_projectile.Lifespan = 5f
|
||||||
ProjectileDefinition.CalculateDerivedFields(spiker_projectile)
|
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.Name = "spitfire_aa_ammo_projectile"
|
||||||
spitfire_aa_ammo_projectile.Damage0 = 5
|
spitfire_aa_ammo_projectile.Damage0 = 5
|
||||||
|
|
@ -4214,8 +4216,8 @@ object GlobalDefinitions {
|
||||||
isp.FireModes.head.AmmoTypeIndices += 0
|
isp.FireModes.head.AmmoTypeIndices += 0
|
||||||
isp.FireModes.head.AmmoTypeIndices += 1
|
isp.FireModes.head.AmmoTypeIndices += 1
|
||||||
isp.FireModes.head.AmmoSlotIndex = 0
|
isp.FireModes.head.AmmoSlotIndex = 0
|
||||||
|
isp.FireModes.head.Chamber = 6 //8 shells x 6 pellets = 36
|
||||||
isp.FireModes.head.Magazine = 8
|
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.Damage0 = 1
|
||||||
isp.FireModes.head.Add.Damage2 = 1
|
isp.FireModes.head.Add.Damage2 = 1
|
||||||
isp.FireModes.head.Add.Damage3 = 1
|
isp.FireModes.head.Add.Damage3 = 1
|
||||||
|
|
@ -4417,7 +4419,7 @@ object GlobalDefinitions {
|
||||||
spiker.Size = EquipmentSize.Pistol
|
spiker.Size = EquipmentSize.Pistol
|
||||||
spiker.AmmoTypes += ancient_ammo_combo
|
spiker.AmmoTypes += ancient_ammo_combo
|
||||||
spiker.ProjectileTypes += spiker_projectile
|
spiker.ProjectileTypes += spiker_projectile
|
||||||
spiker.FireModes += new FireModeDefinition
|
spiker.FireModes += new ChargeFireModeDefinition(time = 1000, drainInterval = 500)
|
||||||
spiker.FireModes.head.AmmoTypeIndices += 0
|
spiker.FireModes.head.AmmoTypeIndices += 0
|
||||||
spiker.FireModes.head.AmmoSlotIndex = 0
|
spiker.FireModes.head.AmmoSlotIndex = 0
|
||||||
spiker.FireModes.head.Magazine = 25
|
spiker.FireModes.head.Magazine = 25
|
||||||
|
|
@ -4682,8 +4684,8 @@ object GlobalDefinitions {
|
||||||
pellet_gun.FireModes += new PelletFireModeDefinition
|
pellet_gun.FireModes += new PelletFireModeDefinition
|
||||||
pellet_gun.FireModes.head.AmmoTypeIndices += 0
|
pellet_gun.FireModes.head.AmmoTypeIndices += 0
|
||||||
pellet_gun.FireModes.head.AmmoSlotIndex = 0
|
pellet_gun.FireModes.head.AmmoSlotIndex = 0
|
||||||
pellet_gun.FireModes.head.Magazine = 1
|
pellet_gun.FireModes.head.Magazine = 1 //what is this?
|
||||||
pellet_gun.FireModes.head.Chamber = 8 //1 shells * 8 pellets = 8
|
pellet_gun.FireModes.head.Chamber = 8 //1 shell * 8 pellets = 8
|
||||||
pellet_gun.Tile = InventoryTile.Tile63
|
pellet_gun.Tile = InventoryTile.Tile63
|
||||||
|
|
||||||
six_shooter.Name = "six_shooter"
|
six_shooter.Name = "six_shooter"
|
||||||
|
|
@ -4773,17 +4775,17 @@ object GlobalDefinitions {
|
||||||
nchev_scattercannon.FireModes.head.AmmoTypeIndices += 0
|
nchev_scattercannon.FireModes.head.AmmoTypeIndices += 0
|
||||||
nchev_scattercannon.FireModes.head.AmmoSlotIndex = 0
|
nchev_scattercannon.FireModes.head.AmmoSlotIndex = 0
|
||||||
nchev_scattercannon.FireModes.head.Magazine = 40
|
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 += new PelletFireModeDefinition
|
||||||
nchev_scattercannon.FireModes(1).AmmoTypeIndices += 0
|
nchev_scattercannon.FireModes(1).AmmoTypeIndices += 0
|
||||||
nchev_scattercannon.FireModes(1).AmmoSlotIndex = 0
|
nchev_scattercannon.FireModes(1).AmmoSlotIndex = 0
|
||||||
nchev_scattercannon.FireModes(1).Magazine = 40
|
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 += new PelletFireModeDefinition
|
||||||
nchev_scattercannon.FireModes(2).AmmoTypeIndices += 0
|
nchev_scattercannon.FireModes(2).AmmoTypeIndices += 0
|
||||||
nchev_scattercannon.FireModes(2).AmmoSlotIndex = 0
|
nchev_scattercannon.FireModes(2).AmmoSlotIndex = 0
|
||||||
nchev_scattercannon.FireModes(2).Magazine = 40
|
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.Name = "nchev_falcon"
|
||||||
nchev_falcon.Size = EquipmentSize.Max
|
nchev_falcon.Size = EquipmentSize.Max
|
||||||
|
|
@ -5526,7 +5528,7 @@ object GlobalDefinitions {
|
||||||
energy_gun_nc.FireModes.head.AmmoTypeIndices += 0
|
energy_gun_nc.FireModes.head.AmmoTypeIndices += 0
|
||||||
energy_gun_nc.FireModes.head.AmmoSlotIndex = 0
|
energy_gun_nc.FireModes.head.AmmoSlotIndex = 0
|
||||||
energy_gun_nc.FireModes.head.Magazine = 35
|
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.Name = "energy_gun_tr"
|
||||||
energy_gun_tr.Size = EquipmentSize.BaseTurretWeapon
|
energy_gun_tr.Size = EquipmentSize.BaseTurretWeapon
|
||||||
|
|
|
||||||
|
|
@ -239,3 +239,5 @@ object Tool {
|
||||||
def Definition: FireModeDefinition = fdef
|
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,
|
shot_angle: Vector3,
|
||||||
quality: ProjectileQuality = ProjectileQuality.Normal,
|
quality: ProjectileQuality = ProjectileQuality.Normal,
|
||||||
id: Long = Projectile.idGenerator.getAndIncrement(),
|
id: Long = Projectile.idGenerator.getAndIncrement(),
|
||||||
fire_time: Long = System.nanoTime
|
fire_time: Long = System.currentTimeMillis()
|
||||||
) extends PlanetSideGameObject {
|
) extends PlanetSideGameObject {
|
||||||
Position = shot_origin
|
Position = shot_origin
|
||||||
Orientation = shot_angle
|
Orientation = shot_angle
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.definition
|
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.equipment.JammingUnit
|
||||||
import net.psforever.objects.vital.damage.DamageModifiers
|
import net.psforever.objects.vital.damage.DamageModifiers
|
||||||
import net.psforever.objects.vital.{DamageType, StandardDamageProfile}
|
import net.psforever.objects.vital.{DamageType, StandardDamageProfile}
|
||||||
|
|
@ -38,8 +38,10 @@ class ProjectileDefinition(objectId: Int)
|
||||||
private var lifespan: Float = 1f
|
private var lifespan: Float = 1f
|
||||||
/** for radial damage, how much damage has been lost the further away from the impact point (m) */
|
/** for radial damage, how much damage has been lost the further away from the impact point (m) */
|
||||||
private var damageAtEdge: Float = 1f
|
private var damageAtEdge: Float = 1f
|
||||||
/** for radial damage, the radial distance of the explosion effect (m) */
|
/** for radial damage, the distance of the explosion effect (m) */
|
||||||
private var damageRadius: Float = 1f
|
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) */
|
/** for lashing damage, how far away a target will be affected by the projectile (m) */
|
||||||
private var lashRadius : Float = 0f
|
private var lashRadius : Float = 0f
|
||||||
/** use a specific modifier as a part of damage calculations */
|
/** use a specific modifier as a part of damage calculations */
|
||||||
|
|
@ -65,9 +67,11 @@ class ProjectileDefinition(objectId: Int)
|
||||||
private var jammerProjectile: Boolean = false
|
private var jammerProjectile: Boolean = false
|
||||||
/** projectile takes the form of a type of "grenade";
|
/** projectile takes the form of a type of "grenade";
|
||||||
* grenades arc with gravity rather than travel in a relatively straight path */
|
* 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 */
|
/** 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
|
//derived calculations
|
||||||
/** the calculated distance at which the projectile have traveled far enough to despawn (m);
|
/** the calculated distance at which the projectile have traveled far enough to despawn (m);
|
||||||
* typically handled as the projectile no longer performing damage;
|
* typically handled as the projectile no longer performing damage;
|
||||||
|
|
@ -75,7 +79,8 @@ class ProjectileDefinition(objectId: Int)
|
||||||
private var distanceMax: Float = 0f
|
private var distanceMax: Float = 0f
|
||||||
/** how far the projectile will travel while accelerating (m) */
|
/** how far the projectile will travel while accelerating (m) */
|
||||||
private var distanceFromAcceleration: Float = 0f
|
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
|
private var distanceNoDegrade: Float = 0f
|
||||||
/** after acceleration, if any, what is the final speed of the projectile (m/s) */
|
/** after acceleration, if any, what is the final speed of the projectile (m/s) */
|
||||||
private var finalVelocity: Float = 0f
|
private var finalVelocity: Float = 0f
|
||||||
|
|
@ -172,6 +177,13 @@ class ProjectileDefinition(objectId: Int)
|
||||||
DamageRadius
|
DamageRadius
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def DamageRadiusMin: Float = damageRadiusMin
|
||||||
|
|
||||||
|
def DamageRadiusMin_=(damageRadius: Float): Float = {
|
||||||
|
this.damageRadiusMin = damageRadius
|
||||||
|
DamageRadiusMin
|
||||||
|
}
|
||||||
|
|
||||||
def LashRadius: Float = lashRadius
|
def LashRadius: Float = lashRadius
|
||||||
|
|
||||||
def LashRadius_=(radius: Float): Float = {
|
def LashRadius_=(radius: Float): Float = {
|
||||||
|
|
@ -239,6 +251,15 @@ class ProjectileDefinition(objectId: Int)
|
||||||
Aggravated
|
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 DistanceMax : Float = distanceMax //accessor only
|
||||||
|
|
||||||
def DistanceFromAcceleration: Float = distanceFromAcceleration //accessor only
|
def DistanceFromAcceleration: Float = distanceFromAcceleration //accessor only
|
||||||
|
|
@ -253,6 +274,13 @@ object ProjectileDefinition {
|
||||||
new ProjectileDefinition(projectileType.id)
|
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 = {
|
def CalculateDerivedFields(pdef: ProjectileDefinition): Unit = {
|
||||||
val (distanceMax, distanceFromAcceleration, finalVelocity): (Float, Float, Float) = if (pdef.Acceleration == 0) {
|
val (distanceMax, distanceFromAcceleration, finalVelocity): (Float, Float, Float) = if (pdef.Acceleration == 0) {
|
||||||
(pdef.InitialVelocity * pdef.Lifespan, 0, pdef.InitialVelocity.toFloat)
|
(pdef.InitialVelocity * pdef.Lifespan, 0, pdef.InitialVelocity.toFloat)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@
|
||||||
package net.psforever.objects.equipment
|
package net.psforever.objects.equipment
|
||||||
|
|
||||||
import net.psforever.objects.Tool
|
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
|
import scala.collection.mutable
|
||||||
|
|
||||||
|
|
@ -41,7 +42,7 @@ class FireModeDefinition extends DamageModifiers {
|
||||||
private var chamber: Int = 1
|
private var chamber: Int = 1
|
||||||
|
|
||||||
/** modifiers for each damage type */
|
/** modifiers for each damage type */
|
||||||
private val modifiers: FireModeDamageModifiers = new FireModeDamageModifiers
|
private val modifiers: SpecificDamageProfile = new SpecificDamageProfile
|
||||||
|
|
||||||
def AmmoSlotIndex: Int = ammoSlotIndex
|
def AmmoSlotIndex: Int = ammoSlotIndex
|
||||||
|
|
||||||
|
|
@ -91,7 +92,7 @@ class FireModeDefinition extends DamageModifiers {
|
||||||
Chamber
|
Chamber
|
||||||
}
|
}
|
||||||
|
|
||||||
def Add: FireModeDamageModifiers = modifiers
|
def Add: SpecificDamageProfile = modifiers
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shoot a weapon, remove an anticipated amount of ammunition.
|
* 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>
|
* Shoot a weapon, remove an anticipated amount of ammunition.<br>
|
||||||
* <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>
|
* 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
|
override def Discharge(weapon: Tool, rounds: Option[Int] = None): Int = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
class FireModeDamageModifiers extends DamageProfile {
|
/**
|
||||||
private var damage0: Int = 0
|
* Shoot a weapon, remove an anticipated amount of ammunition.<br>
|
||||||
private var damage1: Int = 0
|
* <br>
|
||||||
private var damage2: Int = 0
|
* Hold down the fire trigger to create a damage multiplier.
|
||||||
private var damage3: Int = 0
|
* After the multiplier has reach complete/full, expend additional ammunition to sustain it.
|
||||||
private var damage4: Int = 0
|
* @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 = {
|
def RoundsPerInterval: Int = roundsPerInterval
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
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
|
package net.psforever.objects.vital.damage
|
||||||
|
|
||||||
import net.psforever.objects.ballistics._
|
import net.psforever.objects.ballistics._
|
||||||
|
import net.psforever.objects.equipment.ChargeFireModeDefinition
|
||||||
import net.psforever.objects.vital.DamageType
|
import net.psforever.objects.vital.DamageType
|
||||||
import net.psforever.types.{ExoSuitType, Vector3}
|
import net.psforever.types.{ExoSuitType, Vector3}
|
||||||
|
|
||||||
|
|
@ -97,12 +98,17 @@ object DamageModifiers {
|
||||||
def Calculate: DamageModifiers.Format = function
|
def Calculate: DamageModifiers.Format = function
|
||||||
|
|
||||||
private def function(damage: Int, data: ResolvedProjectile): Int = {
|
private def function(damage: Int, data: ResolvedProjectile): Int = {
|
||||||
val profile = data.projectile.profile
|
val profile = data.projectile.profile
|
||||||
val distance = Vector3.Distance(data.hit_pos, data.target.Position)
|
val distance = Vector3.Distance(data.hit_pos, data.target.Position)
|
||||||
val radius = profile.DamageRadius
|
val radius = profile.DamageRadius
|
||||||
if (distance <= radius) {
|
val radiusMin = profile.DamageRadiusMin
|
||||||
val base: Float = profile.DamageAtEdge
|
if (distance <= radiusMin) {
|
||||||
(damage * ((1 - base) * ((radius - distance) / radius) + base)).toInt
|
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 {
|
} else {
|
||||||
0
|
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
|
type Type = Value
|
||||||
val
|
val
|
||||||
// OPCODES 0x00-0f
|
// OPCODES 0x00-0f
|
||||||
Unknown0, // PPT_NULL in beta client
|
Unknown0, // PPT_NULL in beta client
|
||||||
LoginMessage, LoginRespMessage, ConnectToWorldRequestMessage, // found by searching for 83 F8 03 89 in IDA
|
LoginMessage,
|
||||||
ConnectToWorldMessage, VNLWorldStatusMessage, UnknownMessage6, // PPT_TRANSFERTOWORLDREQUEST
|
LoginRespMessage,
|
||||||
UnknownMessage7, // PPT_TRANSFERTOWORLDRESPONSE
|
ConnectToWorldRequestMessage, // found by searching for 83 F8 03 89 in IDA
|
||||||
|
ConnectToWorldMessage,
|
||||||
|
VNLWorldStatusMessage,
|
||||||
|
UnknownMessage6, // PPT_TRANSFERTOWORLDREQUEST
|
||||||
|
UnknownMessage7, // PPT_TRANSFERTOWORLDRESPONSE
|
||||||
// 0x08
|
// 0x08
|
||||||
PlayerStateMessage, HitMessage, HitHint, DamageMessage, DestroyMessage, ReloadMessage, MountVehicleMsg,
|
PlayerStateMessage,
|
||||||
DismountVehicleMsg,
|
HitMessage,
|
||||||
|
HitHint,
|
||||||
|
DamageMessage,
|
||||||
|
DestroyMessage,
|
||||||
|
ReloadMessage,
|
||||||
|
MountVehicleMsg,
|
||||||
|
DismountVehicleMsg,
|
||||||
// OPCODES 0x10-1f
|
// OPCODES 0x10-1f
|
||||||
UseItemMessage, MoveItemMessage, ChatMsg, CharacterNoRecordMessage, CharacterInfoMessage,
|
UseItemMessage,
|
||||||
UnknownMessage21, // PPT_DISCONNECT
|
MoveItemMessage,
|
||||||
BindPlayerMessage, ObjectCreateMessage_Duplicate, // PPT_OBJECTCREATE
|
ChatMsg,
|
||||||
|
CharacterNoRecordMessage,
|
||||||
|
CharacterInfoMessage,
|
||||||
|
UnknownMessage21, // PPT_DISCONNECT
|
||||||
|
BindPlayerMessage,
|
||||||
|
ObjectCreateMessage_Duplicate, // PPT_OBJECTCREATE
|
||||||
// 0x18
|
// 0x18
|
||||||
ObjectCreateMessage, // PPT_OBJECTCREATEDETAILED
|
ObjectCreateMessage, // PPT_OBJECTCREATEDETAILED
|
||||||
ObjectDeleteMessage, PingMsg, VehicleStateMessage, FrameVehicleStateMessage, GenericObjectStateMsg,
|
ObjectDeleteMessage,
|
||||||
ChildObjectStateMessage, ActionResultMessage,
|
PingMsg,
|
||||||
|
VehicleStateMessage,
|
||||||
|
FrameVehicleStateMessage,
|
||||||
|
GenericObjectStateMsg,
|
||||||
|
ChildObjectStateMessage,
|
||||||
|
ActionResultMessage,
|
||||||
// OPCODES 0x20-2f
|
// OPCODES 0x20-2f
|
||||||
UnknownMessage32, // PPT_ACTIONBEGIN
|
UnknownMessage32, // PPT_ACTIONBEGIN
|
||||||
ActionProgressMessage, ActionCancelMessage, ActionCancelAcknowledgeMessage, SetEmpireMessage, EmoteMsg,
|
ActionProgressMessage,
|
||||||
UnuseItemMessage, ObjectDetachMessage,
|
ActionCancelMessage,
|
||||||
|
ActionCancelAcknowledgeMessage,
|
||||||
|
SetEmpireMessage,
|
||||||
|
EmoteMsg,
|
||||||
|
UnuseItemMessage,
|
||||||
|
ObjectDetachMessage,
|
||||||
// 0x28
|
// 0x28
|
||||||
CreateShortcutMessage, ChangeShortcutBankMessage, ObjectAttachMessage, UnknownMessage43, // PPT_OBJECTEMPTY
|
CreateShortcutMessage,
|
||||||
PlanetsideAttributeMessage, RequestDestroyMessage, UnknownMessage46, // PPT_EQUIPITEM
|
ChangeShortcutBankMessage,
|
||||||
|
ObjectAttachMessage,
|
||||||
|
UnknownMessage43, // PPT_OBJECTEMPTY
|
||||||
|
PlanetsideAttributeMessage,
|
||||||
|
RequestDestroyMessage,
|
||||||
|
UnknownMessage46, // PPT_EQUIPITEM
|
||||||
CharacterCreateRequestMessage,
|
CharacterCreateRequestMessage,
|
||||||
// OPCODES 0x30-3f
|
// OPCODES 0x30-3f
|
||||||
CharacterRequestMessage, LoadMapMessage, SetCurrentAvatarMessage, ObjectHeldMessage, WeaponFireMessage,
|
CharacterRequestMessage,
|
||||||
AvatarJumpMessage, PickupItemMessage, DropItemMessage,
|
LoadMapMessage,
|
||||||
|
SetCurrentAvatarMessage,
|
||||||
|
ObjectHeldMessage,
|
||||||
|
WeaponFireMessage,
|
||||||
|
AvatarJumpMessage,
|
||||||
|
PickupItemMessage,
|
||||||
|
DropItemMessage,
|
||||||
// 0x38
|
// 0x38
|
||||||
InventoryStateMessage, ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, UnknownMessage59,
|
InventoryStateMessage,
|
||||||
GenericCollisionMsg, QuantityUpdateMessage, ArmorChangedMessage, ProjectileStateMessage,
|
ChangeFireStateMessage_Start,
|
||||||
|
ChangeFireStateMessage_Stop,
|
||||||
|
UnknownMessage59,
|
||||||
|
GenericCollisionMsg,
|
||||||
|
QuantityUpdateMessage,
|
||||||
|
ArmorChangedMessage,
|
||||||
|
ProjectileStateMessage,
|
||||||
// OPCODES 0x40-4f
|
// OPCODES 0x40-4f
|
||||||
MountVehicleCargoMsg, DismountVehicleCargoMsg, CargoMountPointStatusMessage, BeginZoningMessage,
|
MountVehicleCargoMsg,
|
||||||
ItemTransactionMessage, ItemTransactionResultMessage, ChangeFireModeMessage, ChangeAmmoMessage,
|
DismountVehicleCargoMsg,
|
||||||
|
CargoMountPointStatusMessage,
|
||||||
|
BeginZoningMessage,
|
||||||
|
ItemTransactionMessage,
|
||||||
|
ItemTransactionResultMessage,
|
||||||
|
ChangeFireModeMessage,
|
||||||
|
ChangeAmmoMessage,
|
||||||
// 0x48
|
// 0x48
|
||||||
TimeOfDayMessage, UnknownMessage73, // PPT_PROJECTILE_EVENT_BLOCK
|
TimeOfDayMessage,
|
||||||
SpawnRequestMessage, DeployRequestMessage, UnknownMessage76, // PPT_BUILDINGSTATECHANGED
|
UnknownMessage73, // PPT_PROJECTILE_EVENT_BLOCK
|
||||||
RepairMessage, ServerVehicleOverrideMsg, LashMessage,
|
SpawnRequestMessage,
|
||||||
|
DeployRequestMessage,
|
||||||
|
UnknownMessage76, // PPT_BUILDINGSTATECHANGED
|
||||||
|
RepairMessage,
|
||||||
|
ServerVehicleOverrideMsg,
|
||||||
|
LashMessage,
|
||||||
// OPCODES 0x50-5f
|
// OPCODES 0x50-5f
|
||||||
TargetingInfoMessage, TriggerEffectMessage, WeaponDryFireMessage, DroppodLaunchRequestMessage, HackMessage,
|
TargetingInfoMessage,
|
||||||
DroppodLaunchResponseMessage, GenericObjectActionMessage, AvatarVehicleTimerMessage,
|
TriggerEffectMessage,
|
||||||
|
WeaponDryFireMessage,
|
||||||
|
DroppodLaunchRequestMessage,
|
||||||
|
HackMessage,
|
||||||
|
DroppodLaunchResponseMessage,
|
||||||
|
GenericObjectActionMessage,
|
||||||
|
AvatarVehicleTimerMessage,
|
||||||
// 0x58
|
// 0x58
|
||||||
AvatarImplantMessage, UnknownMessage89, // PPT_SEARCHMESSAGE
|
AvatarImplantMessage,
|
||||||
DelayedPathMountMsg, OrbitalShuttleTimeMsg, AIDamage, DeployObjectMessage, FavoritesRequest, FavoritesResponse,
|
UnknownMessage89, // PPT_SEARCHMESSAGE
|
||||||
|
DelayedPathMountMsg,
|
||||||
|
OrbitalShuttleTimeMsg,
|
||||||
|
AIDamage,
|
||||||
|
DeployObjectMessage,
|
||||||
|
FavoritesRequest,
|
||||||
|
FavoritesResponse,
|
||||||
// OPCODES 0x60-6f
|
// OPCODES 0x60-6f
|
||||||
FavoritesMessage, ObjectDetectedMessage, SplashHitMessage, SetChatFilterMessage, AvatarSearchCriteriaMessage,
|
FavoritesMessage,
|
||||||
AvatarSearchResponse, WeaponJammedMessage, LinkDeadAwarenessMsg,
|
ObjectDetectedMessage,
|
||||||
|
SplashHitMessage,
|
||||||
|
SetChatFilterMessage,
|
||||||
|
AvatarSearchCriteriaMessage,
|
||||||
|
AvatarSearchResponse,
|
||||||
|
WeaponJammedMessage,
|
||||||
|
LinkDeadAwarenessMsg,
|
||||||
// 0x68
|
// 0x68
|
||||||
DroppodFreefallingMessage, AvatarFirstTimeEventMessage, AggravatedDamageMessage, TriggerSoundMessage, LootItemMessage,
|
DroppodFreefallingMessage,
|
||||||
VehicleSubStateMessage, SquadMembershipRequest, SquadMembershipResponse,
|
AvatarFirstTimeEventMessage,
|
||||||
|
AggravatedDamageMessage,
|
||||||
|
TriggerSoundMessage,
|
||||||
|
LootItemMessage,
|
||||||
|
VehicleSubStateMessage,
|
||||||
|
SquadMembershipRequest,
|
||||||
|
SquadMembershipResponse,
|
||||||
// OPCODES 0x70-7f
|
// OPCODES 0x70-7f
|
||||||
SquadMemberEvent, PlatoonEvent, FriendsRequest, FriendsResponse, TriggerEnvironmentalDamageMessage,
|
SquadMemberEvent,
|
||||||
TrainingZoneMessage, DeployableObjectsInfoMessage, SquadState,
|
PlatoonEvent,
|
||||||
|
FriendsRequest,
|
||||||
|
FriendsResponse,
|
||||||
|
TriggerEnvironmentalDamageMessage,
|
||||||
|
TrainingZoneMessage,
|
||||||
|
DeployableObjectsInfoMessage,
|
||||||
|
SquadState,
|
||||||
// 0x78
|
// 0x78
|
||||||
OxygenStateMessage, TradeMessage, UnknownMessage122, DamageFeedbackMessage, DismountBuildingMsg,
|
OxygenStateMessage,
|
||||||
UnknownMessage125, // PPT_MOUNTBUILDING
|
TradeMessage,
|
||||||
UnknownMessage126, // PPT_INTENDEDDROPZONE
|
UnknownMessage122,
|
||||||
|
DamageFeedbackMessage,
|
||||||
|
DismountBuildingMsg,
|
||||||
|
UnknownMessage125, // PPT_MOUNTBUILDING
|
||||||
|
UnknownMessage126, // PPT_INTENDEDDROPZONE
|
||||||
AvatarStatisticsMessage,
|
AvatarStatisticsMessage,
|
||||||
// OPCODES 0x80-8f
|
// OPCODES 0x80-8f
|
||||||
GenericObjectAction2Message, DestroyDisplayMessage, TriggerBotAction, SquadWaypointRequest, SquadWaypointEvent,
|
GenericObjectAction2Message,
|
||||||
OffshoreVehicleMessage, ObjectDeployedMessage, ObjectDeployedCountMessage,
|
DestroyDisplayMessage,
|
||||||
|
TriggerBotAction,
|
||||||
|
SquadWaypointRequest,
|
||||||
|
SquadWaypointEvent,
|
||||||
|
OffshoreVehicleMessage,
|
||||||
|
ObjectDeployedMessage,
|
||||||
|
ObjectDeployedCountMessage,
|
||||||
// 0x88
|
// 0x88
|
||||||
WeaponDelayFireMessage, BugReportMessage, PlayerStasisMessage, UnknownMessage139, OutfitMembershipRequest,
|
WeaponDelayFireMessage,
|
||||||
OutfitMembershipResponse, OutfitRequest, OutfitEvent,
|
BugReportMessage,
|
||||||
|
PlayerStasisMessage,
|
||||||
|
UnknownMessage139,
|
||||||
|
OutfitMembershipRequest,
|
||||||
|
OutfitMembershipResponse,
|
||||||
|
OutfitRequest,
|
||||||
|
OutfitEvent,
|
||||||
// OPCODES 0x90-9f
|
// OPCODES 0x90-9f
|
||||||
OutfitMemberEvent, OutfitMemberUpdate, PlanetsideStringAttributeMessage, DataChallengeMessage,
|
OutfitMemberEvent,
|
||||||
DataChallengeMessageResp, WeatherMessage, SimDataChallenge, SimDataChallengeResp,
|
OutfitMemberUpdate,
|
||||||
|
PlanetsideStringAttributeMessage,
|
||||||
|
DataChallengeMessage,
|
||||||
|
DataChallengeMessageResp,
|
||||||
|
WeatherMessage,
|
||||||
|
SimDataChallenge,
|
||||||
|
SimDataChallengeResp,
|
||||||
// 0x98
|
// 0x98
|
||||||
OutfitListEvent, EmpireIncentivesMessage, InvalidTerrainMessage, SyncMessage, DebugDrawMessage, SoulMarkMessage,
|
OutfitListEvent,
|
||||||
UplinkPositionEvent, HotSpotUpdateMessage,
|
EmpireIncentivesMessage,
|
||||||
|
InvalidTerrainMessage,
|
||||||
|
SyncMessage,
|
||||||
|
DebugDrawMessage,
|
||||||
|
SoulMarkMessage,
|
||||||
|
UplinkPositionEvent,
|
||||||
|
HotSpotUpdateMessage,
|
||||||
// OPCODES 0xa0-af
|
// OPCODES 0xa0-af
|
||||||
BuildingInfoUpdateMessage, FireHintMessage, UplinkRequest, UplinkResponse, WarpgateRequest, WarpgateResponse,
|
BuildingInfoUpdateMessage,
|
||||||
DamageWithPositionMessage, GenericActionMessage,
|
FireHintMessage,
|
||||||
|
UplinkRequest,
|
||||||
|
UplinkResponse,
|
||||||
|
WarpgateRequest,
|
||||||
|
WarpgateResponse,
|
||||||
|
DamageWithPositionMessage,
|
||||||
|
GenericActionMessage,
|
||||||
// 0xa8
|
// 0xa8
|
||||||
ContinentalLockUpdateMessage, AvatarGrenadeStateMessage, UnknownMessage170, UnknownMessage171,
|
ContinentalLockUpdateMessage,
|
||||||
ReleaseAvatarRequestMessage, AvatarDeadStateMessage, CSAssistMessage, CSAssistCommentMessage,
|
AvatarGrenadeStateMessage,
|
||||||
|
UnknownMessage170,
|
||||||
|
UnknownMessage171,
|
||||||
|
ReleaseAvatarRequestMessage,
|
||||||
|
AvatarDeadStateMessage,
|
||||||
|
CSAssistMessage,
|
||||||
|
CSAssistCommentMessage,
|
||||||
// OPCODES 0xb0-bf
|
// OPCODES 0xb0-bf
|
||||||
VoiceHostRequest, VoiceHostKill, VoiceHostInfo, BattleplanMessage, BattleExperienceMessage, TargetingImplantRequest,
|
VoiceHostRequest,
|
||||||
ZonePopulationUpdateMessage, DisconnectMessage,
|
VoiceHostKill,
|
||||||
|
VoiceHostInfo,
|
||||||
|
BattleplanMessage,
|
||||||
|
BattleExperienceMessage,
|
||||||
|
TargetingImplantRequest,
|
||||||
|
ZonePopulationUpdateMessage,
|
||||||
|
DisconnectMessage,
|
||||||
// 0xb8
|
// 0xb8
|
||||||
ExperienceAddedMessage, OrbitalStrikeWaypointMessage, KeepAliveMessage, MapObjectStateBlockMessage, SnoopMsg,
|
ExperienceAddedMessage,
|
||||||
PlayerStateMessageUpstream, PlayerStateShiftMessage, ZipLineMessage,
|
OrbitalStrikeWaypointMessage,
|
||||||
|
KeepAliveMessage,
|
||||||
|
MapObjectStateBlockMessage,
|
||||||
|
SnoopMsg,
|
||||||
|
PlayerStateMessageUpstream,
|
||||||
|
PlayerStateShiftMessage,
|
||||||
|
ZipLineMessage,
|
||||||
// OPCODES 0xc0-cf
|
// OPCODES 0xc0-cf
|
||||||
CaptureFlagUpdateMessage, VanuModuleUpdateMessage, FacilityBenefitShieldChargeRequestMessage,
|
CaptureFlagUpdateMessage,
|
||||||
ProximityTerminalUseMessage, QuantityDeltaUpdateMessage, ChainLashMessage, ZoneInfoMessage,
|
VanuModuleUpdateMessage,
|
||||||
LongRangeProjectileInfoMessage,
|
FacilityBenefitShieldChargeRequestMessage,
|
||||||
|
ProximityTerminalUseMessage,
|
||||||
|
QuantityDeltaUpdateMessage,
|
||||||
|
ChainLashMessage,
|
||||||
|
ZoneInfoMessage,
|
||||||
|
LongRangeProjectileInfoMessage,
|
||||||
// 0xc8
|
// 0xc8
|
||||||
WeaponLazeTargetPositionMessage, ModuleLimitsMessage, OutfitBenefitMessage, EmpireChangeTimeMessage,
|
WeaponLazeTargetPositionMessage,
|
||||||
ClockCalibrationMessage, DensityLevelUpdateMessage, ActOfGodMessage, AvatarAwardMessage,
|
ModuleLimitsMessage,
|
||||||
|
OutfitBenefitMessage,
|
||||||
|
EmpireChangeTimeMessage,
|
||||||
|
ClockCalibrationMessage,
|
||||||
|
DensityLevelUpdateMessage,
|
||||||
|
ActOfGodMessage,
|
||||||
|
AvatarAwardMessage,
|
||||||
// OPCODES 0xd0-df
|
// OPCODES 0xd0-df
|
||||||
UnknownMessage208, DisplayedAwardMessage, RespawnAMSInfoMessage, ComponentDamageMessage,
|
UnknownMessage208,
|
||||||
GenericObjectActionAtPositionMessage, PropertyOverrideMessage, WarpgateLinkOverrideMessage, EmpireBenefitsMessage,
|
DisplayedAwardMessage,
|
||||||
|
RespawnAMSInfoMessage,
|
||||||
|
ComponentDamageMessage,
|
||||||
|
GenericObjectActionAtPositionMessage,
|
||||||
|
PropertyOverrideMessage,
|
||||||
|
WarpgateLinkOverrideMessage,
|
||||||
|
EmpireBenefitsMessage,
|
||||||
// 0xd8
|
// 0xd8
|
||||||
ForceEmpireMessage, BroadcastWarpgateUpdateMessage, UnknownMessage218, SquadMainTerminalMessage,
|
ForceEmpireMessage,
|
||||||
SquadMainTerminalResponseMessage, SquadOrderMessage, SquadOrderResponse, ZoneLockInfoMessage,
|
BroadcastWarpgateUpdateMessage,
|
||||||
|
UnknownMessage218,
|
||||||
|
SquadMainTerminalMessage,
|
||||||
|
SquadMainTerminalResponseMessage,
|
||||||
|
SquadOrderMessage,
|
||||||
|
SquadOrderResponse,
|
||||||
|
ZoneLockInfoMessage,
|
||||||
// OPCODES 0xe0-ef
|
// OPCODES 0xe0-ef
|
||||||
SquadBindInfoMessage, AudioSequenceMessage, SquadFacilityBindInfoMessage, ZoneForcedCavernConnectionsMessage,
|
SquadBindInfoMessage,
|
||||||
MissionActionMessage, MissionKillTriggerMessage, ReplicationStreamMessage, SquadDefinitionActionMessage,
|
AudioSequenceMessage,
|
||||||
|
SquadFacilityBindInfoMessage,
|
||||||
|
ZoneForcedCavernConnectionsMessage,
|
||||||
|
MissionActionMessage,
|
||||||
|
MissionKillTriggerMessage,
|
||||||
|
ReplicationStreamMessage,
|
||||||
|
SquadDefinitionActionMessage,
|
||||||
// 0xe8
|
// 0xe8
|
||||||
SquadDetailDefinitionUpdateMessage, TacticsMessage, RabbitUpdateMessage, SquadInvitationRequestMessage,
|
SquadDetailDefinitionUpdateMessage,
|
||||||
CharacterKnowledgeMessage, GameScoreUpdateMessage, UnknownMessage238, OrderTerminalBugMessage,
|
TacticsMessage,
|
||||||
|
RabbitUpdateMessage,
|
||||||
|
SquadInvitationRequestMessage,
|
||||||
|
CharacterKnowledgeMessage,
|
||||||
|
GameScoreUpdateMessage,
|
||||||
|
UnknownMessage238,
|
||||||
|
OrderTerminalBugMessage,
|
||||||
// OPCODES 0xf0-f3
|
// OPCODES 0xf0-f3
|
||||||
QueueTimedHelpMessage, MailMessage, GameVarUpdate, ClientCheatedMessage // last known message type (243, 0xf3)
|
QueueTimedHelpMessage,
|
||||||
|
MailMessage,
|
||||||
|
GameVarUpdate,
|
||||||
|
ClientCheatedMessage // last known message type (243, 0xf3)
|
||||||
= Value
|
= Value
|
||||||
|
|
||||||
private def noDecoder(opcode: GamePacketOpcode.Type) =
|
private def noDecoder(opcode: GamePacketOpcode.Type) =
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package net.psforever.util
|
||||||
import net.psforever.objects.definition.BasicDefinition
|
import net.psforever.objects.definition.BasicDefinition
|
||||||
import net.psforever.objects.{AmmoBox, GlobalDefinitions, Player, SimpleItem, Tool}
|
import net.psforever.objects.{AmmoBox, GlobalDefinitions, Player, SimpleItem, Tool}
|
||||||
import net.psforever.types.ExoSuitType
|
import net.psforever.types.ExoSuitType
|
||||||
|
|
||||||
import scala.reflect.runtime.universe
|
import scala.reflect.runtime.universe
|
||||||
|
|
||||||
// TODO definitions should be in an iterable format
|
// TODO definitions should be in an iterable format
|
||||||
|
|
@ -225,10 +226,10 @@ object DefinitionUtil {
|
||||||
def applyDefaultLoadout(player: Player): Unit = {
|
def applyDefaultLoadout(player: Player): Unit = {
|
||||||
val faction = player.Faction
|
val faction = player.Faction
|
||||||
player.ExoSuit = ExoSuitType.Standard
|
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(2).Equipment = Tool(GlobalDefinitions.suppressor)
|
||||||
player.Slot(4).Equipment = Tool(GlobalDefinitions.StandardMelee(faction))
|
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(9).Equipment = AmmoBox(GlobalDefinitions.bullet_9mm)
|
||||||
player.Slot(12).Equipment = AmmoBox(GlobalDefinitions.bullet_9mm)
|
player.Slot(12).Equipment = AmmoBox(GlobalDefinitions.bullet_9mm)
|
||||||
player.Slot(33).Equipment = AmmoBox(GlobalDefinitions.bullet_9mm_AP)
|
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.definition.ToolDefinition
|
||||||
import net.psforever.objects.{GlobalDefinitions, Tool}
|
import net.psforever.objects.{GlobalDefinitions, Tool}
|
||||||
import net.psforever.objects.equipment.{
|
import net.psforever.objects.equipment._
|
||||||
EquipmentSize,
|
|
||||||
FireModeDefinition,
|
|
||||||
InfiniteFireModeDefinition,
|
|
||||||
PelletFireModeDefinition
|
|
||||||
}
|
|
||||||
import org.specs2.mutable._
|
import org.specs2.mutable._
|
||||||
|
|
||||||
class FireModeTest extends Specification {
|
class FireModeTest extends Specification {
|
||||||
|
|
@ -129,4 +124,32 @@ class FireModeTest extends Specification {
|
||||||
obj.Magazine mustEqual 1
|
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.InitialVelocity mustEqual 1
|
||||||
obj.Lifespan mustEqual 1f
|
obj.Lifespan mustEqual 1f
|
||||||
obj.DamageAtEdge mustEqual 1f
|
obj.DamageAtEdge mustEqual 1f
|
||||||
obj.DamageRadius mustEqual 1f
|
obj.DamageRadius mustEqual 0f
|
||||||
obj.UseDamage1Subtract mustEqual false
|
obj.UseDamage1Subtract mustEqual false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -269,7 +269,7 @@ class ProjectileTest extends Specification {
|
||||||
obj.attribute_to mustEqual obj.tool_def.ObjectId
|
obj.attribute_to mustEqual obj.tool_def.ObjectId
|
||||||
obj.shot_origin mustEqual Vector3(1.2f, 3.4f, 5.6f)
|
obj.shot_origin mustEqual Vector3(1.2f, 3.4f, 5.6f)
|
||||||
obj.shot_angle mustEqual Vector3(0.2f, 0.4f, 0.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
|
obj.isResolved mustEqual false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue