Last Infantry Weapons (#987)

* preparations for deploying oicw little buddy projectiles

* oicw little buddy projectiles spawn and animate properly, but damage dealing is inconclusive

* radiator clouds cause damage to infantry health

* oicw little buddy projectiles do damage upon detonation; different descent pattern; projectile types given own Enumeration

* proximity terminals for vehicle actions no longer need to use the vehicle event system as a middleman for making changes

* redid the workflow of the proximity terminal resolution so that it avoids SessionActor as much as is possible; this may be a mistake, but my future self will pay the price instead

* changed the timing and the angles of the little buddy explosions; fixed proximity terminal tests
This commit is contained in:
Fate-JH 2022-03-27 19:57:32 -04:00 committed by GitHub
parent 2b58d126b5
commit 0d8c717b73
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 1092 additions and 585 deletions

View file

@ -2,7 +2,7 @@
package game.objectcreate
import net.psforever.packet.PacketCoding
import net.psforever.packet.game.ObjectCreateMessage
import net.psforever.packet.game.{ObjectCreateDetailedMessage, ObjectCreateMessage}
import net.psforever.packet.game.objectcreate._
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, Vector3}
import org.specs2.mutable._
@ -11,6 +11,7 @@ import scodec.bits._
class RemoteProjectileDataTest extends Specification {
val string_striker_projectile = hex"17 C5000000 A4B 009D 4C129 0CB0A 9814 00 F5 E3 040000666686400"
val string_hunter_seeker_missile_projectile = hex"17 c5000000 ca9 ab9e af127 ec465 3723 00 15 c4 2400009a99c9400"
val string_oicw_little_buddy = hex"18 ef000000 aca 3d0e 1ef35 d9417 2511 00 0f 21 d3bf0d1bc38900000000000fc"
"RemoteProjectileData" should {
"decode (striker_missile_targeting_projectile)" in {
@ -33,7 +34,6 @@ class RemoteProjectileDataTest extends Specification {
deploy.v4.isEmpty mustEqual true
deploy.v5.isEmpty mustEqual true
deploy.guid mustEqual PlanetSideGUID(0)
unk2 mustEqual 26214
lim mustEqual 134
unk3 mustEqual FlightPhysics.State4
@ -67,7 +67,6 @@ class RemoteProjectileDataTest extends Specification {
deploy.v4.isEmpty mustEqual true
deploy.v5.isEmpty mustEqual true
deploy.guid mustEqual PlanetSideGUID(0)
unk2 mustEqual 39577
lim mustEqual 201
unk3 mustEqual FlightPhysics.State4
@ -81,6 +80,37 @@ class RemoteProjectileDataTest extends Specification {
}
}
"decode (oicw_little_buddy)" in {
PacketCoding.decodePacket(string_oicw_little_buddy).require match {
case ObjectCreateDetailedMessage(len, cls, guid, parent, data) =>
len mustEqual 239
cls mustEqual ObjectClass.oicw_little_buddy
guid mustEqual PlanetSideGUID(3645)
parent.isDefined mustEqual false
data match {
case LittleBuddyProjectileData(dat, u2, u4) =>
dat.pos.coord mustEqual Vector3(3046.2344f, 3715.6953f, 68.578125f)
dat.pos.orient mustEqual Vector3(0, 317.8125f, 357.1875f)
dat.pos.vel.contains(Vector3(-10.0125f, 101.475f, -101.7f)) mustEqual true
dat.data.faction mustEqual PlanetSideEmpire.NC
dat.data.bops mustEqual false
dat.data.alternate mustEqual false
dat.data.v1 mustEqual true
dat.data.v2.isEmpty mustEqual true
dat.data.jammered mustEqual false
dat.data.v4.isEmpty mustEqual true
dat.data.v5.isEmpty mustEqual true
dat.data.guid mustEqual PlanetSideGUID(0)
u2 mustEqual 0
u4 mustEqual true
case _ =>
ko
}
case _ =>
ko
}
}
"encode (striker_missile_targeting_projectile)" in {
val obj = RemoteProjectileData(
CommonFieldDataWithPlacement(
@ -101,26 +131,53 @@ class RemoteProjectileDataTest extends Specification {
pkt.toBitVector.drop(133).take(7) mustEqual string_striker_projectile.toBitVector.drop(133).take(7)
pkt.toBitVector.drop(141) mustEqual string_striker_projectile.toBitVector.drop(141)
}
}
"encode (hunter_seeker_missile_projectile)" in {
val obj = RemoteProjectileData(
CommonFieldDataWithPlacement(
PlacementData(3621.3672f, 2701.8438f, 140.85938f, 0, 300.9375f, 258.75f),
CommonFieldData(PlanetSideEmpire.NC, false, false, true, None, false, None, None, PlanetSideGUID(0))
),
39577,
201,
FlightPhysics.State4,
0,
0
)
val msg = ObjectCreateMessage(ObjectClass.hunter_seeker_missile_projectile, PlanetSideGUID(40619), obj)
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
//pkt mustEqual string_hunter_seeker_missile_projectile
"encode (hunter_seeker_missile_projectile)" in {
val obj = RemoteProjectileData(
CommonFieldDataWithPlacement(
PlacementData(3621.3672f, 2701.8438f, 140.85938f, 0, 300.9375f, 258.75f),
CommonFieldData(PlanetSideEmpire.NC, false, false, true, None, false, None, None, PlanetSideGUID(0))
),
39577,
201,
FlightPhysics.State4,
0,
0
)
val msg = ObjectCreateMessage(ObjectClass.hunter_seeker_missile_projectile, PlanetSideGUID(40619), obj)
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
//pkt mustEqual string_hunter_seeker_missile_projectile
pkt.toBitVector.take(132) mustEqual string_hunter_seeker_missile_projectile.toBitVector.take(132)
pkt.toBitVector.drop(133).take(7) mustEqual string_hunter_seeker_missile_projectile.toBitVector.drop(133).take(7)
pkt.toBitVector.drop(141) mustEqual string_hunter_seeker_missile_projectile.toBitVector.drop(141)
pkt.toBitVector.take(132) mustEqual string_hunter_seeker_missile_projectile.toBitVector.take(132)
pkt.toBitVector.drop(133).take(7) mustEqual string_hunter_seeker_missile_projectile.toBitVector.drop(133).take(7)
pkt.toBitVector.drop(141) mustEqual string_hunter_seeker_missile_projectile.toBitVector.drop(141)
}
"encode (oicw_little_buddy)" in {
val obj = LittleBuddyProjectileData(
CommonFieldDataWithPlacement(
PlacementData(Vector3(3046.2344f, 3715.6953f, 68.578125f),
Vector3(0, 317.8125f, 357.1875f),
Some(Vector3(-10.0125f, 101.475f, -101.7f))
),
CommonFieldData(
PlanetSideEmpire.NC,
bops = false,
alternate = false,
v1 = true,
v2 = None,
jammered = false,
v4 = None,
v5 = None,
guid = PlanetSideGUID(0)
)
),
u2 = 0,
u4 = true
)
val msg = ObjectCreateDetailedMessage(ObjectClass.oicw_little_buddy, PlanetSideGUID(3645), obj)
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
pkt mustEqual string_oicw_little_buddy
}
}
}

View file

@ -921,7 +921,7 @@ class DamageModelTests extends Specification {
}
object DamageModelTests {
final val projectile = new ProjectileDefinition(Projectiles.heavy_grenade_projectile.id) {
final val projectile = new ProjectileDefinition(Projectiles.Types.heavy_grenade_projectile.id) {
Damage0 = 50
Damage1 = 82
Damage2 = 82

View file

@ -26,7 +26,7 @@ class ProjectileTest extends Specification {
"define (default)" in {
val obj = new ProjectileDefinition(31) //9mmbullet_projectile
obj.ProjectileType mustEqual Projectiles.bullet_9mm_projectile
obj.ProjectileType mustEqual Projectiles.Types.bullet_9mm_projectile
obj.ObjectId mustEqual 31
obj.Damage0 mustEqual 0
obj.Damage1 mustEqual 0
@ -84,9 +84,9 @@ class ProjectileTest extends Specification {
}
"define (failure)" in {
Projectiles(31) mustEqual Projectiles.bullet_9mm_projectile
Projectiles.Types(31) mustEqual Projectiles.Types.bullet_9mm_projectile
try {
ProjectileDefinition(Projectiles.bullet_9mm_projectile) //passes
ProjectileDefinition(Projectiles.Types.bullet_9mm_projectile) //passes
} catch {
case _: NoSuchElementException =>
ko

View file

@ -14,7 +14,7 @@ import net.psforever.objects.guid.source.MaxNumberSource
import net.psforever.objects.serverobject.environment._
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.vehicles.VehicleLockState
import net.psforever.objects.vehicles.control.{CargoCarrierControl, VehicleControl}
import net.psforever.objects.vehicles.control.{/*CargoCarrierControl, */VehicleControl}
import net.psforever.objects.vital.{VehicleShieldCharge, Vitality}
import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.packet.game._

View file

@ -241,6 +241,7 @@ class ProximityTerminalControlTwoUsersTest extends ActorTest {
)
)
avatar.Continent = "test"
avatar.Zone = zone
avatar.Spawn()
avatar.Health = 50
val avatar2 =
@ -249,12 +250,13 @@ class ProximityTerminalControlTwoUsersTest extends ActorTest {
ProximityTest.avatarId.getAndIncrement(),
"TestCharacter2",
PlanetSideEmpire.VS,
CharacterSex.Female,
CharacterSex.Male,
1,
CharacterVoice.Voice1
)
)
avatar2.Continent = "test"
avatar2.Zone = zone
avatar2.Spawn()
avatar2.Health = 50
@ -266,6 +268,7 @@ class ProximityTerminalControlTwoUsersTest extends ActorTest {
val probe1 = new TestProbe(system, "local-events")
val probe2 = new TestProbe(system, "target-callback-1")
val probe3 = new TestProbe(system, "target-callback-2")
zone.AvatarEvents = new TestProbe(system, "avatar-events-throwaway").ref
zone.LocalEvents = probe1.ref
"not send out a start message if not the first user" in {
@ -274,7 +277,7 @@ class ProximityTerminalControlTwoUsersTest extends ActorTest {
terminal.Actor.tell(CommonMessages.Use(avatar, Some(avatar)), probe2.ref)
probe1.expectMsgClass(1 second, classOf[Terminal.StartProximityEffect])
probe2.expectMsgClass(1 second, classOf[ProximityUnit.Action])
probe2.expectMsgClass(5 second, classOf[ProximityUnit.Action])
terminal.Actor.tell(CommonMessages.Use(avatar2, Some(avatar2)), probe3.ref)
probe1.expectNoMessage(1 second)
@ -313,15 +316,17 @@ class ProximityTerminalControlStopTest extends ActorTest {
)
)
avatar.Continent = "test"
avatar.Zone = zone
avatar.Spawn()
avatar.Health = 50
avatar.Health = 1
avatar.GUID = PlanetSideGUID(1)
terminal.GUID = PlanetSideGUID(2)
terminal.Actor ! Service.Startup()
expectNoMessage(500 milliseconds) //spacer
val probe1 = new TestProbe(system, "local-events")
val probe2 = new TestProbe(system, "target-callback-1")
val probe2 = new TestProbe(system, "target-callback")
zone.AvatarEvents = new TestProbe(system, "avatar-events-throwaway").ref
zone.LocalEvents = probe1.ref
"send out a stop message" in {
@ -333,6 +338,14 @@ class ProximityTerminalControlStopTest extends ActorTest {
probe2.expectMsgClass(1 second, classOf[ProximityUnit.Action])
terminal.Actor ! CommonMessages.Unuse(avatar, Some(avatar))
probe2.fishForMessage(2.seconds, hint = "could not find StopAction") {
case _ : ProximityUnit.Action => false
case _ => true
} match {
case _ : ProximityUnit.StopAction => ;
case out => assert(false, s"last message $out is not StopAction")
}
//probe2.expectMsgClass(1 second, classOf[ProximityUnit.StopAction])
probe1.expectMsgClass(1 second, classOf[Terminal.StopProximityEffect])
assert(terminal.NumberUsers == 0)
}