mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-01-21 02:54:44 +00:00
commit
cfeb9afb6f
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects
|
||||
|
||||
import akka.actor.ActorContext
|
||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||
import net.psforever.types.PlanetSideEmpire
|
||||
|
||||
/**
|
||||
* A `LocalProjectile` is a server-side object designed to populate a fake shared space.
|
||||
* It is a placeholder intended to block out the existence of projectiles communicated from clients.
|
||||
* All clients reserve the same internal range of user-generated GUID's from 40100 to 40124, inclusive.
|
||||
* All clients recognize this same range independent of each other as "their own featureless projectiles."
|
||||
* @see `Zone.MakeReservedObjects`<br>
|
||||
* `Projectile.BaseUID`<br>
|
||||
* `Projectile.RangeUID`
|
||||
*/
|
||||
class LocalProjectile extends PlanetSideServerObject {
|
||||
def Faction = PlanetSideEmpire.NEUTRAL
|
||||
|
||||
def Definition = LocalProjectile.local
|
||||
}
|
||||
|
||||
object LocalProjectile {
|
||||
import net.psforever.objects.definition.ObjectDefinition
|
||||
def local = new ObjectDefinition(0) { Name = "projectile" }
|
||||
|
||||
/**
|
||||
* Instantiate and configure a `LocalProjectile` object.
|
||||
* @param id the unique id that will be assigned to this entity
|
||||
* @param context a context to allow the object to properly set up `ActorSystem` functionality
|
||||
* @return the `LocalProjectile` object
|
||||
*/
|
||||
def Constructor(id : Int, context : ActorContext) : LocalProjectile = {
|
||||
new LocalProjectile()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects
|
||||
|
||||
import net.psforever.objects.definition.{AmmoBoxDefinition, ToolDefinition}
|
||||
import net.psforever.objects.equipment.{Ammo, Equipment, FireModeDefinition, FireModeSwitch}
|
||||
import net.psforever.objects.definition.{AmmoBoxDefinition, ProjectileDefinition, ToolDefinition}
|
||||
import net.psforever.objects.equipment._
|
||||
import net.psforever.objects.ballistics.Projectiles
|
||||
|
||||
import scala.annotation.tailrec
|
||||
|
||||
|
|
@ -59,6 +60,20 @@ class Tool(private val toolDef : ToolDefinition) extends Equipment with FireMode
|
|||
AmmoType
|
||||
}
|
||||
|
||||
def Projectile : ProjectileDefinition = {
|
||||
toolDef.ProjectileTypes({
|
||||
val projIndices = FireMode.ProjectileTypeIndices
|
||||
if(projIndices.isEmpty) {
|
||||
AmmoTypeIndex //e.g., bullet_9mm -> bullet_9mm_projectile, bullet_9mm_AP -> bullet_9mm_AP_projectile
|
||||
}
|
||||
else {
|
||||
projIndices(AmmoSlot.AmmoTypeIndex) //e.g., pulsar: f.mode1 -> pulsar_projectile, f.mode2 = pulsar_ap_projectile
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
def ProjectileType : Projectiles.Value = Projectile.ProjectileType
|
||||
|
||||
def Magazine : Int = AmmoSlot.Magazine
|
||||
|
||||
def Magazine_=(mag : Int) : Int = {
|
||||
|
|
|
|||
|
|
@ -323,13 +323,12 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideServ
|
|||
Some(AccessPermissionGroup.Passenger)
|
||||
}
|
||||
case None =>
|
||||
None
|
||||
}
|
||||
CargoHold(seatNumber) match {
|
||||
case Some(_) =>
|
||||
Some(AccessPermissionGroup.Passenger)
|
||||
case None =>
|
||||
None
|
||||
CargoHold(seatNumber) match {
|
||||
case Some(_) =>
|
||||
Some(AccessPermissionGroup.Passenger)
|
||||
case None =>
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.ballistics
|
||||
|
||||
/**
|
||||
* The different values for five common types of damage that can be dealt, based on target and application.
|
||||
* In the same way, the five damage modifiers that are applied to the same kind of damage.
|
||||
*/
|
||||
trait DamageProfile {
|
||||
def Damage0 : Int
|
||||
|
||||
def Damage0_=(damage : Int) : Int
|
||||
|
||||
def Damage1 : Int
|
||||
|
||||
def Damage1_=(damage : Int) : Int
|
||||
|
||||
def Damage2 : Int
|
||||
|
||||
def Damage2_=(damage : Int) : Int
|
||||
|
||||
def Damage3 : Int
|
||||
|
||||
def Damage3_=(damage : Int) : Int
|
||||
|
||||
def Damage4 : Int
|
||||
|
||||
def Damage4_=(damage : Int) : Int
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.ballistics
|
||||
|
||||
/**
|
||||
* An `Enumeration` of the damage type.
|
||||
* These types are not necessarily representative of the kind of projectile being used;
|
||||
* for example, the bolt driver's `bolt` is considered "splash."
|
||||
*/
|
||||
object DamageType extends Enumeration(1) {
|
||||
type Type = Value
|
||||
|
||||
final val Direct,
|
||||
Splash,
|
||||
Radiation,
|
||||
Aggravated,
|
||||
Plasma,
|
||||
Comet,
|
||||
None = Value
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.ballistics
|
||||
|
||||
import net.psforever.objects.definition.{ProjectileDefinition, ToolDefinition}
|
||||
import net.psforever.objects.entity.SimpleWorldEntity
|
||||
import net.psforever.types.Vector3
|
||||
|
||||
/**
|
||||
* A summation of weapon (`Tool`) discharge.
|
||||
* @param profile an explanation of the damage that can be performed by this discharge
|
||||
* @param tool_def the weapon that caused this discharge
|
||||
* @param shot_origin where the projectile started
|
||||
* @param shot_angle in which direction the projectile was aimed when it was discharged
|
||||
* @param resolution whether this projectile has encountered a target or wall;
|
||||
* defaults to `Unresolved`
|
||||
* @param fire_time when the weapon discharged was recorded;
|
||||
* defaults to `System.nanoTime`
|
||||
* @param hit_time when the discharge had its resolution status updated
|
||||
*/
|
||||
final case class Projectile(profile : ProjectileDefinition,
|
||||
tool_def : ToolDefinition,
|
||||
shot_origin : Vector3,
|
||||
shot_angle : Vector3,
|
||||
resolution : ProjectileResolution.Value,
|
||||
fire_time : Long = System.nanoTime,
|
||||
hit_time : Long = 0) {
|
||||
/** Information about the current world coordinates and orientation of the projectile */
|
||||
val current : SimpleWorldEntity = new SimpleWorldEntity()
|
||||
|
||||
/**
|
||||
* Give the projectile the suggested resolution status.
|
||||
* Update the world coordinates and orientation.
|
||||
* @param pos the current position
|
||||
* @param ang the current orientation
|
||||
* @param resolution the resolution status
|
||||
* @return a new projectile with the suggested resolution status, or the original projectile
|
||||
*/
|
||||
def Resolve(pos : Vector3, ang : Vector3, resolution : ProjectileResolution.Value) : Projectile = {
|
||||
val obj = Resolve(resolution)
|
||||
obj.current.Position = pos
|
||||
obj.current.Orientation = ang
|
||||
obj
|
||||
}
|
||||
|
||||
/**
|
||||
* Give the projectile the suggested resolution status.
|
||||
* @param resolution the resolution status
|
||||
* @return a new projectile with the suggested resolution status, or the original projectile
|
||||
*/
|
||||
def Resolve(resolution : ProjectileResolution.Value) : Projectile = {
|
||||
resolution match {
|
||||
case ProjectileResolution.Unresolved =>
|
||||
this
|
||||
case _ =>
|
||||
Projectile(profile, tool_def, shot_origin, shot_angle, resolution, fire_time, System.nanoTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object Projectile {
|
||||
/** the first projectile GUID used by all clients internally */
|
||||
final val BaseUID : Int = 40100
|
||||
/** all clients progress through 40100 to 40124 normally, skipping only for long-lived projectiles
|
||||
* 40125 to 40149 are being reserved as a guard against undetected overflow */
|
||||
final val RangeUID : Int = 40150
|
||||
|
||||
/**
|
||||
* Overloaded constructor for an `Unresolved` projectile.
|
||||
* @param profile an explanation of the damage that can be performed by this discharge
|
||||
* @param tool_def the weapon that caused this discharge
|
||||
* @param shot_origin where the projectile started
|
||||
* @param shot_angle in which direction the projectile was aimed when it was discharged
|
||||
* @return the `Projectile` object
|
||||
*/
|
||||
def apply(profile : ProjectileDefinition, tool_def : ToolDefinition, shot_origin : Vector3, shot_angle : Vector3) : Projectile = {
|
||||
Projectile(profile, tool_def, shot_origin, shot_angle, ProjectileResolution.Unresolved)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.ballistics
|
||||
|
||||
/**
|
||||
* An `Enumeration` of outcomes regarding what actually happened to the projectile.
|
||||
*/
|
||||
object ProjectileResolution extends Enumeration {
|
||||
type Type = Value
|
||||
|
||||
val
|
||||
Unresolved, //original basic non-resolution
|
||||
MissedShot, //projectile did not encounter any collision object and was despawned
|
||||
Resolved, //a general "projectile encountered something" status with a more specific resolution
|
||||
Hit, //direct hit, one target
|
||||
Splash, //area of effect damage, potentially multiple targets
|
||||
Lash //lashing damage, potentially multiple targets
|
||||
= Value
|
||||
}
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.ballistics
|
||||
|
||||
/**
|
||||
* An `Enumeration` of all the projectile types in the game, paired with their object id as the `Value`.
|
||||
*/
|
||||
object Projectiles extends Enumeration {
|
||||
final val bullet_105mm_projectile = Value(1)
|
||||
final val bullet_12mm_projectile = Value(4)
|
||||
final val bullet_12mm_projectileb = Value(5)
|
||||
final val bullet_150mm_projectile = Value(7)
|
||||
final val bullet_15mm_apc_projectile = Value(10)
|
||||
final val bullet_15mm_projectile = Value(11)
|
||||
final val bullet_20mm_apc_projectile = Value(17)
|
||||
final val bullet_20mm_projectile = Value(18)
|
||||
final val bullet_25mm_projectile = Value(20)
|
||||
final val bullet_35mm_projectile = Value(22)
|
||||
final val bullet_75mm_apc_projectile = Value(26)
|
||||
final val bullet_75mm_projectile = Value(27)
|
||||
final val bullet_9mm_AP_projectile = Value(30)
|
||||
final val bullet_9mm_projectile = Value(31)
|
||||
final val anniversary_projectilea = Value(58)
|
||||
final val anniversary_projectileb = Value(59)
|
||||
final val aphelion_immolation_cannon_projectile = Value(87)
|
||||
final val aphelion_laser_projectile = Value(91)
|
||||
final val aphelion_plasma_rocket_projectile = Value(99)
|
||||
final val aphelion_ppa_projectile = Value(103)
|
||||
final val aphelion_starfire_projectile = Value(108)
|
||||
final val bolt_projectile = Value(147)
|
||||
final val burster_projectile = Value(155)
|
||||
final val chainblade_projectile = Value(176)
|
||||
final val colossus_100mm_projectile = Value(181)
|
||||
final val colossus_burster_projectile = Value(188)
|
||||
final val colossus_chaingun_projectile = Value(193)
|
||||
final val colossus_cluster_bomb_projectile = Value(197)
|
||||
final val colossus_tank_cannon_projectile = Value(207)
|
||||
final val comet_projectile = Value(210)
|
||||
final val dualcycler_projectile = Value(266)
|
||||
final val dynomite_projectile = Value(268)
|
||||
final val energy_cell_projectile = Value(273)
|
||||
final val energy_gun_nc_projectile = Value(277)
|
||||
final val energy_gun_tr_projectile = Value(279)
|
||||
final val energy_gun_vs_projectile = Value(281)
|
||||
final val enhanced_energy_cell_projectile = Value(282)
|
||||
final val enhanced_quasar_projectile = Value(283)
|
||||
final val falcon_projectile = Value(286)
|
||||
final val firebird_missile_projectile = Value(288)
|
||||
final val flail_projectile = Value(296)
|
||||
final val flamethrower_fireball = Value(302)
|
||||
final val flamethrower_projectile = Value(303)
|
||||
final val flux_cannon_apc_projectile = Value(305)
|
||||
final val flux_cannon_thresher_projectile = Value(308)
|
||||
final val fluxpod_projectile = Value(311)
|
||||
final val forceblade_projectile = Value(325)
|
||||
final val frag_cartridge_projectile = Value(328)
|
||||
final val frag_cartridge_projectile_b = Value(329)
|
||||
final val frag_grenade_projectile = Value(332)
|
||||
final val frag_grenade_projectile_enh = Value(333)
|
||||
final val galaxy_gunship_gun_projectile = Value(341)
|
||||
final val gauss_cannon_projectile = Value(348)
|
||||
final val grenade_projectile = Value(372)
|
||||
final val heavy_grenade_projectile = Value(392)
|
||||
final val heavy_rail_beam_projectile = Value(395)
|
||||
final val heavy_sniper_projectile = Value(397)
|
||||
final val hellfire_projectile = Value(400)
|
||||
final val hunter_seeker_missile_dumbfire = Value(404)
|
||||
final val hunter_seeker_missile_projectile = Value(405)
|
||||
final val jammer_cartridge_projectile = Value(414)
|
||||
final val jammer_cartridge_projectile_b = Value(415)
|
||||
final val jammer_grenade_projectile = Value(418)
|
||||
final val jammer_grenade_projectile_enh = Value(419)
|
||||
final val katana_projectile = Value(422)
|
||||
final val katana_projectileb = Value(423)
|
||||
final val lancer_projectile = Value(427)
|
||||
final val lasher_projectile = Value(430)
|
||||
final val lasher_projectile_ap = Value(431)
|
||||
final val liberator_bomb_cluster_bomblet_projectile = Value(436)
|
||||
final val liberator_bomb_cluster_projectile = Value(437)
|
||||
final val liberator_bomb_projectile = Value(438)
|
||||
final val maelstrom_grenade_projectile = Value(465)
|
||||
final val maelstrom_grenade_projectile_contact = Value(466)
|
||||
final val maelstrom_stream_projectile = Value(467)
|
||||
final val magcutter_projectile = Value(469)
|
||||
final val melee_ammo_projectile = Value(541)
|
||||
final val meteor_common = Value(543)
|
||||
final val meteor_projectile_b_large = Value(544)
|
||||
final val meteor_projectile_b_medium = Value(545)
|
||||
final val meteor_projectile_b_small = Value(546)
|
||||
final val meteor_projectile_large = Value(547)
|
||||
final val meteor_projectile_medium = Value(548)
|
||||
final val meteor_projectile_small = Value(549)
|
||||
final val mine_projectile = Value(551)
|
||||
final val mine_sweeper_projectile = Value(554)
|
||||
final val mine_sweeper_projectile_enh = Value(555)
|
||||
final val oicw_projectile = Value(602)
|
||||
final val pellet_gun_projectile = Value(631)
|
||||
final val peregrine_dual_machine_gun_projectile = Value(639)
|
||||
final val peregrine_mechhammer_projectile = Value(647)
|
||||
final val peregrine_particle_cannon_projectile = Value(654)
|
||||
final val peregrine_rocket_pod_projectile = Value(657)
|
||||
final val peregrine_sparrow_projectile = Value(661)
|
||||
final val phalanx_av_projectile = Value(665)
|
||||
final val phalanx_flak_projectile = Value(667)
|
||||
final val phalanx_projectile = Value(669)
|
||||
final val phoenix_missile_guided_projectile = Value(675)
|
||||
final val phoenix_missile_projectile = Value(676)
|
||||
final val plasma_cartridge_projectile = Value(678)
|
||||
final val plasma_cartridge_projectile_b = Value(679)
|
||||
final val plasma_grenade_projectile = Value(682)
|
||||
final val plasma_grenade_projectile_B = Value(683)
|
||||
final val pounder_projectile = Value(694)
|
||||
final val pounder_projectile_enh = Value(695)
|
||||
final val ppa_projectile = Value(696)
|
||||
final val pulsar_ap_projectile = Value(702)
|
||||
final val pulsar_projectile = Value(703)
|
||||
final val quasar_projectile = Value(713)
|
||||
final val radiator_grenade_projectile = Value(718)
|
||||
final val radiator_sticky_projectile = Value(719)
|
||||
final val reaver_rocket_projectile = Value(723)
|
||||
final val rocket_projectile = Value(735)
|
||||
final val rocklet_flak_projectile = Value(738)
|
||||
final val rocklet_jammer_projectile = Value(739)
|
||||
final val scattercannon_projectile = Value(746)
|
||||
final val scythe_projectile = Value(748)
|
||||
final val scythe_projectile_slave = Value(749)
|
||||
final val shotgun_shell_AP_projectile = Value(757)
|
||||
final val shotgun_shell_projectile = Value(758)
|
||||
final val six_shooter_projectile = Value(763)
|
||||
final val skyguard_flak_cannon_projectile = Value(787)
|
||||
final val sparrow_projectile = Value(792)
|
||||
final val sparrow_secondary_projectile = Value(793)
|
||||
final val spiker_projectile = Value(818)
|
||||
final val spitfire_aa_ammo_projectile = Value(821)
|
||||
final val spitfire_ammo_projectile = Value(824)
|
||||
final val starfire_projectile = Value(831)
|
||||
final val striker_missile_projectile = Value(840)
|
||||
final val striker_missile_targeting_projectile = Value(841)
|
||||
final val trek_projectile = Value(878)
|
||||
final val vanu_sentry_turret_projectile = Value(944)
|
||||
final val vulture_bomb_projectile = Value(988)
|
||||
final val vulture_nose_bullet_projectile = Value(989)
|
||||
final val vulture_tail_bullet_projectile = Value(991)
|
||||
final val wasp_gun_projectile = Value(999)
|
||||
final val wasp_rocket_projectile = Value(1001)
|
||||
final val winchester_projectile = Value(1005)
|
||||
}
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.definition
|
||||
|
||||
import net.psforever.objects.ballistics.{DamageProfile, DamageType, Projectiles}
|
||||
|
||||
/**
|
||||
* The definition that outlines the damage-dealing characteristics of any projectile.
|
||||
* `Tool` objects emit `ProjectileDefinition` objects and that is later wrapped into a `Projectile` object.
|
||||
* @param objectId the object's identifier number
|
||||
*/
|
||||
class ProjectileDefinition(objectId : Int) extends ObjectDefinition(objectId) with DamageProfile {
|
||||
private val projectileType : Projectiles.Value = Projectiles(objectId) //let throw NoSuchElementException
|
||||
private var damage0 : Int = 0
|
||||
private var damage1 : Option[Int] = None
|
||||
private var damage2 : Option[Int] = None
|
||||
private var damage3 : Option[Int] = None
|
||||
private var damage4 : Option[Int] = None
|
||||
private var acceleration : Int = 0
|
||||
private var accelerationUntil : Float = 0f
|
||||
private var damageType : DamageType.Value = DamageType.None
|
||||
private var damageTypeSecondary : DamageType.Value = DamageType.None
|
||||
private var degradeDelay : Float = 1f
|
||||
private var degradeMultiplier : Float = 1f
|
||||
private var initialVelocity : Int = 1
|
||||
private var lifespan : Float = 1f
|
||||
private var damageAtEdge : Float = 1f
|
||||
private var damageRadius : Float = 1f
|
||||
private var useDamage1Subtract : Boolean = false
|
||||
Name = "projectile"
|
||||
|
||||
def ProjectileType : Projectiles.Value = projectileType
|
||||
|
||||
def UseDamage1Subtract : Boolean = useDamage1Subtract
|
||||
|
||||
def UseDamage1Subtract_=(useDamage1Subtract : Boolean) : Boolean = {
|
||||
this.useDamage1Subtract = useDamage1Subtract
|
||||
UseDamage1Subtract
|
||||
}
|
||||
|
||||
def Damage0 : Int = damage0
|
||||
|
||||
def Damage0_=(damage : Int) : Int = {
|
||||
damage0 = damage
|
||||
damage0
|
||||
}
|
||||
|
||||
def Damage0_=(damage : Option[Int]) : Int = {
|
||||
damage0 = damage match {
|
||||
case Some(value) => value
|
||||
case None => 0 //can not be set to None
|
||||
}
|
||||
Damage0
|
||||
}
|
||||
|
||||
def Damage1 : Int = damage1.getOrElse(Damage0)
|
||||
|
||||
def Damage1_=(damage : Int) : Int = Damage1_=(Some(damage))
|
||||
|
||||
def Damage1_=(damage : Option[Int]) : Int = {
|
||||
this.damage1 = damage
|
||||
Damage1
|
||||
}
|
||||
|
||||
def Damage2 : Int = damage2.getOrElse(Damage1)
|
||||
|
||||
def Damage2_=(damage : Int) : Int = Damage2_=(Some(damage))
|
||||
|
||||
def Damage2_=(damage : Option[Int]) : Int = {
|
||||
this.damage2 = damage
|
||||
Damage2
|
||||
}
|
||||
|
||||
def Damage3 : Int = damage3.getOrElse(Damage2)
|
||||
|
||||
def Damage3_=(damage : Int) : Int = Damage3_=(Some(damage))
|
||||
|
||||
def Damage3_=(damage : Option[Int]) : Int = {
|
||||
this.damage3 = damage
|
||||
Damage3
|
||||
}
|
||||
|
||||
def Damage4 : Int = damage4.getOrElse(Damage3)
|
||||
|
||||
def Damage4_=(damage : Int) : Int = Damage4_=(Some(damage))
|
||||
|
||||
def Damage4_=(damage : Option[Int]) : Int = {
|
||||
this.damage4 = damage
|
||||
Damage4
|
||||
}
|
||||
|
||||
def Acceleration : Int = acceleration
|
||||
|
||||
def Acceleration_=(accel : Int) : Int = {
|
||||
acceleration = accel
|
||||
Acceleration
|
||||
}
|
||||
|
||||
def AccelerationUntil : Float = accelerationUntil
|
||||
|
||||
def AccelerationUntil_=(accelUntil : Float) : Float = {
|
||||
accelerationUntil = accelUntil
|
||||
AccelerationUntil
|
||||
}
|
||||
|
||||
def ProjectileDamageType : DamageType.Value = damageType
|
||||
|
||||
def ProjectileDamageType_=(damageType1 : DamageType.Value) : DamageType.Value = {
|
||||
damageType = damageType1
|
||||
ProjectileDamageType
|
||||
}
|
||||
|
||||
def ProjectileDamageTypeSecondary : DamageType.Value = damageTypeSecondary
|
||||
|
||||
def ProjectileDamageTypeSecondary_=(damageTypeSecondary1 : DamageType.Value) : DamageType.Value = {
|
||||
damageTypeSecondary = damageTypeSecondary1
|
||||
ProjectileDamageTypeSecondary
|
||||
}
|
||||
|
||||
def DegradeDelay : Float = degradeDelay
|
||||
|
||||
def DegradeDelay_=(degradeDelay : Float) : Float = {
|
||||
this.degradeDelay = degradeDelay
|
||||
DegradeDelay
|
||||
}
|
||||
|
||||
def DegradeMultiplier : Float = degradeMultiplier
|
||||
|
||||
def DegradeMultiplier_=(degradeMultiplier : Float) : Float = {
|
||||
this.degradeMultiplier = degradeMultiplier
|
||||
DegradeMultiplier
|
||||
}
|
||||
|
||||
def InitialVelocity : Int = initialVelocity
|
||||
|
||||
def InitialVelocity_=(initialVelocity : Int) : Int = {
|
||||
this.initialVelocity = initialVelocity
|
||||
InitialVelocity
|
||||
}
|
||||
|
||||
def Lifespan : Float = lifespan
|
||||
|
||||
def Lifespan_=(lifespan : Float) : Float = {
|
||||
this.lifespan = lifespan
|
||||
Lifespan
|
||||
}
|
||||
|
||||
def DamageAtEdge : Float = damageAtEdge
|
||||
|
||||
def DamageAtEdge_=(damageAtEdge : Float) : Float = {
|
||||
this.damageAtEdge = damageAtEdge
|
||||
DamageAtEdge
|
||||
}
|
||||
|
||||
def DamageRadius : Float = damageRadius
|
||||
|
||||
def DamageRadius_=(damageRadius : Float) : Float = {
|
||||
this.damageRadius = damageRadius
|
||||
DamageRadius
|
||||
}
|
||||
}
|
||||
|
||||
object ProjectileDefinition {
|
||||
def apply(projectileType : Projectiles.Value) : ProjectileDefinition = {
|
||||
new ProjectileDefinition(projectileType.id)
|
||||
}
|
||||
}
|
||||
|
|
@ -8,12 +8,15 @@ import scala.collection.mutable
|
|||
|
||||
class ToolDefinition(objectId : Int) extends EquipmentDefinition(objectId) {
|
||||
private val ammoTypes : mutable.ListBuffer[AmmoBoxDefinition] = new mutable.ListBuffer[AmmoBoxDefinition]
|
||||
private val projectileTypes : mutable.ListBuffer[ProjectileDefinition] = new mutable.ListBuffer[ProjectileDefinition]
|
||||
private val fireModes : mutable.ListBuffer[FireModeDefinition] = new mutable.ListBuffer[FireModeDefinition]
|
||||
Name = "tool"
|
||||
Packet = ToolDefinition.converter
|
||||
|
||||
def AmmoTypes : mutable.ListBuffer[AmmoBoxDefinition] = ammoTypes
|
||||
|
||||
def ProjectileTypes : mutable.ListBuffer[ProjectileDefinition] = projectileTypes
|
||||
|
||||
def FireModes : mutable.ListBuffer[FireModeDefinition] = fireModes
|
||||
|
||||
def NextFireModeIndex(index : Int) : Int = index + 1
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ package net.psforever.objects.entity
|
|||
import net.psforever.types.Vector3
|
||||
|
||||
class SimpleWorldEntity extends WorldEntity {
|
||||
private var coords : Vector3 = Vector3(0f, 0f, 0f)
|
||||
private var orient : Vector3 = Vector3(0f, 0f, 0f)
|
||||
private var coords : Vector3 = Vector3.Zero
|
||||
private var orient : Vector3 = Vector3.Zero
|
||||
private var vel : Option[Vector3] = None
|
||||
|
||||
def Position : Vector3 = coords
|
||||
|
|
|
|||
|
|
@ -2,24 +2,30 @@
|
|||
package net.psforever.objects.equipment
|
||||
|
||||
import net.psforever.objects.Tool
|
||||
import net.psforever.objects.ballistics.DamageProfile
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
class FireModeDefinition {
|
||||
/** indices pointing to all ammo types used */
|
||||
/** indices pointing to all ammo types used, in (an) order
|
||||
* the ammo types list will be available from the `ToolDefinition` */
|
||||
private val ammoTypeIndices : mutable.ListBuffer[Int] = mutable.ListBuffer[Int]()
|
||||
/** custom indices pointing to the projectile type used for this mode's ammo types
|
||||
* for most weapon fire modes, this list will be empty and the projectile will align with the `ammoTypeIndex`
|
||||
* if at least one ammo type has a redirected projectile type, all projectiles must be defined for this mode */
|
||||
private val projectileTypeIndices : mutable.ListBuffer[Int] = mutable.ListBuffer[Int]()
|
||||
/** ammunition slot number this fire mode utilizes */
|
||||
private var ammoSlotIndex : Int = 0
|
||||
/** how many rounds are replenished each reload cycle */
|
||||
private var magazine : Int = 1
|
||||
/** how much is subtracted from the magazine each fire cycle;
|
||||
* most weapons will only fire 1 round per fire cycle; the flamethrower, fire mode 1, fires 50 */
|
||||
* most weapons will only fire 1 round per fire cycle; the flamethrower in fire mode 1 fires 50 */
|
||||
private var rounds : Int = 1
|
||||
/** how many sub-rounds are queued per round fired;
|
||||
* the flechette fires 8 pellets per shell and generates 8 fire reports before the ammo count goes down */
|
||||
private var chamber : Int = 1
|
||||
|
||||
//damage modifiers will follow here ... ?
|
||||
/** modifiers for each damage type */
|
||||
private val modifiers : DamageModifiers = new DamageModifiers
|
||||
|
||||
def AmmoSlotIndex : Int = ammoSlotIndex
|
||||
|
||||
|
|
@ -34,6 +40,12 @@ class FireModeDefinition {
|
|||
ammoTypeIndices += index
|
||||
}
|
||||
|
||||
def ProjectileTypeIndices : mutable.ListBuffer[Int] = projectileTypeIndices
|
||||
|
||||
def ProjectileTypeIndices_=(index : Int) : mutable.ListBuffer[Int] = {
|
||||
projectileTypeIndices += index
|
||||
}
|
||||
|
||||
def Magazine : Int = magazine
|
||||
|
||||
def Magazine_=(inMagazine : Int) : Int = {
|
||||
|
|
@ -55,6 +67,8 @@ class FireModeDefinition {
|
|||
Chamber
|
||||
}
|
||||
|
||||
def Modifiers : DamageModifiers = modifiers
|
||||
|
||||
/**
|
||||
* Shoot a weapon, remove an anticipated amount of ammunition.
|
||||
* @param weapon the weapon
|
||||
|
|
@ -105,3 +119,46 @@ class InfiniteFireModeDefinition extends FireModeDefinition {
|
|||
*/
|
||||
override def Discharge(weapon : Tool) : Int = 1
|
||||
}
|
||||
|
||||
class DamageModifiers 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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ package net.psforever.objects.zones
|
|||
|
||||
import akka.actor.{ActorContext, ActorRef, Props}
|
||||
import akka.routing.RandomPool
|
||||
import net.psforever.objects.{Avatar, PlanetSideGameObject, Player, Vehicle}
|
||||
import net.psforever.objects.ballistics.Projectile
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.objects.guid.NumberPoolHub
|
||||
import net.psforever.objects.guid.actor.UniqueNumberSystem
|
||||
|
|
@ -45,8 +46,6 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
|||
private var accessor : ActorRef = ActorRef.noSender
|
||||
/** The basic support structure for the globally unique number system used by this `Zone`. */
|
||||
private var guid : NumberPoolHub = new NumberPoolHub(new LimitedNumberSource(65536))
|
||||
guid.AddPool("environment", (0 to 3000).toList) //TODO tailer ro suit requirements of zone
|
||||
guid.AddPool("dynamic", (3001 to 10000).toList).Selector = new RandomSelector //TODO unlump pools later; do not make too big
|
||||
/** A synchronized `List` of items (`Equipment`) dropped by players on the ground and can be collected again. */
|
||||
private val equipmentOnGround : ListBuffer[Equipment] = ListBuffer[Equipment]()
|
||||
/** */
|
||||
|
|
@ -88,6 +87,7 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
|||
def Init(implicit context : ActorContext) : Unit = {
|
||||
if(accessor == ActorRef.noSender) {
|
||||
implicit val guid : NumberPoolHub = this.guid //passed into builderObject.Build implicitly
|
||||
SetupNumberPools()
|
||||
accessor = context.actorOf(RandomPool(25).props(Props(classOf[UniqueNumberSystem], guid, UniqueNumberSystem.AllocateNumberPoolActors(guid))), s"$Id-uns")
|
||||
ground = context.actorOf(Props(classOf[ZoneGroundActor], this, equipmentOnGround), s"$Id-ground")
|
||||
transport = context.actorOf(Props(classOf[ZoneVehicleActor], this, vehicles), s"$Id-vehicles")
|
||||
|
|
@ -100,6 +100,25 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
|||
}
|
||||
}
|
||||
|
||||
def SetupNumberPools() : Unit = {
|
||||
guid.AddPool("environment", (0 to 3000).toList) //TODO tailor to suit requirements of zone
|
||||
//TODO unlump pools later; do not make any single pool too big
|
||||
guid.AddPool("dynamic", (3001 to 10000).toList).Selector = new RandomSelector //TODO all things will be registered here, for now
|
||||
guid.AddPool("b", (10001 to 15000).toList).Selector = new RandomSelector
|
||||
guid.AddPool("c", (15001 to 20000).toList).Selector = new RandomSelector
|
||||
guid.AddPool("d", (20001 to 25000).toList).Selector = new RandomSelector
|
||||
guid.AddPool("e", (25001 to 30000).toList).Selector = new RandomSelector
|
||||
guid.AddPool("f", (30001 to 35000).toList).Selector = new RandomSelector
|
||||
guid.AddPool("g", (35001 until 40100).toList).Selector = new RandomSelector
|
||||
guid.AddPool("projectiles", (Projectile.BaseUID until Projectile.RangeUID).toList)
|
||||
//TODO disabled temporarily to lighten load times
|
||||
//guid.AddPool("h", (40150 to 45000).toList).Selector = new RandomSelector
|
||||
//guid.AddPool("i", (45001 to 50000).toList).Selector = new RandomSelector
|
||||
//guid.AddPool("j", (50001 to 55000).toList).Selector = new RandomSelector
|
||||
//guid.AddPool("k", (55001 to 60000).toList).Selector = new RandomSelector
|
||||
//guid.AddPool("l", (60001 to 65535).toList).Selector = new RandomSelector
|
||||
}
|
||||
|
||||
/**
|
||||
* A reference to the primary `Actor` that governs this `Zone`.
|
||||
* @return an `ActorRef`
|
||||
|
|
@ -150,10 +169,15 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
|||
/**
|
||||
* Replace the current globally unique identifier system with a new one.
|
||||
* The replacement will not occur if the current system is populated or if its synchronized reference has been created.
|
||||
* The primary use of this function should be testing.
|
||||
* A warning will be issued.
|
||||
* @return synchronized reference to the globally unique identifier system
|
||||
*/
|
||||
def GUID(hub : NumberPoolHub) : Boolean = {
|
||||
if(actor == ActorRef.noSender && guid.Pools.map({case ((_, pool)) => pool.Count}).sum == 0) {
|
||||
import org.fusesource.jansi.Ansi.Color.RED
|
||||
import org.fusesource.jansi.Ansi.ansi
|
||||
println(ansi().fgBright(RED).a(s"""Caution: replacement of the number pool system for zone $Id; function is for testing purposes only""").reset())
|
||||
guid = hub
|
||||
true
|
||||
}
|
||||
|
|
@ -162,6 +186,43 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps around the globally unique identifier system to insert a new number pool.
|
||||
* Throws exceptions for specific reasons if the pool can not be populated before the system has been started.
|
||||
* @see `NumberPoolHub.AddPool`
|
||||
* @param name the name of the pool
|
||||
* @param pool the numbers that will belong to the pool
|
||||
* @return `true`, if the new pool is created;
|
||||
* `false`, if the new pool can not be created because the system has already been started
|
||||
*/
|
||||
def AddPool(name : String, pool : Seq[Int]) : Boolean = {
|
||||
if(accessor == ActorRef.noSender) {
|
||||
guid.AddPool(name, pool.toList)
|
||||
true
|
||||
}
|
||||
else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps around the globally unique identifier system to remove an existing number pool.
|
||||
* Throws exceptions for specific reasons if the pool can not be removed before the system has been started.
|
||||
* @see `NumberPoolHub.RemovePool`
|
||||
* @param name the name of the pool
|
||||
* @return `true`, if the new pool is un-made;
|
||||
* `false`, if the new pool can not be removed because the system has already been started
|
||||
*/
|
||||
def RemovePool(name : String) : Boolean = {
|
||||
if(accessor == ActorRef.noSender) {
|
||||
guid.RemovePool(name)
|
||||
true
|
||||
}
|
||||
else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recover an object from the globally unique identifier system by the number that was assigned previously.
|
||||
* @param object_guid the globally unique identifier requested
|
||||
|
|
|
|||
|
|
@ -3,11 +3,23 @@ package objects
|
|||
|
||||
import akka.actor.ActorSystem
|
||||
import akka.testkit.{ImplicitSender, TestKit}
|
||||
import com.typesafe.config.{ConfigFactory, ConfigValueFactory}
|
||||
import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike}
|
||||
import org.specs2.specification.Scope
|
||||
|
||||
abstract class ActorTest(sys : ActorSystem = ActorSystem("system")) extends TestKit(sys) with Scope with ImplicitSender with WordSpecLike with Matchers with BeforeAndAfterAll {
|
||||
abstract class ActorTest(sys : ActorSystem = ActorSystem("system", ConfigFactory.parseMap(ActorTest.LoggingConfig)))
|
||||
extends TestKit(sys) with Scope with ImplicitSender with WordSpecLike with Matchers with BeforeAndAfterAll {
|
||||
override def afterAll {
|
||||
TestKit.shutdownActorSystem(system)
|
||||
}
|
||||
}
|
||||
|
||||
object ActorTest {
|
||||
import scala.collection.JavaConverters._
|
||||
private val LoggingConfig = Map(
|
||||
"akka.loggers" -> List("akka.testkit.TestEventListener").asJava,
|
||||
"akka.loglevel" -> "OFF",
|
||||
"akka.stdout-loglevel" -> "OFF",
|
||||
"akka.log-dead-letters" -> "OFF"
|
||||
).asJava
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,10 @@ import net.psforever.objects.zones.Zone
|
|||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import net.psforever.types.PlanetSideEmpire
|
||||
import org.specs2.mutable.Specification
|
||||
import services.ServiceManager
|
||||
import services.galaxy.GalaxyService
|
||||
|
||||
import scala.concurrent.duration.Duration
|
||||
import scala.concurrent.duration._
|
||||
|
||||
class AmenityTest extends Specification {
|
||||
class AmenityObject extends Amenity {
|
||||
|
|
@ -122,15 +124,20 @@ class BuildingControl1Test extends ActorTest {
|
|||
}
|
||||
|
||||
class BuildingControl2Test extends ActorTest {
|
||||
ServiceManager.boot(system) ! ServiceManager.Register(Props[GalaxyService], "galaxy")
|
||||
val bldg = Building(10, Zone.Nowhere, StructureType.Building)
|
||||
bldg.Faction = PlanetSideEmpire.TR
|
||||
bldg.Actor = system.actorOf(Props(classOf[BuildingControl], bldg), "test")
|
||||
|
||||
"Building Control" should {
|
||||
"convert and assert faction affinity on convert request" in {
|
||||
val bldg = Building(10, Zone.Nowhere, StructureType.Building)
|
||||
bldg.Faction = PlanetSideEmpire.TR
|
||||
bldg.Actor = system.actorOf(Props(classOf[BuildingControl], bldg), "test")
|
||||
assert(bldg.Faction == PlanetSideEmpire.TR)
|
||||
expectNoMsg(250 milliseconds)
|
||||
bldg.Actor ! "startup"
|
||||
expectNoMsg(250 milliseconds)
|
||||
|
||||
assert(bldg.Faction == PlanetSideEmpire.TR)
|
||||
bldg.Actor ! FactionAffinity.ConvertFactionAffinity(PlanetSideEmpire.VS)
|
||||
val reply = receiveOne(Duration.create(100, "ms"))
|
||||
val reply = receiveOne(500 milliseconds)
|
||||
assert(reply.isInstanceOf[FactionAffinity.AssertFactionAffinity])
|
||||
assert(reply.asInstanceOf[FactionAffinity.AssertFactionAffinity].obj == bldg)
|
||||
assert(reply.asInstanceOf[FactionAffinity.AssertFactionAffinity].faction == PlanetSideEmpire.VS)
|
||||
|
|
@ -140,19 +147,25 @@ class BuildingControl2Test extends ActorTest {
|
|||
}
|
||||
|
||||
class BuildingControl3Test extends ActorTest {
|
||||
ServiceManager.boot(system) ! ServiceManager.Register(Props[GalaxyService], "galaxy")
|
||||
val bldg = Building(10, Zone.Nowhere, StructureType.Building)
|
||||
bldg.Faction = PlanetSideEmpire.TR
|
||||
bldg.Actor = system.actorOf(Props(classOf[BuildingControl], bldg), "test")
|
||||
val door1 = Door(GlobalDefinitions.door)
|
||||
door1.GUID = PlanetSideGUID(1)
|
||||
door1.Actor = system.actorOf(Props(classOf[DoorControl], door1), "door1-test")
|
||||
val door2 = Door(GlobalDefinitions.door)
|
||||
door2.GUID = PlanetSideGUID(2)
|
||||
door2.Actor = system.actorOf(Props(classOf[DoorControl], door2), "door2-test")
|
||||
bldg.Amenities = door2
|
||||
bldg.Amenities = door1
|
||||
|
||||
"Building Control" should {
|
||||
"convert and assert faction affinity on convert request, and for each of its amenities" in {
|
||||
val bldg = Building(10, Zone.Nowhere, StructureType.Building)
|
||||
bldg.Faction = PlanetSideEmpire.TR
|
||||
bldg.Actor = system.actorOf(Props(classOf[BuildingControl], bldg), "building-test")
|
||||
val door1 = Door(GlobalDefinitions.door)
|
||||
door1.GUID = PlanetSideGUID(1)
|
||||
door1.Actor = system.actorOf(Props(classOf[DoorControl], door1), "door1-test")
|
||||
val door2 = Door(GlobalDefinitions.door)
|
||||
door2.GUID = PlanetSideGUID(2)
|
||||
door2.Actor = system.actorOf(Props(classOf[DoorControl], door2), "door2-test")
|
||||
bldg.Amenities = door2
|
||||
bldg.Amenities = door1
|
||||
expectNoMsg(250 milliseconds)
|
||||
bldg.Actor ! "startup"
|
||||
expectNoMsg(250 milliseconds)
|
||||
|
||||
assert(bldg.Faction == PlanetSideEmpire.TR)
|
||||
assert(bldg.Amenities.length == 2)
|
||||
assert(bldg.Amenities.head == door2)
|
||||
|
|
|
|||
|
|
@ -236,6 +236,50 @@ class EquipmentTest extends Specification {
|
|||
obj.AmmoType mustEqual Ammo.rocket
|
||||
}
|
||||
|
||||
"projectile types and ammo types" in {
|
||||
val suppressor_wep = Tool(suppressor)
|
||||
suppressor_wep.ProjectileType mustEqual bullet_9mm_projectile.ProjectileType
|
||||
suppressor_wep.NextAmmoType
|
||||
suppressor_wep.ProjectileType mustEqual bullet_9mm_AP_projectile.ProjectileType
|
||||
suppressor_wep.NextAmmoType
|
||||
suppressor_wep.ProjectileType mustEqual bullet_9mm_projectile.ProjectileType
|
||||
}
|
||||
|
||||
"projectile types and fire modes" in {
|
||||
val pulsar_wep = Tool(pulsar)
|
||||
pulsar_wep.ProjectileType mustEqual pulsar_projectile.ProjectileType
|
||||
pulsar_wep.NextFireMode
|
||||
pulsar_wep.ProjectileType mustEqual pulsar_ap_projectile.ProjectileType
|
||||
pulsar_wep.NextFireMode
|
||||
pulsar_wep.ProjectileType mustEqual pulsar_projectile.ProjectileType
|
||||
}
|
||||
|
||||
"projectile types and fire modes / ammo types" in {
|
||||
val punisher_wep = Tool(punisher)
|
||||
punisher_wep.ProjectileType mustEqual bullet_9mm_projectile.ProjectileType
|
||||
punisher_wep.NextAmmoType
|
||||
punisher_wep.ProjectileType mustEqual bullet_9mm_AP_projectile.ProjectileType
|
||||
|
||||
punisher_wep.NextFireMode
|
||||
punisher_wep.ProjectileType mustEqual rocket_projectile.ProjectileType
|
||||
punisher_wep.NextAmmoType
|
||||
punisher_wep.ProjectileType mustEqual frag_cartridge_projectile.ProjectileType
|
||||
punisher_wep.NextAmmoType
|
||||
punisher_wep.ProjectileType mustEqual jammer_cartridge_projectile.ProjectileType
|
||||
|
||||
punisher_wep.NextFireMode
|
||||
punisher_wep.ProjectileType mustEqual bullet_9mm_AP_projectile.ProjectileType
|
||||
punisher_wep.NextAmmoType
|
||||
punisher_wep.ProjectileType mustEqual bullet_9mm_projectile.ProjectileType
|
||||
|
||||
punisher_wep.NextFireMode
|
||||
punisher_wep.ProjectileType mustEqual jammer_cartridge_projectile.ProjectileType
|
||||
punisher_wep.NextAmmoType
|
||||
punisher_wep.ProjectileType mustEqual plasma_cartridge_projectile.ProjectileType
|
||||
punisher_wep.NextAmmoType
|
||||
punisher_wep.ProjectileType mustEqual rocket_projectile.ProjectileType
|
||||
}
|
||||
|
||||
"discharge (1)" in {
|
||||
val obj = Tool(GlobalDefinitions.punisher)
|
||||
obj.Magazine mustEqual 30
|
||||
|
|
|
|||
198
common/src/test/scala/objects/ProjectileTest.scala
Normal file
198
common/src/test/scala/objects/ProjectileTest.scala
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects
|
||||
|
||||
import net.psforever.objects.{GlobalDefinitions, LocalProjectile, Tool}
|
||||
import net.psforever.objects.ballistics.{DamageType, Projectile, ProjectileResolution, Projectiles}
|
||||
import net.psforever.objects.definition.ProjectileDefinition
|
||||
import net.psforever.types.Vector3
|
||||
import org.specs2.mutable.Specification
|
||||
|
||||
class ProjectileTest extends Specification {
|
||||
"LocalProjectile" should {
|
||||
"construct" in {
|
||||
val obj = new LocalProjectile() //since they're just placeholders, they only need to construct
|
||||
obj.Definition.ObjectId mustEqual 0
|
||||
obj.Definition.Name mustEqual "projectile"
|
||||
}
|
||||
}
|
||||
|
||||
"ProjectileDefinition" should {
|
||||
"define (default)" in {
|
||||
val obj = new ProjectileDefinition(31) //9mmbullet_projectile
|
||||
|
||||
obj.ProjectileType mustEqual Projectiles.bullet_9mm_projectile
|
||||
obj.ObjectId mustEqual 31
|
||||
obj.Damage0 mustEqual 0
|
||||
obj.Damage1 mustEqual 0
|
||||
obj.Damage2 mustEqual 0
|
||||
obj.Damage3 mustEqual 0
|
||||
obj.Damage4 mustEqual 0
|
||||
obj.Acceleration mustEqual 0
|
||||
obj.AccelerationUntil mustEqual 0f
|
||||
obj.ProjectileDamageType mustEqual DamageType.None
|
||||
obj.ProjectileDamageTypeSecondary mustEqual DamageType.None
|
||||
obj.DegradeDelay mustEqual 1f
|
||||
obj.DegradeMultiplier mustEqual 1f
|
||||
obj.InitialVelocity mustEqual 1
|
||||
obj.Lifespan mustEqual 1f
|
||||
obj.DamageAtEdge mustEqual 1f
|
||||
obj.DamageRadius mustEqual 1f
|
||||
obj.UseDamage1Subtract mustEqual false
|
||||
}
|
||||
|
||||
"define (custom)" in {
|
||||
val obj = new ProjectileDefinition(31) //9mmbullet_projectile
|
||||
obj.Damage0 = 2
|
||||
obj.Damage1 = 4
|
||||
obj.Damage2 = 8
|
||||
obj.Damage3 = 16
|
||||
obj.Damage4 = 32
|
||||
obj.Acceleration = 5
|
||||
obj.AccelerationUntil = 5.5f
|
||||
obj.ProjectileDamageType = DamageType.Splash
|
||||
obj.ProjectileDamageTypeSecondary = DamageType.Radiation
|
||||
obj.DegradeDelay = 11.1f
|
||||
obj.DegradeMultiplier = 22.2f
|
||||
obj.InitialVelocity = 50
|
||||
obj.Lifespan = 11.2f
|
||||
obj.DamageAtEdge = 3f
|
||||
obj.DamageRadius = 3f
|
||||
obj.UseDamage1Subtract = true
|
||||
|
||||
obj.Damage0 mustEqual 2
|
||||
obj.Damage1 mustEqual 4
|
||||
obj.Damage2 mustEqual 8
|
||||
obj.Damage3 mustEqual 16
|
||||
obj.Damage4 mustEqual 32
|
||||
obj.Acceleration mustEqual 5
|
||||
obj.AccelerationUntil mustEqual 5.5f
|
||||
obj.ProjectileDamageType mustEqual DamageType.Splash
|
||||
obj.ProjectileDamageTypeSecondary mustEqual DamageType.Radiation
|
||||
obj.DegradeDelay mustEqual 11.1f
|
||||
obj.DegradeMultiplier mustEqual 22.2f
|
||||
obj.InitialVelocity mustEqual 50
|
||||
obj.Lifespan mustEqual 11.2f
|
||||
obj.DamageAtEdge mustEqual 3f
|
||||
obj.DamageRadius mustEqual 3f
|
||||
obj.UseDamage1Subtract mustEqual true
|
||||
}
|
||||
|
||||
"define (failure)" in {
|
||||
Projectiles(31) mustEqual Projectiles.bullet_9mm_projectile
|
||||
try {
|
||||
ProjectileDefinition(Projectiles.bullet_9mm_projectile) //passes
|
||||
}
|
||||
catch {
|
||||
case _ : NoSuchElementException =>
|
||||
ko
|
||||
}
|
||||
|
||||
Projectiles(2) must throwA[NoSuchElementException]
|
||||
new ProjectileDefinition(2) must throwA[NoSuchElementException]
|
||||
}
|
||||
|
||||
"cascade damage values" in {
|
||||
val obj = new ProjectileDefinition(31) //9mmbullet_projectile
|
||||
obj.Damage4 = 32
|
||||
obj.Damage3 = 16
|
||||
obj.Damage2 = 8
|
||||
obj.Damage1 = 4
|
||||
obj.Damage0 = 2
|
||||
|
||||
//initial
|
||||
obj.Damage4 mustEqual 32
|
||||
obj.Damage3 mustEqual 16
|
||||
obj.Damage2 mustEqual 8
|
||||
obj.Damage1 mustEqual 4
|
||||
obj.Damage0 mustEqual 2
|
||||
//negate Damage4
|
||||
obj.Damage4 = None
|
||||
obj.Damage4 mustEqual 16
|
||||
obj.Damage3 mustEqual 16
|
||||
obj.Damage2 mustEqual 8
|
||||
obj.Damage1 mustEqual 4
|
||||
obj.Damage0 mustEqual 2
|
||||
//negate Damage3
|
||||
obj.Damage3 = None
|
||||
obj.Damage4 mustEqual 8
|
||||
obj.Damage3 mustEqual 8
|
||||
obj.Damage2 mustEqual 8
|
||||
obj.Damage1 mustEqual 4
|
||||
obj.Damage0 mustEqual 2
|
||||
//negate Damage2
|
||||
obj.Damage2 = None
|
||||
obj.Damage4 mustEqual 4
|
||||
obj.Damage3 mustEqual 4
|
||||
obj.Damage2 mustEqual 4
|
||||
obj.Damage1 mustEqual 4
|
||||
obj.Damage0 mustEqual 2
|
||||
//negate Damage1
|
||||
obj.Damage1 = None
|
||||
obj.Damage4 mustEqual 2
|
||||
obj.Damage3 mustEqual 2
|
||||
obj.Damage2 mustEqual 2
|
||||
obj.Damage1 mustEqual 2
|
||||
obj.Damage0 mustEqual 2
|
||||
//negate Damage0
|
||||
obj.Damage0 = None
|
||||
obj.Damage4 mustEqual 0
|
||||
obj.Damage3 mustEqual 0
|
||||
obj.Damage2 mustEqual 0
|
||||
obj.Damage1 mustEqual 0
|
||||
obj.Damage0 mustEqual 0
|
||||
//set Damage3, set Damage0
|
||||
obj.Damage3 = 13
|
||||
obj.Damage0 = 7
|
||||
obj.Damage4 mustEqual 13
|
||||
obj.Damage3 mustEqual 13
|
||||
obj.Damage2 mustEqual 7
|
||||
obj.Damage1 mustEqual 7
|
||||
obj.Damage0 mustEqual 7
|
||||
}
|
||||
}
|
||||
|
||||
"Projectile" should {
|
||||
"construct" in {
|
||||
val beamer_wep = Tool(GlobalDefinitions.beamer)
|
||||
val projectile = beamer_wep.Projectile
|
||||
val obj = Projectile(projectile, beamer_wep.Definition, Vector3(1.2f, 3.4f, 5.6f), Vector3(0.2f, 0.4f, 0.6f))
|
||||
|
||||
obj.profile mustEqual beamer_wep.Projectile
|
||||
obj.tool_def mustEqual GlobalDefinitions.beamer
|
||||
obj.shot_origin mustEqual Vector3(1.2f, 3.4f, 5.6f)
|
||||
obj.shot_angle mustEqual Vector3(0.2f, 0.4f, 0.6f)
|
||||
obj.resolution mustEqual ProjectileResolution.Unresolved
|
||||
obj.fire_time <= System.nanoTime mustEqual true
|
||||
obj.hit_time mustEqual 0
|
||||
}
|
||||
|
||||
"resolve" in {
|
||||
val beamer_wep = Tool(GlobalDefinitions.beamer)
|
||||
val projectile = beamer_wep.Projectile
|
||||
val obj = Projectile(projectile, beamer_wep.Definition, Vector3(1.2f, 3.4f, 5.6f), Vector3(0.2f, 0.4f, 0.6f))
|
||||
val obj2 = obj.Resolve(ProjectileResolution.MissedShot)
|
||||
|
||||
obj.resolution mustEqual ProjectileResolution.Unresolved
|
||||
obj.fire_time <= System.nanoTime mustEqual true
|
||||
obj.hit_time mustEqual 0
|
||||
obj2.resolution mustEqual ProjectileResolution.MissedShot
|
||||
obj2.fire_time == obj.fire_time mustEqual true
|
||||
obj2.hit_time <= System.nanoTime mustEqual true
|
||||
obj2.fire_time <= obj2.hit_time mustEqual true
|
||||
}
|
||||
|
||||
"resolve, with coordinates" in {
|
||||
val beamer_wep = Tool(GlobalDefinitions.beamer)
|
||||
val projectile = beamer_wep.Projectile
|
||||
val obj = Projectile(projectile, beamer_wep.Definition, Vector3(1.2f, 3.4f, 5.6f), Vector3(0.2f, 0.4f, 0.6f))
|
||||
val obj2 = obj.Resolve(Vector3(7.2f, 8.4f, 9.6f), Vector3(1.2f, 1.4f, 1.6f), ProjectileResolution.Resolved)
|
||||
|
||||
obj.resolution mustEqual ProjectileResolution.Unresolved
|
||||
obj.current.Position mustEqual Vector3.Zero
|
||||
obj.current.Orientation mustEqual Vector3.Zero
|
||||
obj2.resolution mustEqual ProjectileResolution.Resolved
|
||||
obj2.current.Position mustEqual Vector3(7.2f, 8.4f, 9.6f)
|
||||
obj2.current.Orientation mustEqual Vector3(1.2f, 1.4f, 1.6f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -170,6 +170,24 @@ class VehicleSpawnPadObjectBuilderTest extends ActorTest {
|
|||
}
|
||||
}
|
||||
|
||||
class LocalProjectileBuilderTest extends ActorTest {
|
||||
import net.psforever.objects.LocalProjectile
|
||||
"Local ProjectileBuilder" should {
|
||||
"build" in {
|
||||
val hub = ServerObjectBuilderTest.NumberPoolHub
|
||||
val actor = system.actorOf(Props(classOf[ServerObjectBuilderTest.BuilderTestActor], ServerObjectBuilder(1,
|
||||
LocalProjectile.Constructor), hub), "locker")
|
||||
actor ! "!"
|
||||
|
||||
val reply = receiveOne(Duration.create(1000, "ms"))
|
||||
assert(reply.isInstanceOf[LocalProjectile])
|
||||
assert(reply.asInstanceOf[LocalProjectile].HasGUID)
|
||||
assert(reply.asInstanceOf[LocalProjectile].GUID == PlanetSideGUID(1))
|
||||
assert(reply == hub(1).get)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LockerObjectBuilderTest extends ActorTest {
|
||||
import net.psforever.objects.serverobject.mblocker.Locker
|
||||
"LockerObjectBuilder" should {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package objects
|
|||
|
||||
import akka.actor.{ActorRef, ActorSystem, Props}
|
||||
import akka.testkit.TestProbe
|
||||
import net.psforever.objects.ballistics.Projectile
|
||||
import net.psforever.objects.serverobject.mount.Mountable
|
||||
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
|
||||
import net.psforever.objects.serverobject.structures.StructureType
|
||||
|
|
@ -323,10 +324,10 @@ object VehicleSpawnPadControlTest {
|
|||
import net.psforever.objects.Tool
|
||||
import net.psforever.types.CharacterGender
|
||||
|
||||
val zone = new Zone("test-zone", map, 0)
|
||||
val zone = new Zone("test-zone", map, 0) { override def SetupNumberPools() = { } }
|
||||
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
|
||||
val weapon = vehicle.WeaponControlledFromSeat(1).get.asInstanceOf[Tool]
|
||||
val guid : NumberPoolHub = new NumberPoolHub(LimitedNumberSource(3))
|
||||
val guid : NumberPoolHub = new NumberPoolHub(LimitedNumberSource(5))
|
||||
guid.AddPool("test-pool", (0 to 2).toList)
|
||||
guid.register(vehicle, "test-pool")
|
||||
guid.register(weapon, "test-pool")
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects
|
||||
|
||||
import akka.actor.{ActorSystem, Props}
|
||||
import akka.actor.Props
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.definition.{SeatDefinition, VehicleDefinition}
|
||||
import net.psforever.objects.serverobject.mount.Mountable
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package objects
|
|||
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
import akka.actor.{Actor, ActorContext, ActorRef, Props}
|
||||
import akka.actor.{ActorContext, ActorRef, Props}
|
||||
import net.psforever.objects.entity.IdentifiableEntity
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.objects.guid.NumberPoolHub
|
||||
|
|
@ -96,18 +96,15 @@ class ZoneTest extends Specification {
|
|||
"can have its unique identifier system changed if no objects were added to it" in {
|
||||
val zone = new Zone("home3", map13, 13)
|
||||
val guid1 : NumberPoolHub = new NumberPoolHub(new LimitedNumberSource(100))
|
||||
guid1.AddPool("pool1", (0 to 50).toList)
|
||||
guid1.AddPool("pool2", (51 to 75).toList)
|
||||
zone.GUID(guid1) mustEqual true
|
||||
zone.AddPool("pool1", (0 to 50).toList)
|
||||
zone.AddPool("pool2", (51 to 75).toList)
|
||||
|
||||
val obj = new TestObject()
|
||||
guid1.register(obj, "pool2").isSuccess mustEqual true
|
||||
guid1.WhichPool(obj) mustEqual Some("pool2")
|
||||
|
||||
val guid2 : NumberPoolHub = new NumberPoolHub(new LimitedNumberSource(150))
|
||||
guid2.AddPool("pool3", (0 to 50).toList)
|
||||
guid2.AddPool("pool4", (51 to 75).toList)
|
||||
zone.GUID(guid2) mustEqual false
|
||||
zone.GUID(new NumberPoolHub(new LimitedNumberSource(150))) mustEqual false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -115,12 +112,54 @@ class ZoneTest extends Specification {
|
|||
class ZoneActorTest extends ActorTest {
|
||||
"Zone" should {
|
||||
"have an Actor" in {
|
||||
val zone = new Zone("test", new ZoneMap("map6"), 1)
|
||||
val zone = new Zone("test", new ZoneMap("map6"), 1) { override def SetupNumberPools() = { } }
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-actor")
|
||||
expectNoMsg(Duration.create(100, "ms"))
|
||||
assert(zone.Actor != ActorRef.noSender)
|
||||
}
|
||||
|
||||
"create new number pools before the Actor is started" in {
|
||||
val zone = new Zone("test", new ZoneMap("map6"), 1) { override def SetupNumberPools() = { } }
|
||||
zone.GUID(new NumberPoolHub(new LimitedNumberSource(10)))
|
||||
assert( zone.AddPool("test1", 1 to 2) )
|
||||
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-add-pool-actor") //note: not Init'd yet
|
||||
assert( zone.AddPool("test2", 3 to 4) )
|
||||
}
|
||||
|
||||
"remove existing number pools before the Actor is started" in {
|
||||
val zone = new Zone("test", new ZoneMap("map6"), 1) { override def SetupNumberPools() = { } }
|
||||
zone.GUID(new NumberPoolHub(new LimitedNumberSource(10)))
|
||||
assert( zone.AddPool("test1", 1 to 2) )
|
||||
assert( zone.RemovePool("test1") )
|
||||
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-remove-pool-actor") //note: not Init'd yet
|
||||
assert( zone.AddPool("test2", 3 to 4) )
|
||||
assert( zone.RemovePool("test2") )
|
||||
}
|
||||
|
||||
"refuse new number pools after the Actor is started" in {
|
||||
val zone = new Zone("test", new ZoneMap("map6"), 1) { override def SetupNumberPools() = { } }
|
||||
zone.GUID(new NumberPoolHub(new LimitedNumberSource(40150)))
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-add-pool-actor-init")
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMsg(Duration.create(500, "ms"))
|
||||
|
||||
assert( !zone.AddPool("test1", 1 to 2) )
|
||||
}
|
||||
|
||||
"refuse to remove number pools after the Actor is started" in {
|
||||
val zone = new Zone("test", new ZoneMap("map6"), 1) { override def SetupNumberPools() = { } }
|
||||
|
||||
zone.GUID(new NumberPoolHub(new LimitedNumberSource(10)))
|
||||
zone.AddPool("test", 1 to 2)
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-remove-pool-actor-init")
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMsg(Duration.create(300, "ms"))
|
||||
|
||||
assert( !zone.RemovePool("test") )
|
||||
}
|
||||
|
||||
"set up spawn groups based on buildings" in {
|
||||
val map6 = new ZoneMap("map6") {
|
||||
LocalBuilding(1, FoundationBuilder(Building.Structure(StructureType.Building, Vector3(1,1,1))))
|
||||
|
|
@ -143,7 +182,7 @@ class ZoneActorTest extends ActorTest {
|
|||
ObjectToBuilding(5, 3)
|
||||
ObjectToBuilding(6, 3)
|
||||
}
|
||||
val zone = new Zone("test", map6, 1)
|
||||
val zone = new Zone("test", map6, 1) { override def SetupNumberPools() = { } }
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-init")
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMsg(Duration.create(300, "ms"))
|
||||
|
|
@ -181,7 +220,7 @@ class ZoneActorTest extends ActorTest {
|
|||
LocalObject(5, SpawnTube.Constructor(Vector3.Zero, Vector3.Zero))
|
||||
ObjectToBuilding(5, 3)
|
||||
}
|
||||
val zone = new Zone("test", map6, 1)
|
||||
val zone = new Zone("test", map6, 1) { override def SetupNumberPools() = { } }
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-spawn")
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMsg(Duration.create(300, "ms"))
|
||||
|
|
@ -212,7 +251,7 @@ class ZoneActorTest extends ActorTest {
|
|||
LocalObject(5, SpawnTube.Constructor(Vector3.Zero, Vector3.Zero))
|
||||
ObjectToBuilding(5, 3)
|
||||
}
|
||||
val zone = new Zone("test", map6, 1)
|
||||
val zone = new Zone("test", map6, 1) { override def SetupNumberPools() = { } }
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-no-spawn")
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMsg(Duration.create(300, "ms"))
|
||||
|
|
@ -228,15 +267,13 @@ class ZoneActorTest extends ActorTest {
|
|||
}
|
||||
|
||||
class ZonePopulationTest extends ActorTest {
|
||||
val testNum = new AtomicInteger(1)
|
||||
def TestName : String = s"test${testNum.getAndIncrement()}"
|
||||
|
||||
"ZonePopulationActor" should {
|
||||
"add new user to zones" in {
|
||||
val zone = new Zone("test", new ZoneMap(""), 0)
|
||||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = { } }
|
||||
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), TestName) ! "!"
|
||||
receiveOne(Duration.create(200, "ms")) //consume
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMsg(200 milliseconds)
|
||||
|
||||
assert(zone.Players.isEmpty)
|
||||
assert(zone.LivePlayers.isEmpty)
|
||||
|
|
@ -248,9 +285,10 @@ class ZonePopulationTest extends ActorTest {
|
|||
}
|
||||
|
||||
"remove user from zones" in {
|
||||
val zone = new Zone("test", new ZoneMap(""), 0)
|
||||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = { } }
|
||||
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), TestName) ! "!"
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
receiveOne(Duration.create(200, "ms")) //consume
|
||||
zone.Population ! Zone.Population.Join(avatar)
|
||||
expectNoMsg(Duration.create(100, "ms"))
|
||||
|
|
@ -263,11 +301,12 @@ class ZonePopulationTest extends ActorTest {
|
|||
}
|
||||
|
||||
"associate user with a character" in {
|
||||
val zone = new Zone("test", new ZoneMap(""), 0)
|
||||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = { } }
|
||||
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||
val player = Player(avatar)
|
||||
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), TestName) ! "!"
|
||||
receiveOne(Duration.create(200, "ms")) //consume
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMsg(200 milliseconds)
|
||||
zone.Population ! Zone.Population.Join(avatar)
|
||||
expectNoMsg(Duration.create(100, "ms"))
|
||||
|
||||
|
|
@ -283,11 +322,12 @@ class ZonePopulationTest extends ActorTest {
|
|||
}
|
||||
|
||||
"disassociate character from a user" in {
|
||||
val zone = new Zone("test", new ZoneMap(""), 0)
|
||||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = { } }
|
||||
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||
val player = Player(avatar)
|
||||
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), TestName) ! "!"
|
||||
receiveOne(Duration.create(200, "ms")) //consume
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMsg(200 milliseconds)
|
||||
zone.Population ! Zone.Population.Join(avatar)
|
||||
expectNoMsg(Duration.create(100, "ms"))
|
||||
zone.Population ! Zone.Population.Spawn(avatar, player)
|
||||
|
|
@ -305,11 +345,12 @@ class ZonePopulationTest extends ActorTest {
|
|||
}
|
||||
|
||||
"user tries to Leave, but still has an associated character" in {
|
||||
val zone = new Zone("test", new ZoneMap(""), 0)
|
||||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = { } }
|
||||
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||
val player = Player(avatar)
|
||||
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), TestName) ! "!"
|
||||
receiveOne(Duration.create(500, "ms")) //consume
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMsg(200 milliseconds)
|
||||
zone.Population ! Zone.Population.Join(avatar)
|
||||
expectNoMsg(Duration.create(100, "ms"))
|
||||
zone.Population ! Zone.Population.Spawn(avatar, player)
|
||||
|
|
@ -329,12 +370,13 @@ class ZonePopulationTest extends ActorTest {
|
|||
}
|
||||
|
||||
"user tries to Spawn a character, but an associated character already exists" in {
|
||||
val zone = new Zone("test", new ZoneMap(""), 0)
|
||||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = { } }
|
||||
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||
val player1 = Player(avatar)
|
||||
val player2 = Player(avatar)
|
||||
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), TestName) ! "!"
|
||||
receiveOne(Duration.create(200, "ms")) //consume
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMsg(200 milliseconds)
|
||||
zone.Population ! Zone.Population.Join(avatar)
|
||||
expectNoMsg(Duration.create(100, "ms"))
|
||||
zone.Population ! Zone.Population.Spawn(avatar, player1)
|
||||
|
|
@ -355,11 +397,12 @@ class ZonePopulationTest extends ActorTest {
|
|||
}
|
||||
|
||||
"user tries to Spawn a character, but did not Join first" in {
|
||||
val zone = new Zone("test", new ZoneMap(""), 0)
|
||||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = { } }
|
||||
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||
val player = Player(avatar)
|
||||
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), TestName) ! "!"
|
||||
receiveOne(Duration.create(200, "ms")) //consume
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMsg(200 milliseconds)
|
||||
|
||||
assert(zone.Players.isEmpty)
|
||||
assert(zone.LivePlayers.isEmpty)
|
||||
|
|
@ -373,10 +416,11 @@ class ZonePopulationTest extends ActorTest {
|
|||
}
|
||||
|
||||
"user tries to Release a character, but did not Spawn a character first" in {
|
||||
val zone = new Zone("test", new ZoneMap(""), 0)
|
||||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = { } }
|
||||
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), TestName) ! "!"
|
||||
receiveOne(Duration.create(200, "ms")) //consume
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMsg(200 milliseconds)
|
||||
zone.Population ! Zone.Population.Join(avatar)
|
||||
expectNoMsg(Duration.create(100, "ms"))
|
||||
|
||||
|
|
@ -394,11 +438,12 @@ class ZonePopulationTest extends ActorTest {
|
|||
}
|
||||
|
||||
"user adds character to list of retired characters" in {
|
||||
val zone = new Zone("test", new ZoneMap(""), 0)
|
||||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = { } }
|
||||
val player = Player(Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
|
||||
player.Release
|
||||
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), TestName) ! "!"
|
||||
receiveOne(Duration.create(200, "ms")) //consume
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMsg(200 milliseconds)
|
||||
|
||||
assert(zone.Corpses.isEmpty)
|
||||
zone.Population ! Zone.Corpse.Add(player)
|
||||
|
|
@ -408,11 +453,12 @@ class ZonePopulationTest extends ActorTest {
|
|||
}
|
||||
|
||||
"user removes character from the list of retired characters" in {
|
||||
val zone = new Zone("test", new ZoneMap(""), 0)
|
||||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = { } }
|
||||
val player = Player(Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
|
||||
player.Release
|
||||
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), TestName) ! "!"
|
||||
receiveOne(Duration.create(200, "ms")) //consume
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMsg(200 milliseconds)
|
||||
zone.Population ! Zone.Corpse.Add(player)
|
||||
expectNoMsg(Duration.create(100, "ms"))
|
||||
|
||||
|
|
@ -424,15 +470,16 @@ class ZonePopulationTest extends ActorTest {
|
|||
}
|
||||
|
||||
"user removes THE CORRECT character from the list of retired characters" in {
|
||||
val zone = new Zone("test", new ZoneMap(""), 0)
|
||||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = { } }
|
||||
val player1 = Player(Avatar("Chord1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
|
||||
player1.Release
|
||||
val player2 = Player(Avatar("Chord2", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
|
||||
player2.Release
|
||||
val player3 = Player(Avatar("Chord3", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
|
||||
player3.Release
|
||||
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), TestName) ! "!"
|
||||
receiveOne(Duration.create(200, "ms")) //consume
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMsg(200 milliseconds)
|
||||
zone.Population ! Zone.Corpse.Add(player1)
|
||||
zone.Population ! Zone.Corpse.Add(player2)
|
||||
zone.Population ! Zone.Corpse.Add(player3)
|
||||
|
|
@ -450,11 +497,12 @@ class ZonePopulationTest extends ActorTest {
|
|||
}
|
||||
|
||||
"user tries to add character to list of retired characters, but is not in correct state" in {
|
||||
val zone = new Zone("test", new ZoneMap(""), 0)
|
||||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = { } }
|
||||
val player = Player(Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
|
||||
//player.Release !!important
|
||||
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), "testC") ! "!"
|
||||
receiveOne(Duration.create(500, "ms")) //consume
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMsg(200 milliseconds)
|
||||
|
||||
assert(zone.Corpses.isEmpty)
|
||||
zone.Population ! Zone.Corpse.Add(player)
|
||||
|
|
@ -468,9 +516,11 @@ class ZoneGroundDropItemTest extends ActorTest {
|
|||
val item = AmmoBox(GlobalDefinitions.bullet_9mm)
|
||||
val hub = new NumberPoolHub(new LimitedNumberSource(20))
|
||||
hub.register(item, 10)
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0)
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = { } }
|
||||
zone.GUID(hub)
|
||||
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), "drop-test-zone") ! "!"
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMsg(200 milliseconds)
|
||||
|
||||
"DropItem" should {
|
||||
"drop item on ground" in {
|
||||
|
|
@ -492,9 +542,11 @@ class ZoneGroundCanNotDropItem1Test extends ActorTest {
|
|||
val item = AmmoBox(GlobalDefinitions.bullet_9mm)
|
||||
val hub = new NumberPoolHub(new LimitedNumberSource(20))
|
||||
//hub.register(item, 10) //!important
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0)
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = { } }
|
||||
zone.GUID(hub)
|
||||
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), "drop-test-zone") ! "!"
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMsg(200 milliseconds)
|
||||
|
||||
"DropItem" should {
|
||||
"not drop an item that is not registered" in {
|
||||
|
|
@ -516,9 +568,11 @@ class ZoneGroundCanNotDropItem2Test extends ActorTest {
|
|||
val item = AmmoBox(GlobalDefinitions.bullet_9mm)
|
||||
val hub = new NumberPoolHub(new LimitedNumberSource(20))
|
||||
hub.register(item, 10) //!important
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0)
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = { } }
|
||||
//zone.GUID(hub) //!important
|
||||
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), "drop-test-zone") ! "!"
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMsg(200 milliseconds)
|
||||
|
||||
"DropItem" should {
|
||||
"not drop an item that is not registered to the zone" in {
|
||||
|
|
@ -540,9 +594,11 @@ class ZoneGroundCanNotDropItem3Test extends ActorTest {
|
|||
val item = AmmoBox(GlobalDefinitions.bullet_9mm)
|
||||
val hub = new NumberPoolHub(new LimitedNumberSource(20))
|
||||
hub.register(item, 10) //!important
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0)
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = { } }
|
||||
zone.GUID(hub) //!important
|
||||
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), "drop-test-zone") ! "!"
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMsg(200 milliseconds)
|
||||
|
||||
"DropItem" should {
|
||||
"not drop an item that has already been dropped" in {
|
||||
|
|
@ -572,9 +628,11 @@ class ZoneGroundPickupItemTest extends ActorTest {
|
|||
val item = AmmoBox(GlobalDefinitions.bullet_9mm)
|
||||
val hub = new NumberPoolHub(new LimitedNumberSource(20))
|
||||
hub.register(item, 10)
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0)
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = { } }
|
||||
zone.GUID(hub)
|
||||
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), "drop-test-zone") ! "!"
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMsg(200 milliseconds)
|
||||
|
||||
"PickupItem" should {
|
||||
"pickup an item from ground" in {
|
||||
|
|
@ -599,9 +657,11 @@ class ZoneGroundCanNotPickupItemTest extends ActorTest {
|
|||
val item = AmmoBox(GlobalDefinitions.bullet_9mm)
|
||||
val hub = new NumberPoolHub(new LimitedNumberSource(20))
|
||||
hub.register(item, 10)
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0)
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = { } }
|
||||
zone.GUID(hub) //still registered to this zone
|
||||
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), "drop-test-zone") ! "!"
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMsg(200 milliseconds)
|
||||
|
||||
"PickupItem" should {
|
||||
"not pickup an item if it can not be found" in {
|
||||
|
|
@ -622,9 +682,11 @@ class ZoneGroundRemoveItemTest extends ActorTest {
|
|||
val item = AmmoBox(GlobalDefinitions.bullet_9mm)
|
||||
val hub = new NumberPoolHub(new LimitedNumberSource(20))
|
||||
hub.register(item, 10)
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0)
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = { } }
|
||||
zone.GUID(hub) //still registered to this zone
|
||||
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), "drop-test-zone") ! "!"
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMsg(200 milliseconds)
|
||||
|
||||
"RemoveItem" should {
|
||||
"remove an item from the ground without callback (even if the item is not found)" in {
|
||||
|
|
@ -646,12 +708,6 @@ class ZoneGroundRemoveItemTest extends ActorTest {
|
|||
}
|
||||
|
||||
object ZoneTest {
|
||||
class ZoneInitActor(zone : Zone) extends Actor {
|
||||
def receive : Receive = {
|
||||
case "!" =>
|
||||
zone.Init(context)
|
||||
sender ! "!"
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
val testNum = new AtomicInteger(1)
|
||||
def TestName : String = s"test${testNum.getAndIncrement()}"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,52 +1,17 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects.guidtask
|
||||
|
||||
import akka.actor.{Actor, ActorSystem, Props}
|
||||
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
|
||||
import org.specs2.mutable.Specification
|
||||
import objects.ActorTest
|
||||
|
||||
import scala.concurrent.Await
|
||||
import akka.pattern.ask
|
||||
import akka.util.Timeout
|
||||
import scala.concurrent.duration._
|
||||
class GUIDTaskRegister1Test extends ActorTest {
|
||||
"RegisterObjectTask" in {
|
||||
val (_, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
|
||||
val obj = new GUIDTaskTest.TestObject
|
||||
|
||||
class GUIDTaskRegister1Test extends Specification {
|
||||
"RegisterObjectTask" should {
|
||||
"register (1)" in {
|
||||
val system = ActorSystem("sys")
|
||||
val test = system.actorOf(Props(classOf[GUIDTaskRegister1TestActor], system), "test")
|
||||
|
||||
implicit val timeout = Timeout(5 seconds)
|
||||
val future = test ? "test"
|
||||
val result = Await.result(future, timeout.duration).asInstanceOf[String]
|
||||
result mustEqual "success"
|
||||
}
|
||||
assert(!obj.HasGUID)
|
||||
taskResolver ! TaskResolver.GiveTask(new GUIDTaskTest.RegisterTestTask(probe.ref), List(GUIDTask.RegisterObjectTask(obj)(uns)))
|
||||
probe.expectMsg(scala.util.Success)
|
||||
assert(obj.HasGUID)
|
||||
}
|
||||
}
|
||||
|
||||
private class GUIDTaskRegister1TestActor(implicit system : ActorSystem) extends Actor {
|
||||
def receive : Receive = {
|
||||
case "test" =>
|
||||
val (_, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
|
||||
val obj = new GUIDTaskTest.TestObject
|
||||
|
||||
assert(!obj.HasGUID)
|
||||
taskResolver ! TaskResolver.GiveTask(new GUIDTaskTest.RegisterTestTask(probe.ref), List(GUIDTask.RegisterObjectTask(obj)(uns)))
|
||||
probe.expectMsg(scala.util.Success)
|
||||
assert(obj.HasGUID)
|
||||
sender ! "success"
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
||||
//class GUIDTaskRegister1Test extends ActorTest() {
|
||||
// "RegisterObjectTask" in {
|
||||
// val (_, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
|
||||
// val obj = new GUIDTaskTest.TestObject
|
||||
//
|
||||
// assert(!obj.HasGUID)
|
||||
// taskResolver ! TaskResolver.GiveTask(new GUIDTaskTest.RegisterTestTask(probe.ref), List(GUIDTask.RegisterObjectTask(obj)(uns)))
|
||||
// probe.expectMsg(scala.util.Success)
|
||||
// assert(obj.HasGUID)
|
||||
// }
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import objects.ActorTest
|
|||
|
||||
import scala.concurrent.duration.Duration
|
||||
|
||||
class NumberPoolActorTest extends ActorTest(ActorSystem("test")) {
|
||||
class NumberPoolActorTest extends ActorTest() {
|
||||
"NumberPoolActor" should {
|
||||
"GetAnyNumber" in {
|
||||
val pool = new ExclusivePool((25 to 50).toList)
|
||||
|
|
@ -22,7 +22,7 @@ class NumberPoolActorTest extends ActorTest(ActorSystem("test")) {
|
|||
}
|
||||
}
|
||||
|
||||
class NumberPoolActorTest1 extends ActorTest(ActorSystem("test")) {
|
||||
class NumberPoolActorTest1 extends ActorTest() {
|
||||
"NumberPoolActor" should {
|
||||
"GetSpecificNumber" in {
|
||||
val pool = new ExclusivePool((25 to 50).toList)
|
||||
|
|
@ -34,7 +34,7 @@ class NumberPoolActorTest1 extends ActorTest(ActorSystem("test")) {
|
|||
}
|
||||
}
|
||||
|
||||
class NumberPoolActorTest2 extends ActorTest(ActorSystem("test")) {
|
||||
class NumberPoolActorTest2 extends ActorTest() {
|
||||
"NumberPoolActor" should {
|
||||
"NoNumber" in {
|
||||
val pool = new ExclusivePool((25 to 25).toList) //pool only has one number - 25
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
import net.psforever.objects.zones.ZoneMap
|
||||
import net.psforever.objects.GlobalDefinitions._
|
||||
import net.psforever.objects.LocalProjectile
|
||||
import net.psforever.objects.ballistics.Projectile
|
||||
import net.psforever.objects.serverobject.doors.Door
|
||||
import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech
|
||||
import net.psforever.objects.serverobject.locks.IFFLock
|
||||
|
|
@ -13,15 +15,25 @@ import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
|
|||
import net.psforever.types.Vector3
|
||||
|
||||
object Maps {
|
||||
val map1 = new ZoneMap("map01")
|
||||
val map1 = new ZoneMap("map01") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val map2 = new ZoneMap("map02")
|
||||
val map2 = new ZoneMap("map02") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val map3 = new ZoneMap("map03")
|
||||
val map3 = new ZoneMap("map03") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val map4 = new ZoneMap("map04")
|
||||
val map4 = new ZoneMap("map04") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val map5 = new ZoneMap("map05")
|
||||
val map5 = new ZoneMap("map05") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val map6 = new ZoneMap("map06") {
|
||||
Building2()
|
||||
|
|
@ -29,6 +41,7 @@ object Maps {
|
|||
Building42()
|
||||
Building48()
|
||||
Building49()
|
||||
Projectiles(this)
|
||||
|
||||
def Building2() : Unit = {
|
||||
//Anguta
|
||||
|
|
@ -420,17 +433,29 @@ object Maps {
|
|||
}
|
||||
}
|
||||
|
||||
val map7 = new ZoneMap("map07")
|
||||
val map7 = new ZoneMap("map07") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val map8 = new ZoneMap("map08")
|
||||
val map8 = new ZoneMap("map08") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val map9 = new ZoneMap("map09")
|
||||
val map9 = new ZoneMap("map09") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val map10 = new ZoneMap("map10")
|
||||
val map10 = new ZoneMap("map10") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val map11 = new ZoneMap("map11")
|
||||
val map11 = new ZoneMap("map11") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val map12 = new ZoneMap("map12")
|
||||
val map12 = new ZoneMap("map12") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val map13 = new ZoneMap("map13") {
|
||||
Building1()
|
||||
|
|
@ -443,6 +468,7 @@ object Maps {
|
|||
Building77()
|
||||
Building79()
|
||||
Building81()
|
||||
Projectiles(this)
|
||||
|
||||
def Building1() : Unit = {
|
||||
//warpgate?
|
||||
|
|
@ -716,29 +742,59 @@ object Maps {
|
|||
}
|
||||
}
|
||||
|
||||
val map14 = new ZoneMap("map14")
|
||||
val map14 = new ZoneMap("map14") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val map15 = new ZoneMap("map15")
|
||||
val map15 = new ZoneMap("map15") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val map16 = new ZoneMap("map16")
|
||||
val map16 = new ZoneMap("map16") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val ugd01 = new ZoneMap("ugd01")
|
||||
val ugd01 = new ZoneMap("ugd01") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val ugd02 = new ZoneMap("ugd02")
|
||||
val ugd02 = new ZoneMap("ugd02") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val ugd03 = new ZoneMap("ugd03")
|
||||
val ugd03 = new ZoneMap("ugd03") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val ugd04 = new ZoneMap("ugd04")
|
||||
val ugd04 = new ZoneMap("ugd04") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val ugd05 = new ZoneMap("ugd05")
|
||||
val ugd05 = new ZoneMap("ugd05") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val ugd06 = new ZoneMap("ugd06")
|
||||
val ugd06 = new ZoneMap("ugd06") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val map96 = new ZoneMap("map96")
|
||||
val map96 = new ZoneMap("map96") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val map97 = new ZoneMap("map97")
|
||||
val map97 = new ZoneMap("map97") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val map98 = new ZoneMap("map98")
|
||||
val map98 = new ZoneMap("map98") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val map99 = new ZoneMap("map99")
|
||||
val map99 = new ZoneMap("map99") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
private def Projectiles(zmap : ZoneMap) : Unit = {
|
||||
(Projectile.BaseUID until Projectile.RangeUID) foreach { zmap.LocalObject(_, LocalProjectile.Constructor) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ import scala.concurrent.Future
|
|||
import scala.concurrent.duration._
|
||||
import scala.util.Success
|
||||
import akka.pattern.ask
|
||||
import net.psforever.objects.ballistics.{Projectile, ProjectileResolution}
|
||||
|
||||
class WorldSessionActor extends Actor with MDCContextAware {
|
||||
import WorldSessionActor._
|
||||
|
|
@ -84,6 +85,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
var traveler : Traveler = null
|
||||
var deadState : DeadState.Value = DeadState.Dead
|
||||
var whenUsedLastKit : Long = 0
|
||||
val projectiles : Array[Option[Projectile]] = Array.fill[Option[Projectile]](Projectile.RangeUID - Projectile.BaseUID)(None)
|
||||
|
||||
var amsSpawnPoint : Option[SpawnTube] = None
|
||||
|
||||
|
|
@ -2586,7 +2588,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
else if((player.DrawnSlot = held_holsters) != before) {
|
||||
avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.ObjectHeld(player.GUID, player.LastDrawnSlot))
|
||||
|
||||
|
||||
// Ignore non-equipment holsters
|
||||
//todo: check current suit holster slots?
|
||||
if(held_holsters >= 0 && held_holsters < 5) {
|
||||
|
|
@ -2598,7 +2599,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
case None => ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Stop using proximity terminals if player unholsters a weapon (which should re-trigger the proximity effect and re-holster the weapon)
|
||||
|
|
@ -2684,11 +2684,22 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
}
|
||||
|
||||
case Some(_ : LocalProjectile) =>
|
||||
FindProjectileEntry(object_guid) match {
|
||||
case Some(projectile) =>
|
||||
if(projectile.resolution != ProjectileResolution.Unresolved) {
|
||||
log.warn(s"RequestDestroy: tried to clean up missed projectile ${object_guid.guid} but it was already resolved")
|
||||
}
|
||||
ResolveProjectileEntry(object_guid, ProjectileResolution.MissedShot)
|
||||
case None =>
|
||||
log.warn(s"RequestDestroy: projectile ${object_guid.guid} has never been fired")
|
||||
}
|
||||
|
||||
case Some(thing) =>
|
||||
log.warn(s"RequestDestroy: not allowed to delete object $thing")
|
||||
|
||||
case None =>
|
||||
log.warn(s"RequestDestroy: object $object_guid not found")
|
||||
log.warn(s"RequestDestroy: object ${object_guid.guid} not found")
|
||||
}
|
||||
|
||||
case msg @ ObjectDeleteMessage(object_guid, unk1) =>
|
||||
|
|
@ -3137,8 +3148,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
|
||||
case msg @ WeaponFireMessage(seq_time, weapon_guid, projectile_guid, shot_origin, unk1, unk2, unk3, unk4, unk5, unk6, unk7) =>
|
||||
log.info("WeaponFire: " + msg)
|
||||
FindWeapon match {
|
||||
case Some(tool : Tool) =>
|
||||
FindContainedWeapon match {
|
||||
case (Some(obj), Some(tool : Tool)) =>
|
||||
if(tool.Magazine <= 0) { //safety: enforce ammunition depletion
|
||||
tool.Magazine = 0
|
||||
sendResponse(InventoryStateMessage(tool.AmmoSlot.Box.GUID, weapon_guid, 0))
|
||||
|
|
@ -3149,7 +3160,17 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
else { //shooting
|
||||
tool.Discharge
|
||||
//TODO other stuff?
|
||||
val projectileIndex = projectile_guid.guid - Projectile.BaseUID
|
||||
val ang = obj match {
|
||||
case _ : Player =>
|
||||
obj.Orientation //TODO upper body facing
|
||||
case _ : Vehicle =>
|
||||
tool.Orientation //TODO this is too simplistic
|
||||
case _ =>
|
||||
Vector3.Zero
|
||||
}
|
||||
projectiles(projectileIndex) =
|
||||
Some(Projectile(tool.Projectile, tool.Definition, shot_origin, ang))
|
||||
}
|
||||
case _ => ;
|
||||
}
|
||||
|
|
@ -3158,10 +3179,16 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
log.info("Lazing position: " + pos2.toString)
|
||||
|
||||
case msg @ HitMessage(seq_time, projectile_guid, unk1, hit_info, unk2, unk3, unk4) =>
|
||||
log.info("Hit: " + msg)
|
||||
log.info(s"Hit: $msg")
|
||||
ResolveProjectileEntry(projectile_guid, ProjectileResolution.Hit)
|
||||
|
||||
case msg @ SplashHitMessage(unk1, unk2, unk3, unk4, unk5, unk6, unk7, unk8) =>
|
||||
log.info("SplashHitMessage: " + msg)
|
||||
case msg @ SplashHitMessage(seq_time, projectile_guid, explosion_pos, direct_victim_uid, unk3, projectile_vel, unk4, targets) =>
|
||||
log.info(s"Splash: $msg")
|
||||
ResolveProjectileEntry(projectile_guid, ProjectileResolution.Splash)
|
||||
|
||||
case msg @ LashMessage(seq_time, killer_guid, victim_guid, projectile_guid, pos, unk1) =>
|
||||
log.info(s"Lash: $msg")
|
||||
ResolveProjectileEntry(projectile_guid, ProjectileResolution.Lash)
|
||||
|
||||
case msg @ AvatarFirstTimeEventMessage(avatar_guid, object_guid, unk1, event_name) =>
|
||||
log.info("AvatarFirstTimeEvent: " + msg)
|
||||
|
|
@ -5229,6 +5256,62 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a globally unique identifier in the 40100 to 40124 range
|
||||
* (with an optional 25 as buffer),
|
||||
* find a projectile.
|
||||
* @param projectile_guid the projectile's GUID
|
||||
* @return the discovered projectile
|
||||
*/
|
||||
def FindProjectileEntry(projectile_guid : PlanetSideGUID) : Option[Projectile] = {
|
||||
val index = projectile_guid.guid - Projectile.BaseUID
|
||||
if(0 <= index && index < projectiles.length) {
|
||||
projectiles(index)
|
||||
}
|
||||
else {
|
||||
log.warn(s"ResolveProjectile: expected projectile, but ${projectile_guid.guid} not found")
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a projectile with the given globally unique identifier and mark it as a resolved shot.
|
||||
* A `Resolved` shot has either encountered an obstacle or is being cleaned up for not finding an obstacle.
|
||||
* @param projectile_guid the projectile GUID
|
||||
* @param resolution the resolution status to promote the projectile
|
||||
* @return the projectile
|
||||
*/
|
||||
def ResolveProjectileEntry(projectile_guid : PlanetSideGUID, resolution : ProjectileResolution.Value) : Option[Projectile] = {
|
||||
FindProjectileEntry(projectile_guid) match {
|
||||
case Some(projectile) =>
|
||||
val index = projectile_guid.guid - Projectile.BaseUID
|
||||
ResolveProjectileEntry(projectile, index, resolution)
|
||||
case None =>
|
||||
log.warn(s"ResolveProjectile: expected projectile, but ${projectile_guid.guid} not found")
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a projectile with the given globally unique identifier and mark it as a resolved shot.
|
||||
* A `Resolved` shot has either encountered an obstacle or is being cleaned up for not finding an obstacle.
|
||||
* The internal copy of the projectile is retained as merely `Resolved`
|
||||
* while the observed projectile is promoted to the suggested resolution status.
|
||||
* @param projectile the projectile object
|
||||
* @param index where the projectile was found
|
||||
* @param resolution the resolution status to promote the projectile
|
||||
* @return a copy of the projectile
|
||||
*/
|
||||
def ResolveProjectileEntry(projectile : Projectile, index : Int, resolution : ProjectileResolution.Value) : Option[Projectile] = {
|
||||
if(projectiles(index).contains(projectile)) {
|
||||
projectiles(index) = Some(projectile.Resolve(ProjectileResolution.Resolved))
|
||||
Some(projectile.Resolve(resolution))
|
||||
}
|
||||
else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
def failWithError(error : String) = {
|
||||
log.error(error)
|
||||
sendResponse(ConnectionClose())
|
||||
|
|
|
|||
|
|
@ -2,17 +2,27 @@
|
|||
|
||||
import akka.actor.{ActorRef, ActorSystem, MDCContextAware}
|
||||
import akka.testkit.{ImplicitSender, TestKit, TestProbe}
|
||||
import com.typesafe.config.{ConfigFactory, ConfigValueFactory}
|
||||
import net.psforever.packet.{ControlPacket, GamePacket}
|
||||
import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike}
|
||||
import org.specs2.specification.Scope
|
||||
|
||||
abstract class ActorTest(sys : ActorSystem = ActorSystem("system")) extends TestKit(sys) with Scope with ImplicitSender with WordSpecLike with Matchers with BeforeAndAfterAll {
|
||||
abstract class ActorTest(sys : ActorSystem = ActorSystem("system", ConfigFactory.parseMap(ActorTest.LoggingConfig)))
|
||||
extends TestKit(sys) with Scope with ImplicitSender with WordSpecLike with Matchers with BeforeAndAfterAll {
|
||||
override def afterAll {
|
||||
TestKit.shutdownActorSystem(system)
|
||||
}
|
||||
}
|
||||
|
||||
object ActorTest {
|
||||
import scala.collection.JavaConverters._
|
||||
private val LoggingConfig = Map(
|
||||
"akka.loggers" -> List("akka.testkit.TestEventListener").asJava,
|
||||
"akka.loglevel" -> "OFF",
|
||||
"akka.stdout-loglevel" -> "OFF",
|
||||
"akka.log-dead-letters" -> "OFF"
|
||||
).asJava
|
||||
|
||||
final case class MDCGamePacket(packet : GamePacket)
|
||||
|
||||
final case class MDCControlPacket(packet : ControlPacket)
|
||||
|
|
|
|||
|
|
@ -384,7 +384,7 @@ Even with all this work, the tests have a high chance of failure just due to bei
|
|||
class AvatarReleaseTest extends ActorTest {
|
||||
ServiceManager.boot(system) ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]), "taskResolver")
|
||||
val service = system.actorOf(Props[AvatarService], "release-test-service")
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0)
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = { AddPool("dynamic", 1 to 10) } }
|
||||
val taskResolver = system.actorOf(Props[TaskResolver], "release-test-resolver")
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "release-test-zone")
|
||||
zone.Actor ! Zone.Init()
|
||||
|
|
@ -433,7 +433,7 @@ class AvatarReleaseTest extends ActorTest {
|
|||
class AvatarReleaseEarly1Test extends ActorTest {
|
||||
ServiceManager.boot(system) ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]), "taskResolver")
|
||||
val service = system.actorOf(Props[AvatarService], "release-test-service")
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0)
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = { AddPool("dynamic", 1 to 10) } }
|
||||
val taskResolver = system.actorOf(Props[TaskResolver], "release-test-resolver")
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "release-test-zone")
|
||||
zone.Actor ! Zone.Init()
|
||||
|
|
@ -483,7 +483,7 @@ class AvatarReleaseEarly1Test extends ActorTest {
|
|||
class AvatarReleaseEarly2Test extends ActorTest {
|
||||
ServiceManager.boot(system) ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]), "taskResolver")
|
||||
val service = system.actorOf(Props[AvatarService], "release-test-service")
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0)
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = { AddPool("dynamic", 1 to 10) } }
|
||||
val taskResolver = system.actorOf(Props[TaskResolver], "release-test-resolver")
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "release-test-zone")
|
||||
zone.Actor ! Zone.Init()
|
||||
|
|
|
|||
Loading…
Reference in a new issue