redid DamageFeedbackMessage packet because I thought I could use it for something; didn't use it for anything; boomers are no longer responsive to explosive sympathy

This commit is contained in:
Fate-JH 2024-05-28 23:02:32 -04:00
parent 82222d7c0b
commit fa9ba7e7da
7 changed files with 216 additions and 261 deletions

View file

@ -162,8 +162,7 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
case None => () case None => ()
} }
val eagleEye: Boolean = ops.canSeeReallyFar val eagleEye: Boolean = ops.canSeeReallyFar
val isNotVisible: Boolean = player.spectator || val isNotVisible: Boolean = sessionLogic.zoning.zoningStatus == Zoning.Status.Deconstructing ||
sessionLogic.zoning.zoningStatus == Zoning.Status.Deconstructing ||
(player.isAlive && sessionLogic.zoning.spawn.deadState == DeadState.RespawnTime) (player.isAlive && sessionLogic.zoning.spawn.deadState == DeadState.RespawnTime)
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! AvatarServiceMessage(
continent.id, continent.id,
@ -716,7 +715,7 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
val (target1, target2, bailProtectStatus, velocity) = (ctype, sessionLogic.validObject(p, decorator = "GenericCollision/Primary")) match { val (target1, target2, bailProtectStatus, velocity) = (ctype, sessionLogic.validObject(p, decorator = "GenericCollision/Primary")) match {
case (CollisionIs.OfInfantry, out @ Some(user: Player)) case (CollisionIs.OfInfantry, out @ Some(user: Player))
if user == player => if user == player =>
val bailStatus = session.flying || player.spectator || session.speed > 1f || player.BailProtection val bailStatus = session.flying || session.speed > 1f || player.BailProtection
player.BailProtection = false player.BailProtection = false
val v = if (player.avatar.implants.exists { val v = if (player.avatar.implants.exists {
case Some(implant) => implant.definition.implantType == ImplantType.Surge && implant.active case Some(implant) => implant.definition.implantType == ImplantType.Surge && implant.active

View file

@ -4,8 +4,11 @@ package net.psforever.objects
import akka.actor.{ActorContext, Props} import akka.actor.{ActorContext, Props}
import net.psforever.objects.ce.{Deployable, DeployedItem} import net.psforever.objects.ce.{Deployable, DeployedItem}
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow} import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.objects.serverobject.damage.Damageable
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject} import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
import net.psforever.objects.sourcing.{PlayerSource, SourceEntry} import net.psforever.objects.sourcing.{PlayerSource, SourceEntry}
import net.psforever.objects.vital.Vitality
import net.psforever.objects.vital.etc.TriggerUsedReason import net.psforever.objects.vital.etc.TriggerUsedReason
import net.psforever.objects.vital.interaction.DamageInteraction import net.psforever.objects.vital.interaction.DamageInteraction
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
@ -58,8 +61,7 @@ class BoomerDeployableControl(mine: BoomerDeployable)
case CommonMessages.Use(player, Some(trigger: BoomerTrigger)) if mine.Trigger.contains(trigger) => case CommonMessages.Use(player, Some(trigger: BoomerTrigger)) if mine.Trigger.contains(trigger) =>
// the trigger damages the mine, which sets it off, which causes an explosion // the trigger damages the mine, which sets it off, which causes an explosion
// think of this as an initiator to the proper explosion // think of this as an initiator to the proper explosion
mine.Destroyed = true HandleDamage(
ExplosiveDeployableControl.DamageResolution(
mine, mine,
DamageInteraction( DamageInteraction(
SourceEntry(mine), SourceEntry(mine),
@ -68,8 +70,7 @@ class BoomerDeployableControl(mine: BoomerDeployable)
).calculate()(mine), ).calculate()(mine),
damage = 0 damage = 0
) )
case _ => ()
case _ => ;
} }
def loseOwnership(@unused faction: PlanetSideEmpire.Value): Unit = { def loseOwnership(@unused faction: PlanetSideEmpire.Value): Unit = {
@ -97,14 +98,27 @@ class BoomerDeployableControl(mine: BoomerDeployable)
container.Slot(index).Equipment = None container.Slot(index).Equipment = None
case Some(Zone.EquipmentIs.OnGround()) => case Some(Zone.EquipmentIs.OnGround()) =>
zone.Ground ! Zone.Ground.RemoveItem(guid) zone.Ground ! Zone.Ground.RemoveItem(guid)
case _ => ; case _ => ()
} }
zone.AvatarEvents! AvatarServiceMessage( zone.AvatarEvents! AvatarServiceMessage(
zone.id, zone.id,
AvatarAction.ObjectDelete(Service.defaultPlayerGUID, guid) AvatarAction.ObjectDelete(Service.defaultPlayerGUID, guid)
) )
TaskWorkflow.execute(GUIDTask.unregisterObject(zone.GUID, trigger)) TaskWorkflow.execute(GUIDTask.unregisterObject(zone.GUID, trigger))
case None => ; case None => ()
} }
} }
/**
* Boomers are not bothered by explosive sympathy
* but can still be affected by sources of jammering.
* @param obj the entity being damaged
* @param damage the amount of damage
* @param data historical information about the damage
* @return `true`, if the target can be affected;
* `false`, otherwise
*/
override def CanDetonate(obj: Vitality with FactionAffinity, damage: Int, data: DamageInteraction): Boolean = {
!mine.Destroyed && (data.cause.isInstanceOf[TriggerUsedReason] || Damageable.CanJammer(obj, data))
}
} }

View file

@ -90,14 +90,34 @@ abstract class ExplosiveDeployableControl(mine: ExplosiveDeployable)
val originalHealth = mine.Health val originalHealth = mine.Health
val cause = applyDamageTo(mine) val cause = applyDamageTo(mine)
val damage = originalHealth - mine.Health val damage = originalHealth - mine.Health
if (CanDetonate(mine, damage, cause.interaction)) { if (Interaction(mine, damage, cause.interaction)) {
ExplosiveDeployableControl.DamageResolution(mine, cause, damage) HandleDamage(mine, cause, damage)
} else { } else {
mine.Health = originalHealth mine.Health = originalHealth
} }
} }
} }
def Interaction(obj: Vitality with FactionAffinity, damage: Int, data: DamageInteraction): Boolean = {
!mine.Destroyed && (if (damage == 0 && data.cause.source.SympatheticExplosion) {
Damageable.CanDamageOrJammer(obj, damage = 1, data)
} else {
Damageable.CanDamageOrJammer(obj, damage, data)
})
}
final def HandleDamage(target: ExplosiveDeployable, cause: DamageResult, damage: Int): Unit = {
target.LogActivity(cause)
if (CanDetonate(target, damage, cause.interaction)) {
ExplosiveDeployableControl.explodes(target, cause)
ExplosiveDeployableControl.DestructionAwareness(target, cause)
} else if (target.Health == 0) {
ExplosiveDeployableControl.DestructionAwareness(target, cause)
} else {
ExplosiveDeployableControl.DamageAwareness(target, cause, damage)
}
}
/** /**
* A supplement for checking target susceptibility * A supplement for checking target susceptibility
* to account for sympathetic explosives even if there is no damage. * to account for sympathetic explosives even if there is no damage.
@ -117,6 +137,11 @@ abstract class ExplosiveDeployableControl(mine: ExplosiveDeployable)
Damageable.CanDamageOrJammer(mine, damage, data) Damageable.CanDamageOrJammer(mine, damage, data)
}) })
} }
def explode(target: ExplosiveDeployable, cause: DamageResult): Unit = {
ExplosiveDeployableControl.explodes(target, cause)
ExplosiveDeployableControl.DestructionAwareness(target, cause)
}
} }
object ExplosiveDeployableControl { object ExplosiveDeployableControl {
@ -126,14 +151,8 @@ object ExplosiveDeployableControl {
* @param cause na * @param cause na
* @param damage na * @param damage na
*/ */
def DamageResolution(target: ExplosiveDeployable, cause: DamageResult, damage: Int): Unit = { def DamageAwareness(target: ExplosiveDeployable, cause: DamageResult, damage: Int): Unit = {
target.LogActivity(cause) if (!target.Jammed && Damageable.CanJammer(target, cause.interaction)) {
if (cause.interaction.cause.source.SympatheticExplosion) {
explodes(target, cause)
DestructionAwareness(target, cause)
} else if (target.Health == 0) {
DestructionAwareness(target, cause)
} else if (!target.Jammed && Damageable.CanJammer(target, cause.interaction)) {
if ( { if ( {
target.Jammed = cause.interaction.cause match { target.Jammed = cause.interaction.cause match {
case o: ProjectileReason => case o: ProjectileReason =>
@ -158,6 +177,7 @@ object ExplosiveDeployableControl {
* @param cause na * @param cause na
*/ */
def explodes(target: Damageable.Target, cause: DamageResult): Unit = { def explodes(target: Damageable.Target, cause: DamageResult): Unit = {
target.Destroyed = true
target.Health = 1 // short-circuit logic in DestructionAwareness target.Health = 1 // short-circuit logic in DestructionAwareness
val zone = target.Zone val zone = target.Zone
zone.Activity ! Zone.HotSpot.Activity(cause) zone.Activity ! Zone.HotSpot.Activity(cause)
@ -268,7 +288,7 @@ class MineDeployableControl(mine: ExplosiveDeployable)
mine.Definition.innateDamage.map { _.DamageRadius }.getOrElse(mine.Definition.triggerRadius) mine.Definition.innateDamage.map { _.DamageRadius }.getOrElse(mine.Definition.triggerRadius)
)) ))
case _ => ; case _ => ()
} }
override def finalizeDeployable(callback: ActorRef): Unit = { override def finalizeDeployable(callback: ActorRef): Unit = {
@ -287,33 +307,36 @@ class MineDeployableControl(mine: ExplosiveDeployable)
} }
def setTriggered(instigator: Option[PlanetSideServerObject], delay: Long): Unit = { def setTriggered(instigator: Option[PlanetSideServerObject], delay: Long): Unit = {
instigator match { instigator
case Some(_) if isConstructed.contains(true) && setup.isCancelled => .collect {
//re-use the setup timer here case _ if isConstructed.contains(true) && setup.isCancelled =>
import scala.concurrent.ExecutionContext.Implicits.global //re-use the setup timer here
setup = context.system.scheduler.scheduleOnce(delay milliseconds, self, MineDeployableControl.Triggered()) import scala.concurrent.ExecutionContext.Implicits.global
case _ => ; setup = context.system.scheduler.scheduleOnce(delay milliseconds, self, MineDeployableControl.Triggered())
} }
} }
def explodes(instigator: Option[PlanetSideServerObject]): Unit = { def explodes(instigator: Option[PlanetSideServerObject]): Unit = {
instigator match { instigator
case Some(_) => .collect {
//explosion case _ =>
mine.Destroyed = true //explosion
ExplosiveDeployableControl.DamageResolution( mine.Destroyed = true
mine, ExplosiveDeployableControl.DamageAwareness(
DamageInteraction( mine,
SourceEntry(mine), DamageInteraction(
MineDeployableControl.trippedMineReason(mine), SourceEntry(mine),
mine.Position MineDeployableControl.trippedMineReason(mine),
).calculate()(mine), mine.Position
damage = 0 ).calculate()(mine),
) damage = 0
case None => )
}
.orElse {
//reset //reset
setup = Default.Cancellable setup = Default.Cancellable
} None
}
} }
} }

View file

@ -34,7 +34,7 @@ object GlobalDefinitionsDeployable {
boomer.Name = "boomer" boomer.Name = "boomer"
boomer.Descriptor = "Boomers" boomer.Descriptor = "Boomers"
boomer.MaxHealth = 100 boomer.MaxHealth = 50
boomer.Damageable = true boomer.Damageable = true
boomer.DamageableByFriendlyFire = false boomer.DamageableByFriendlyFire = false
boomer.Repairable = false boomer.Repairable = false
@ -58,7 +58,7 @@ object GlobalDefinitionsDeployable {
he_mine.Name = "he_mine" he_mine.Name = "he_mine"
he_mine.Descriptor = "Mines" he_mine.Descriptor = "Mines"
he_mine.MaxHealth = 100 he_mine.MaxHealth = 50
he_mine.Damageable = true he_mine.Damageable = true
he_mine.DamageableByFriendlyFire = false he_mine.DamageableByFriendlyFire = false
he_mine.Repairable = false he_mine.Repairable = false
@ -82,7 +82,7 @@ object GlobalDefinitionsDeployable {
jammer_mine.Name = "jammer_mine" jammer_mine.Name = "jammer_mine"
jammer_mine.Descriptor = "JammerMines" jammer_mine.Descriptor = "JammerMines"
jammer_mine.MaxHealth = 100 jammer_mine.MaxHealth = 50
jammer_mine.Damageable = true jammer_mine.Damageable = true
jammer_mine.DamageableByFriendlyFire = false jammer_mine.DamageableByFriendlyFire = false
jammer_mine.Repairable = false jammer_mine.Repairable = false

View file

@ -50,7 +50,6 @@ final case class TriggerUsedReason(user: PlayerSource, item_guid: PlanetSideGUID
object TriggerUsedReason { object TriggerUsedReason {
private val triggered = new DamageProperties { private val triggered = new DamageProperties {
Damage0 = 1 //token damage Damage0 = 1 //token damage
SympatheticExplosion = true //sets off a boomer
} }
/** basic damage, no resisting, quick and simple */ /** basic damage, no resisting, quick and simple */

View file

@ -1,51 +1,55 @@
// Copyright (c) 2019 PSForever // Copyright (c) 2019 PSForever
package net.psforever.packet.game package net.psforever.packet.game
import net.psforever.packet.GamePacketOpcode.Type
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket} import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
import net.psforever.types.PlanetSideGUID import net.psforever.types.PlanetSideGUID
import scodec.Codec import scodec.bits.BitVector
import scodec.{Attempt, Codec}
import scodec.codecs._ import scodec.codecs._
import shapeless.{::, HNil} import shapeless.{::, HNil}
/** /**
* na * na
* @param unk1 na * @param unk1 na
* @param unk2 if no global unique identifier (below), the alternate identification for the entity * @param unk2 a modifier that customizes one of the values for the `unk2...` determination values;
* @param unk2a the global unique identifier of the entity inflicting the damage * when not using the GUID field, `true` when using the string field
* @param unk2b if no global unique identifier (above), the name of the entity inflicting the damage * @param unk2a the global unique identifier of the entity inflicting the damage
* @param unk2c if no global unique identifier (above), the object type of the entity inflicting the damage * @param unk2b if no global unique identifier (above), the name of the entity inflicting the damage
* @param unk3 if no global unique identifier (below), the alternate identification for the entity * @param unk2c if no global unique identifier (above), the object type of the entity inflicting the damage
* @param unk3a the global unique identifier of the entity absorbing the damage * @param unk3 a modifier that customizes one of the values for the `unk3...` determination values;
* @param unk3b if no global unique identifier (above), the name of the entity absorbing the damage * when not using the GUID field, `true` when using the string field
* @param unk3c if no global unique identifier (above), the object type of the entity absorbing the damage * @param unk3a the global unique identifier of the entity absorbing the damage
* @param unk3d na * @param unk3b if no global unique identifier (above), the name of the entity absorbing the damage
* @param unk4 an indicator for the target-specific vital statistic being affected * @param unk3c if no global unique identifier (above), the object type of the entity absorbing the damage
* @param unk5 the amount of damage * @param unk3d na
* @param unk6 na * @param unk4 an indicator for the target-specific vital statistic being affected
*/ * @param unk5 the amount of damage
* @param unk6 na
*/
final case class DamageFeedbackMessage( final case class DamageFeedbackMessage(
unk1: Int, unk1: Int,
unk2: Boolean, unk2: Option[Boolean],
unk2a: Option[PlanetSideGUID], unk2a: Option[PlanetSideGUID],
unk2b: Option[String], unk2b: Option[String],
unk2c: Option[Int], unk2c: Option[Int],
unk3: Boolean, unk3: Option[Boolean],
unk3a: Option[PlanetSideGUID], unk3a: Option[PlanetSideGUID],
unk3b: Option[String], unk3b: Option[String],
unk3c: Option[Int], unk3c: Option[Int],
unk3d: Option[Int], unk3d: Option[Int],
unk4: Int, unk4: Int,
unk5: Long, unk5: Long,
unk6: Int unk6: Int
) extends PlanetSideGamePacket { ) extends PlanetSideGamePacket {
assert( assert(
{ {
val unk2aEmpty = unk2a.isEmpty val unk2aEmpty = unk2a.isEmpty
val unk2bEmpty = unk2b.isEmpty val unk2bEmpty = unk2b.isEmpty
val unk2cEmpty = unk2c.isEmpty val unk2cEmpty = unk2c.isEmpty
if (unk2a.nonEmpty) unk2bEmpty && unk2cEmpty if (!unk2aEmpty) unk2bEmpty && unk2cEmpty
else if (unk2b.nonEmpty) unk2 && unk2aEmpty && unk2cEmpty else if (!unk2bEmpty) unk2aEmpty && unk2cEmpty
else unk2aEmpty && !unk2 && unk2bEmpty && unk2c.nonEmpty else unk2aEmpty && unk2bEmpty && !unk2cEmpty
} }
) )
assert( assert(
@ -53,58 +57,104 @@ final case class DamageFeedbackMessage(
val unk3aEmpty = unk3a.isEmpty val unk3aEmpty = unk3a.isEmpty
val unk3bEmpty = unk3b.isEmpty val unk3bEmpty = unk3b.isEmpty
val unk3cEmpty = unk3c.isEmpty val unk3cEmpty = unk3c.isEmpty
if (unk3a.nonEmpty) unk3bEmpty && unk3cEmpty if (!unk3aEmpty) unk3bEmpty && unk3cEmpty
else if (unk3b.nonEmpty) unk3 && unk3aEmpty && unk3cEmpty else if (!unk3bEmpty) unk3aEmpty && unk3cEmpty
else unk3aEmpty && !unk3 && unk3bEmpty && unk3c.nonEmpty else unk3aEmpty && unk3bEmpty && !unk3cEmpty
} }
) )
assert(unk3a.isEmpty == unk3d.nonEmpty) assert(unk3a.isEmpty == unk3d.nonEmpty)
type Packet = DamageFeedbackMessage type Packet = DamageFeedbackMessage
def opcode = GamePacketOpcode.DamageFeedbackMessage def opcode: Type = GamePacketOpcode.DamageFeedbackMessage
def encode = DamageFeedbackMessage.encode(this) def encode: Attempt[BitVector] = DamageFeedbackMessage.encode(this)
} }
object DamageFeedbackMessage extends Marshallable[DamageFeedbackMessage] { object DamageFeedbackMessage extends Marshallable[DamageFeedbackMessage] {
def apply(unk1: Int, def apply(
unk2: PlanetSideGUID, unk1: Int,
unk3: PlanetSideGUID, unk2a: Option[PlanetSideGUID],
unk4: Int, unk2b: Option[String],
unk5: Long): DamageFeedbackMessage = unk2c: Option[Int],
DamageFeedbackMessage(unk1, true, Some(unk2), None, None, true, Some(unk3), None, None, None, unk4, unk5, 0) unk3a: Option[PlanetSideGUID],
unk3b: Option[String],
unk3c: Option[Int],
unk3d: Option[Int],
unk4: Int,
unk5: Long
): DamageFeedbackMessage = {
DamageFeedbackMessage(unk1, None, unk2a, unk2b, unk2c, None, unk3a, unk3b, unk3c, unk3d, unk4, unk5, 0)
}
def apply(
unk1: Int,
unk2: PlanetSideGUID,
unk3: PlanetSideGUID,
unk4: Int,
unk5: Long
): DamageFeedbackMessage = {
DamageFeedbackMessage(unk1, None, Some(unk2), None, None, None, Some(unk3), None, None, None, unk4, unk5, 0)
}
private case class EntryFields(
usesGuid: Boolean,
usesStr: Boolean,
guidOpt: Option[PlanetSideGUID],
strOpt: Option[String],
intOpt: Option[Int]
)
/**
* na
* @param adjustment na;
* can not be a negative number
* @return na
*/
private def entityFieldFormatCodec(adjustment: Int): Codec[EntryFields] = {
((bool :: bool) >>:~ { case usesGuid :: usesString :: HNil =>
conditional(usesGuid, PlanetSideGUID.codec) ::
conditional(!usesGuid && usesString, PacketHelpers.encodedWideStringAligned(adjustment)) ::
conditional(!usesGuid && !usesString, uintL(bits = 11))
}).xmap[EntryFields](
{
case (a :: b :: HNil) :: c :: d :: e :: HNil => EntryFields(a, b, c, d, e)
},
{
case EntryFields(a, b, c, d, e) => (a :: b :: HNil) :: c :: d :: e :: HNil
}
)
}
implicit val codec: Codec[DamageFeedbackMessage] = ( implicit val codec: Codec[DamageFeedbackMessage] = (
("unk1" | uint4) :: ("unk1" | uint4) :: {
(bool >>:~ { u2 => entityFieldFormatCodec(adjustment = 4) >>:~ { fieldsA =>
bool >>:~ { u3 => val offset = if (fieldsA.usesGuid) { 0 } else if (fieldsA.usesStr) { 6 } else { 5 }
("unk2a" | conditional(u2, PlanetSideGUID.codec)) :: entityFieldFormatCodec(offset) >>:~ { fieldsB =>
(("unk2b" | conditional(!u2 && u3, PacketHelpers.encodedWideStringAligned(6))) >>:~ { u2b => ("unk3d" | conditional(!fieldsB.usesGuid, uint2)) ::
("unk2c" | conditional(!u2 && !u3, uintL(11))) :: ("unk4" | uint(bits = 3)) ::
(bool >>:~ { u5 => ("unk5" | uint32L) ::
bool >>:~ { u6 => ("unk6" | uint2)
("unk3a" | conditional(u5, PlanetSideGUID.codec)) :: }
("unk3b" | conditional(
!u5 && u6,
PacketHelpers.encodedWideStringAligned(if (u2b.nonEmpty) 3 else 1)
)) ::
("unk3c" | conditional(!u5 && !u6, uintL(11))) ::
("unk3d" | conditional(!u5, uint2)) ::
("unk4" | uint(3)) ::
("unk5" | uint32L) ::
("unk6" | uint2)
}
})
})
} }
}) }).xmap[DamageFeedbackMessage](
).xmap[DamageFeedbackMessage](
{ {
case u1 :: _ :: u2 :: u2a :: u2b :: u2c :: _ :: u3 :: u3a :: u3b :: u3c :: u3d :: u4 :: u5 :: u6 :: HNil => case u1 :: EntryFields(_, u2, u2a, u2b, u2c) :: EntryFields(_, u3, u3a, u3b, u3c) :: u3d :: u4 :: u5 :: u6 :: HNil =>
DamageFeedbackMessage(u1, u2, u2a, u2b, u2c, u3, u3a, u3b, u3c, u3d, u4, u5, u6) val u2False = if (u2a.nonEmpty && !u2) { Some(false) } else { None }
val u3False = if (u3a.nonEmpty && !u3) { Some(false) } else { None }
DamageFeedbackMessage(u1, u2False, u2a, u2b, u2c, u3False, u3a, u3b, u3c, u3d, u4, u5, u6)
}, },
{ {
case DamageFeedbackMessage(u1, u2, u2a, u2b, u2c, u3, u3a, u3b, u3c, u3d, u4, u5, u6) => case DamageFeedbackMessage(u1, u2, u2a, u2b, u2c, u3, u3a, u3b, u3c, u3d, u4, u5, u6) =>
u1 :: u2a.nonEmpty :: u2 :: u2a :: u2b :: u2c :: u3a.nonEmpty :: u3 :: u3a :: u3b :: u3c :: u3d :: u4 :: u5 :: u6 :: HNil val(u2Boola, u2Boolb) = if (u2a.nonEmpty) {
(true, u2.getOrElse(true))
} else {
(false, u2b.nonEmpty)
}
val(u3Boola, u3Boolb) = if (u3a.nonEmpty) {
(true, u3.getOrElse(true))
} else {
(false, u3b.nonEmpty)
}
u1 :: EntryFields(u2Boola, u2Boolb, u2a, u2b, u2c) :: EntryFields(u3Boola, u3Boolb, u3a, u3b, u3c) :: u3d :: u4 :: u5 :: u6 :: HNil
} }
) )
} }

View file

@ -13,13 +13,11 @@ class DamageFeedbackMessageTest extends Specification {
"decode (string 1)" in { "decode (string 1)" in {
PacketCoding.decodePacket(string).require match { PacketCoding.decodePacket(string).require match {
case DamageFeedbackMessage(unk1, unk2, unk2a, unk2b, unk2c, unk3, unk3a, unk3b, unk3c, unk3d, unk4, unk5, unk6) => case DamageFeedbackMessage(unk1, _, unk2a, unk2b, unk2c, _, unk3a, unk3b, unk3c, unk3d, unk4, unk5, unk6) =>
unk1 mustEqual 3 unk1 mustEqual 3
unk2 mustEqual true
unk2a.contains(PlanetSideGUID(2913)) mustEqual true unk2a.contains(PlanetSideGUID(2913)) mustEqual true
unk2b.isEmpty mustEqual true unk2b.isEmpty mustEqual true
unk2c.isEmpty mustEqual true unk2c.isEmpty mustEqual true
unk3 mustEqual true
unk3a.contains(PlanetSideGUID(2913)) mustEqual true unk3a.contains(PlanetSideGUID(2913)) mustEqual true
unk3b.isEmpty mustEqual true unk3b.isEmpty mustEqual true
unk3c.isEmpty mustEqual true unk3c.isEmpty mustEqual true
@ -34,13 +32,11 @@ class DamageFeedbackMessageTest extends Specification {
"decode (string 2)" in { "decode (string 2)" in {
PacketCoding.decodePacket(string_2).require match { PacketCoding.decodePacket(string_2).require match {
case DamageFeedbackMessage(unk1, unk2, unk2a, unk2b, unk2c, unk3, unk3a, unk3b, unk3c, unk3d, unk4, unk5, unk6) => case DamageFeedbackMessage(unk1, _, unk2a, unk2b, unk2c, _, unk3a, unk3b, unk3c, unk3d, unk4, unk5, unk6) =>
unk1 mustEqual 5 unk1 mustEqual 5
unk2 mustEqual true
unk2a.contains(PlanetSideGUID(2454)) mustEqual true unk2a.contains(PlanetSideGUID(2454)) mustEqual true
unk2b.isEmpty mustEqual true unk2b.isEmpty mustEqual true
unk2c.isEmpty mustEqual true unk2c.isEmpty mustEqual true
unk3 mustEqual false
unk3a.contains(PlanetSideGUID(216)) mustEqual true unk3a.contains(PlanetSideGUID(216)) mustEqual true
unk3b.isEmpty mustEqual true unk3b.isEmpty mustEqual true
unk3c.isEmpty mustEqual true unk3c.isEmpty mustEqual true
@ -56,18 +52,15 @@ class DamageFeedbackMessageTest extends Specification {
"encode (string 1)" in { "encode (string 1)" in {
val msg = DamageFeedbackMessage( val msg = DamageFeedbackMessage(
3, 3,
true,
Some(PlanetSideGUID(2913)), Some(PlanetSideGUID(2913)),
None, None,
None, None,
true,
Some(PlanetSideGUID(2913)), Some(PlanetSideGUID(2913)),
None, None,
None, None,
None, None,
1, 1,
2, 2
0
) )
val pkt = PacketCoding.encodePacket(msg).require.toByteVector val pkt = PacketCoding.encodePacket(msg).require.toByteVector
@ -77,11 +70,11 @@ class DamageFeedbackMessageTest extends Specification {
"encode (string 2)" in { "encode (string 2)" in {
val msg = DamageFeedbackMessage( val msg = DamageFeedbackMessage(
5, 5,
true, None,
Some(PlanetSideGUID(2454)), Some(PlanetSideGUID(2454)),
None, None,
None, None,
false, Some(false),
Some(PlanetSideGUID(216)), Some(PlanetSideGUID(216)),
None, None,
None, None,
@ -99,252 +92,129 @@ class DamageFeedbackMessageTest extends Specification {
//unk2: no parameters //unk2: no parameters
DamageFeedbackMessage( DamageFeedbackMessage(
3, 3,
true,
None, None,
None, None,
None, None,
true,
Some(PlanetSideGUID(2913)), Some(PlanetSideGUID(2913)),
None, None,
None, None,
None, None,
1, 1,
2, 2
0
) must throwA[AssertionError] ) must throwA[AssertionError]
//unk2: two exclusive parameters //unk2: two exclusive parameters
DamageFeedbackMessage( DamageFeedbackMessage(
3, 3,
true,
Some(PlanetSideGUID(2913)), Some(PlanetSideGUID(2913)),
Some("error"), Some("error"),
None, None,
true,
Some(PlanetSideGUID(2913)), Some(PlanetSideGUID(2913)),
None, None,
None, None,
None, None,
1, 1,
2, 2
0
) must throwA[AssertionError] ) must throwA[AssertionError]
DamageFeedbackMessage( DamageFeedbackMessage(
3, 3,
true,
Some(PlanetSideGUID(2913)), Some(PlanetSideGUID(2913)),
None, None,
Some(5), Some(5),
true,
Some(PlanetSideGUID(2913)), Some(PlanetSideGUID(2913)),
None, None,
None, None,
None, None,
1, 1,
2, 2
0
) must throwA[AssertionError] ) must throwA[AssertionError]
DamageFeedbackMessage( DamageFeedbackMessage(
3, 3,
true,
None, None,
Some("error"), Some("error"),
Some(5), Some(5),
true,
Some(PlanetSideGUID(2913)), Some(PlanetSideGUID(2913)),
None, None,
None, None,
None, None,
1, 1,
2, 2
0
) must throwA[AssertionError] ) must throwA[AssertionError]
//unk2: all parameters //unk2: all parameters
DamageFeedbackMessage( DamageFeedbackMessage(
3, 3,
true,
Some(PlanetSideGUID(2913)), Some(PlanetSideGUID(2913)),
Some("error"), Some("error"),
Some(5), Some(5),
true,
Some(PlanetSideGUID(2913)), Some(PlanetSideGUID(2913)),
None, None,
None, None,
None, None,
1, 1,
2, 2
0
) must throwA[AssertionError]
//unk2: mismatched flag for strings
DamageFeedbackMessage(
3,
true,
None,
None,
Some(5),
true,
Some(PlanetSideGUID(2913)),
None,
None,
None,
1,
2,
0
) must throwA[AssertionError]
DamageFeedbackMessage(
3,
false,
None,
Some("error"),
None,
true,
Some(PlanetSideGUID(2913)),
None,
None,
None,
1,
2,
0
) must throwA[AssertionError] ) must throwA[AssertionError]
//unk3: no parameters //unk3: no parameters
DamageFeedbackMessage( DamageFeedbackMessage(
3, 3,
true,
Some(PlanetSideGUID(2913)), Some(PlanetSideGUID(2913)),
None, None,
None, None,
true,
None, None,
None, None,
None, None,
None, None,
1, 1,
2, 2
0
) must throwA[AssertionError] ) must throwA[AssertionError]
//unk3: two exclusive parameters //unk3: two exclusive parameters
DamageFeedbackMessage( DamageFeedbackMessage(
3, 3,
true,
Some(PlanetSideGUID(2913)), Some(PlanetSideGUID(2913)),
None, None,
None, None,
true,
Some(PlanetSideGUID(2913)), Some(PlanetSideGUID(2913)),
Some("error"), Some("error"),
None, None,
None, None,
1, 1,
2, 2
0
) must throwA[AssertionError] ) must throwA[AssertionError]
DamageFeedbackMessage( DamageFeedbackMessage(
3, 3,
true,
Some(PlanetSideGUID(2913)), Some(PlanetSideGUID(2913)),
None, None,
None, None,
true,
Some(PlanetSideGUID(2913)), Some(PlanetSideGUID(2913)),
None, None,
Some(5), Some(5),
None, None,
1, 1,
2, 2
0
) must throwA[AssertionError] ) must throwA[AssertionError]
DamageFeedbackMessage( DamageFeedbackMessage(
3, 3,
true,
Some(PlanetSideGUID(2913)), Some(PlanetSideGUID(2913)),
None, None,
None, None,
true,
None, None,
Some("error"), Some("error"),
Some(5), Some(5),
Some(1), Some(1),
1, 1,
2, 2
0
) must throwA[AssertionError] ) must throwA[AssertionError]
//unk3: all parameters //unk3: all parameters
DamageFeedbackMessage( DamageFeedbackMessage(
3, 3,
true,
Some(PlanetSideGUID(2913)), Some(PlanetSideGUID(2913)),
None, None,
None, None,
true,
Some(PlanetSideGUID(2913)), Some(PlanetSideGUID(2913)),
Some("error"), Some("error"),
Some(5), Some(5),
None, None,
1, 1,
2, 2
0
) must throwA[AssertionError]
//unk3: mismatched fields
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
None,
None,
true,
Some(PlanetSideGUID(2913)),
None,
None,
Some(5),
1,
2,
0
) must throwA[AssertionError]
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
None,
None,
true,
None,
Some("Error"),
None,
None,
1,
2,
0
) must throwA[AssertionError]
//unk3: mismatched flag for strings
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
None,
None,
true,
None,
None,
Some(5),
None,
1,
2,
0
) must throwA[AssertionError]
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
None,
None,
false,
None,
Some("error"),
None,
None,
1,
2,
0
) must throwA[AssertionError] ) must throwA[AssertionError]
} }
} }