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 => ()
}
val eagleEye: Boolean = ops.canSeeReallyFar
val isNotVisible: Boolean = player.spectator ||
sessionLogic.zoning.zoningStatus == Zoning.Status.Deconstructing ||
val isNotVisible: Boolean = sessionLogic.zoning.zoningStatus == Zoning.Status.Deconstructing ||
(player.isAlive && sessionLogic.zoning.spawn.deadState == DeadState.RespawnTime)
continent.AvatarEvents ! AvatarServiceMessage(
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 {
case (CollisionIs.OfInfantry, out @ Some(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
val v = if (player.avatar.implants.exists {
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 net.psforever.objects.ce.{Deployable, DeployedItem}
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.sourcing.{PlayerSource, SourceEntry}
import net.psforever.objects.vital.Vitality
import net.psforever.objects.vital.etc.TriggerUsedReason
import net.psforever.objects.vital.interaction.DamageInteraction
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) =>
// the trigger damages the mine, which sets it off, which causes an explosion
// think of this as an initiator to the proper explosion
mine.Destroyed = true
ExplosiveDeployableControl.DamageResolution(
HandleDamage(
mine,
DamageInteraction(
SourceEntry(mine),
@ -68,8 +70,7 @@ class BoomerDeployableControl(mine: BoomerDeployable)
).calculate()(mine),
damage = 0
)
case _ => ;
case _ => ()
}
def loseOwnership(@unused faction: PlanetSideEmpire.Value): Unit = {
@ -97,14 +98,27 @@ class BoomerDeployableControl(mine: BoomerDeployable)
container.Slot(index).Equipment = None
case Some(Zone.EquipmentIs.OnGround()) =>
zone.Ground ! Zone.Ground.RemoveItem(guid)
case _ => ;
case _ => ()
}
zone.AvatarEvents! AvatarServiceMessage(
zone.id,
AvatarAction.ObjectDelete(Service.defaultPlayerGUID, guid)
)
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 cause = applyDamageTo(mine)
val damage = originalHealth - mine.Health
if (CanDetonate(mine, damage, cause.interaction)) {
ExplosiveDeployableControl.DamageResolution(mine, cause, damage)
if (Interaction(mine, damage, cause.interaction)) {
HandleDamage(mine, cause, damage)
} else {
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
* 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)
})
}
def explode(target: ExplosiveDeployable, cause: DamageResult): Unit = {
ExplosiveDeployableControl.explodes(target, cause)
ExplosiveDeployableControl.DestructionAwareness(target, cause)
}
}
object ExplosiveDeployableControl {
@ -126,14 +151,8 @@ object ExplosiveDeployableControl {
* @param cause na
* @param damage na
*/
def DamageResolution(target: ExplosiveDeployable, cause: DamageResult, damage: Int): Unit = {
target.LogActivity(cause)
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)) {
def DamageAwareness(target: ExplosiveDeployable, cause: DamageResult, damage: Int): Unit = {
if (!target.Jammed && Damageable.CanJammer(target, cause.interaction)) {
if ( {
target.Jammed = cause.interaction.cause match {
case o: ProjectileReason =>
@ -158,6 +177,7 @@ object ExplosiveDeployableControl {
* @param cause na
*/
def explodes(target: Damageable.Target, cause: DamageResult): Unit = {
target.Destroyed = true
target.Health = 1 // short-circuit logic in DestructionAwareness
val zone = target.Zone
zone.Activity ! Zone.HotSpot.Activity(cause)
@ -268,7 +288,7 @@ class MineDeployableControl(mine: ExplosiveDeployable)
mine.Definition.innateDamage.map { _.DamageRadius }.getOrElse(mine.Definition.triggerRadius)
))
case _ => ;
case _ => ()
}
override def finalizeDeployable(callback: ActorRef): Unit = {
@ -287,33 +307,36 @@ class MineDeployableControl(mine: ExplosiveDeployable)
}
def setTriggered(instigator: Option[PlanetSideServerObject], delay: Long): Unit = {
instigator match {
case Some(_) if isConstructed.contains(true) && setup.isCancelled =>
//re-use the setup timer here
import scala.concurrent.ExecutionContext.Implicits.global
setup = context.system.scheduler.scheduleOnce(delay milliseconds, self, MineDeployableControl.Triggered())
case _ => ;
}
instigator
.collect {
case _ if isConstructed.contains(true) && setup.isCancelled =>
//re-use the setup timer here
import scala.concurrent.ExecutionContext.Implicits.global
setup = context.system.scheduler.scheduleOnce(delay milliseconds, self, MineDeployableControl.Triggered())
}
}
def explodes(instigator: Option[PlanetSideServerObject]): Unit = {
instigator match {
case Some(_) =>
//explosion
mine.Destroyed = true
ExplosiveDeployableControl.DamageResolution(
mine,
DamageInteraction(
SourceEntry(mine),
MineDeployableControl.trippedMineReason(mine),
mine.Position
).calculate()(mine),
damage = 0
)
case None =>
instigator
.collect {
case _ =>
//explosion
mine.Destroyed = true
ExplosiveDeployableControl.DamageAwareness(
mine,
DamageInteraction(
SourceEntry(mine),
MineDeployableControl.trippedMineReason(mine),
mine.Position
).calculate()(mine),
damage = 0
)
}
.orElse {
//reset
setup = Default.Cancellable
}
None
}
}
}

View file

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

View file

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

View file

@ -1,51 +1,55 @@
// Copyright (c) 2019 PSForever
package net.psforever.packet.game
import net.psforever.packet.GamePacketOpcode.Type
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
import net.psforever.types.PlanetSideGUID
import scodec.Codec
import scodec.bits.BitVector
import scodec.{Attempt, Codec}
import scodec.codecs._
import shapeless.{::, HNil}
/**
* na
* @param unk1 na
* @param unk2 if no global unique identifier (below), the alternate identification for the entity
* @param unk2a the global unique identifier of the entity inflicting the damage
* @param unk2b if no global unique identifier (above), the name of the entity inflicting the damage
* @param unk2c if no global unique identifier (above), the object type of the entity inflicting the damage
* @param unk3 if no global unique identifier (below), the alternate identification for the entity
* @param unk3a the global unique identifier of the entity absorbing the damage
* @param unk3b if no global unique identifier (above), the name of the entity absorbing the damage
* @param unk3c if no global unique identifier (above), the object type of the entity absorbing the damage
* @param unk3d na
* @param unk4 an indicator for the target-specific vital statistic being affected
* @param unk5 the amount of damage
* @param unk6 na
*/
* na
* @param unk1 na
* @param unk2 a modifier that customizes one of the values for the `unk2...` determination values;
* when not using the GUID field, `true` when using the string field
* @param unk2a the global unique identifier of the entity inflicting the damage
* @param unk2b if no global unique identifier (above), the name of the entity inflicting the damage
* @param unk2c if no global unique identifier (above), the object type of the entity inflicting the damage
* @param unk3 a modifier that customizes one of the values for the `unk3...` determination values;
* when not using the GUID field, `true` when using the string field
* @param unk3a the global unique identifier of the entity absorbing the damage
* @param unk3b if no global unique identifier (above), the name of the entity absorbing the damage
* @param unk3c if no global unique identifier (above), the object type of the entity absorbing the damage
* @param unk3d 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(
unk1: Int,
unk2: Boolean,
unk2a: Option[PlanetSideGUID],
unk2b: Option[String],
unk2c: Option[Int],
unk3: Boolean,
unk3a: Option[PlanetSideGUID],
unk3b: Option[String],
unk3c: Option[Int],
unk3d: Option[Int],
unk4: Int,
unk5: Long,
unk6: Int
) extends PlanetSideGamePacket {
unk1: Int,
unk2: Option[Boolean],
unk2a: Option[PlanetSideGUID],
unk2b: Option[String],
unk2c: Option[Int],
unk3: Option[Boolean],
unk3a: Option[PlanetSideGUID],
unk3b: Option[String],
unk3c: Option[Int],
unk3d: Option[Int],
unk4: Int,
unk5: Long,
unk6: Int
) extends PlanetSideGamePacket {
assert(
{
val unk2aEmpty = unk2a.isEmpty
val unk2bEmpty = unk2b.isEmpty
val unk2cEmpty = unk2c.isEmpty
if (unk2a.nonEmpty) unk2bEmpty && unk2cEmpty
else if (unk2b.nonEmpty) unk2 && unk2aEmpty && unk2cEmpty
else unk2aEmpty && !unk2 && unk2bEmpty && unk2c.nonEmpty
if (!unk2aEmpty) unk2bEmpty && unk2cEmpty
else if (!unk2bEmpty) unk2aEmpty && unk2cEmpty
else unk2aEmpty && unk2bEmpty && !unk2cEmpty
}
)
assert(
@ -53,58 +57,104 @@ final case class DamageFeedbackMessage(
val unk3aEmpty = unk3a.isEmpty
val unk3bEmpty = unk3b.isEmpty
val unk3cEmpty = unk3c.isEmpty
if (unk3a.nonEmpty) unk3bEmpty && unk3cEmpty
else if (unk3b.nonEmpty) unk3 && unk3aEmpty && unk3cEmpty
else unk3aEmpty && !unk3 && unk3bEmpty && unk3c.nonEmpty
if (!unk3aEmpty) unk3bEmpty && unk3cEmpty
else if (!unk3bEmpty) unk3aEmpty && unk3cEmpty
else unk3aEmpty && unk3bEmpty && !unk3cEmpty
}
)
assert(unk3a.isEmpty == unk3d.nonEmpty)
type Packet = DamageFeedbackMessage
def opcode = GamePacketOpcode.DamageFeedbackMessage
def encode = DamageFeedbackMessage.encode(this)
def opcode: Type = GamePacketOpcode.DamageFeedbackMessage
def encode: Attempt[BitVector] = DamageFeedbackMessage.encode(this)
}
object DamageFeedbackMessage extends Marshallable[DamageFeedbackMessage] {
def apply(unk1: Int,
unk2: PlanetSideGUID,
unk3: PlanetSideGUID,
unk4: Int,
unk5: Long): DamageFeedbackMessage =
DamageFeedbackMessage(unk1, true, Some(unk2), None, None, true, Some(unk3), None, None, None, unk4, unk5, 0)
def apply(
unk1: Int,
unk2a: Option[PlanetSideGUID],
unk2b: Option[String],
unk2c: Option[Int],
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] = (
("unk1" | uint4) ::
(bool >>:~ { u2 =>
bool >>:~ { u3 =>
("unk2a" | conditional(u2, PlanetSideGUID.codec)) ::
(("unk2b" | conditional(!u2 && u3, PacketHelpers.encodedWideStringAligned(6))) >>:~ { u2b =>
("unk2c" | conditional(!u2 && !u3, uintL(11))) ::
(bool >>:~ { u5 =>
bool >>:~ { u6 =>
("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)
}
})
})
("unk1" | uint4) :: {
entityFieldFormatCodec(adjustment = 4) >>:~ { fieldsA =>
val offset = if (fieldsA.usesGuid) { 0 } else if (fieldsA.usesStr) { 6 } else { 5 }
entityFieldFormatCodec(offset) >>:~ { fieldsB =>
("unk3d" | conditional(!fieldsB.usesGuid, uint2)) ::
("unk4" | uint(bits = 3)) ::
("unk5" | uint32L) ::
("unk6" | uint2)
}
}
})
).xmap[DamageFeedbackMessage](
}).xmap[DamageFeedbackMessage](
{
case u1 :: _ :: u2 :: u2a :: u2b :: u2c :: _ :: u3 :: u3a :: u3b :: u3c :: u3d :: u4 :: u5 :: u6 :: HNil =>
DamageFeedbackMessage(u1, u2, u2a, u2b, u2c, u3, u3a, u3b, u3c, u3d, u4, u5, u6)
case u1 :: EntryFields(_, u2, u2a, u2b, u2c) :: EntryFields(_, u3, u3a, u3b, u3c) :: u3d :: u4 :: u5 :: u6 :: HNil =>
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) =>
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 {
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
unk2 mustEqual true
unk2a.contains(PlanetSideGUID(2913)) mustEqual true
unk2b.isEmpty mustEqual true
unk2c.isEmpty mustEqual true
unk3 mustEqual true
unk3a.contains(PlanetSideGUID(2913)) mustEqual true
unk3b.isEmpty mustEqual true
unk3c.isEmpty mustEqual true
@ -34,13 +32,11 @@ class DamageFeedbackMessageTest extends Specification {
"decode (string 2)" in {
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
unk2 mustEqual true
unk2a.contains(PlanetSideGUID(2454)) mustEqual true
unk2b.isEmpty mustEqual true
unk2c.isEmpty mustEqual true
unk3 mustEqual false
unk3a.contains(PlanetSideGUID(216)) mustEqual true
unk3b.isEmpty mustEqual true
unk3c.isEmpty mustEqual true
@ -56,18 +52,15 @@ class DamageFeedbackMessageTest extends Specification {
"encode (string 1)" in {
val msg = DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
None,
None,
true,
Some(PlanetSideGUID(2913)),
None,
None,
None,
1,
2,
0
2
)
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
@ -77,11 +70,11 @@ class DamageFeedbackMessageTest extends Specification {
"encode (string 2)" in {
val msg = DamageFeedbackMessage(
5,
true,
None,
Some(PlanetSideGUID(2454)),
None,
None,
false,
Some(false),
Some(PlanetSideGUID(216)),
None,
None,
@ -99,252 +92,129 @@ class DamageFeedbackMessageTest extends Specification {
//unk2: no parameters
DamageFeedbackMessage(
3,
true,
None,
None,
None,
true,
Some(PlanetSideGUID(2913)),
None,
None,
None,
1,
2,
0
2
) must throwA[AssertionError]
//unk2: two exclusive parameters
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
Some("error"),
None,
true,
Some(PlanetSideGUID(2913)),
None,
None,
None,
1,
2,
0
2
) must throwA[AssertionError]
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
None,
Some(5),
true,
Some(PlanetSideGUID(2913)),
None,
None,
None,
1,
2,
0
2
) must throwA[AssertionError]
DamageFeedbackMessage(
3,
true,
None,
Some("error"),
Some(5),
true,
Some(PlanetSideGUID(2913)),
None,
None,
None,
1,
2,
0
2
) must throwA[AssertionError]
//unk2: all parameters
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
Some("error"),
Some(5),
true,
Some(PlanetSideGUID(2913)),
None,
None,
None,
1,
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
2
) must throwA[AssertionError]
//unk3: no parameters
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
None,
None,
true,
None,
None,
None,
None,
1,
2,
0
2
) must throwA[AssertionError]
//unk3: two exclusive parameters
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
None,
None,
true,
Some(PlanetSideGUID(2913)),
Some("error"),
None,
None,
1,
2,
0
2
) must throwA[AssertionError]
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
None,
None,
true,
Some(PlanetSideGUID(2913)),
None,
Some(5),
None,
1,
2,
0
2
) must throwA[AssertionError]
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
None,
None,
true,
None,
Some("error"),
Some(5),
Some(1),
1,
2,
0
2
) must throwA[AssertionError]
//unk3: all parameters
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
None,
None,
true,
Some(PlanetSideGUID(2913)),
Some("error"),
Some(5),
None,
1,
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
2
) must throwA[AssertionError]
}
}