Scorpion Death Message (#1044)

* correction to scorpion sub-projectile death message

* redirected the definition fields

* output method of demise to chat; chat will answer us the mystery

* finally attributes the scorpion as the method of demise
This commit is contained in:
Fate-JH 2023-03-06 14:16:56 -05:00 committed by GitHub
parent 36c7a1e520
commit ae66f86f63
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 102 additions and 21 deletions

View file

@ -2,8 +2,6 @@
package net.psforever.actors.session.support package net.psforever.actors.session.support
import akka.actor.{ActorContext, typed} import akka.actor.{ActorContext, typed}
import net.psforever.objects.avatar.scoring.EquipmentStat
import scala.collection.mutable import scala.collection.mutable
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future import scala.concurrent.Future
@ -11,6 +9,7 @@ import scala.concurrent.duration._
// //
import net.psforever.actors.session.{AvatarActor, ChatActor, SessionActor} import net.psforever.actors.session.{AvatarActor, ChatActor, SessionActor}
import net.psforever.login.WorldSession.{CountAmmunition, CountGrenades, FindAmmoBoxThatUses, FindEquipmentStock, FindToolThatUses, PutEquipmentInInventoryOrDrop, PutNewEquipmentInInventoryOrDrop, RemoveOldEquipmentFromInventory} import net.psforever.login.WorldSession.{CountAmmunition, CountGrenades, FindAmmoBoxThatUses, FindEquipmentStock, FindToolThatUses, PutEquipmentInInventoryOrDrop, PutNewEquipmentInInventoryOrDrop, RemoveOldEquipmentFromInventory}
import net.psforever.objects.avatar.scoring.EquipmentStat
import net.psforever.objects.ballistics.{Projectile, ProjectileQuality} import net.psforever.objects.ballistics.{Projectile, ProjectileQuality}
import net.psforever.objects.entity.SimpleWorldEntity import net.psforever.objects.entity.SimpleWorldEntity
import net.psforever.objects.equipment.{ChargeFireModeDefinition, Equipment, EquipmentSize, FireModeSwitch} import net.psforever.objects.equipment.{ChargeFireModeDefinition, Equipment, EquipmentSize, FireModeSwitch}
@ -22,6 +21,7 @@ import net.psforever.objects.serverobject.turret.FacilityTurret
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject} import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
import net.psforever.objects.vital.Vitality import net.psforever.objects.vital.Vitality
import net.psforever.objects.vital.base.{DamageResolution, DamageType} import net.psforever.objects.vital.base.{DamageResolution, DamageType}
import net.psforever.objects.vital.etc.OicwLilBuddyReason
import net.psforever.objects.vital.interaction.DamageInteraction import net.psforever.objects.vital.interaction.DamageInteraction
import net.psforever.objects.vital.projectile.ProjectileReason import net.psforever.objects.vital.projectile.ProjectileReason
import net.psforever.objects.zones.{Zone, ZoneProjectile} import net.psforever.objects.zones.{Zone, ZoneProjectile}
@ -1186,13 +1186,10 @@ private[support] class WeaponAndProjectileOperations(
def HandleDamageProxyLittleBuddyExplosion(proxy: Projectile, orientation: Vector3, distance: Float): Unit = { def HandleDamageProxyLittleBuddyExplosion(proxy: Projectile, orientation: Vector3, distance: Float): Unit = {
//explosion //explosion
val obj = DummyExplodingEntity(proxy) val obj = new DummyExplodingEntity(proxy, proxy.owner.Faction)
obj.Position = obj.Position + orientation * distance obj.Position = obj.Position + orientation * distance
context.system.scheduler.scheduleOnce(500.milliseconds) { val explosionFunc: ()=>Unit = WeaponAndProjectileOperations.detonateLittleBuddy(continent, obj, proxy, proxy.owner)
val c = continent context.system.scheduler.scheduleOnce(500.milliseconds) { explosionFunc() }
val o = obj
Zone.serverSideDamage(c, o, Zone.explosionDamage(None, o.Position))
}
} }
/** /**
@ -1246,3 +1243,50 @@ private[support] class WeaponAndProjectileOperations(
} }
} }
} }
object WeaponAndProjectileOperations {
/**
* Preparation for explosion damage that utilizes the Scorpion's little buddy sub-projectiles.
* The main difference from "normal" server-side explosion
* is that the owner of the projectile must be clarified explicitly.
* @see `Zone::serverSideDamage`
* @param zone where the explosion is taking place
* (`source` contains the coordinate location)
* @param source a game object that represents the source of the explosion
* @param owner who or what to accredit damage from the explosion to;
* clarifies a normal `SourceEntry(source)` accreditation
*/
private def detonateLittleBuddy(
zone: Zone,
source: PlanetSideGameObject with FactionAffinity with Vitality,
proxy: Projectile,
owner: SourceEntry
)(): Unit = {
Zone.serverSideDamage(zone, source, littleBuddyExplosionDamage(owner, proxy.id, source.Position))
}
/**
* Preparation for explosion damage that utilizes the Scorpion's little buddy sub-projectiles.
* The main difference from "normal" server-side explosion
* is that the owner of the projectile must be clarified explicitly.
* The sub-projectiles will be the product of a normal projectile rather than a standard game object
* so a custom `source` entity must wrap around it and fulfill the requirements of the field.
* @see `Zone::explosionDamage`
* @param owner who or what to accredit damage from the explosion to
* @param explosionPosition where the explosion will be positioned in the game world
* @param source a game object that represents the source of the explosion
* @param target a game object that is affected by the explosion
* @return a `DamageInteraction` object
*/
private def littleBuddyExplosionDamage(
owner: SourceEntry,
projectileId: Long,
explosionPosition: Vector3
)
(
source: PlanetSideGameObject with FactionAffinity with Vitality,
target: PlanetSideGameObject with FactionAffinity with Vitality
): DamageInteraction = {
DamageInteraction(SourceEntry(target), OicwLilBuddyReason(owner, projectileId, target.DamageModel), explosionPosition)
}
}

View file

@ -180,13 +180,14 @@ class ZoningOperations(
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 112, 0)) // disable festive backpacks sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 112, 0)) // disable festive backpacks
//find and reclaim own deployables, if any //find and reclaim own deployables, if any
val foundDeployables = val foundDeployables = continent.DeployableList.filter {
continent.DeployableList.filter(obj => obj.OwnerName.contains(player.Name) && obj.Health > 0) case _: BoomerDeployable => false //if we do find boomers for any reason, ignore them
foundDeployables.foreach(obj => { case dobj => dobj.OwnerName.contains(player.Name) && dobj.Health > 0
if (avatar.deployables.AddOverLimit(obj)) { }
foundDeployables.collect {
case obj if avatar.deployables.AddOverLimit(obj) =>
obj.Actor ! Deployable.Ownership(player) obj.Actor ! Deployable.Ownership(player)
} }
})
//render deployable objects //render deployable objects
val (turrets, normal) = continent.DeployableList.partition(obj => val (turrets, normal) = continent.DeployableList.partition(obj =>
DeployableToolbox.UnifiedType(obj.Definition.Item) == DeployedItem.portable_manned_turret DeployableToolbox.UnifiedType(obj.Definition.Item) == DeployedItem.portable_manned_turret

View file

@ -1,11 +1,12 @@
// Copyright (c) 2022 PSForever // Copyright (c) 2022 PSForever
package net.psforever.objects package net.psforever.objects
import net.psforever.objects.ballistics.Projectile
import net.psforever.objects.definition.{ObjectDefinition, ProjectileDefinition} import net.psforever.objects.definition.{ObjectDefinition, ProjectileDefinition}
import net.psforever.objects.serverobject.affinity.FactionAffinity import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.objects.vital.resolution.{DamageAndResistance, DamageResistanceModel} import net.psforever.objects.vital.resolution.{DamageAndResistance, DamageResistanceModel}
import net.psforever.objects.vital.{Vitality, VitalityDefinition} import net.psforever.objects.vital.{Vitality, VitalityDefinition}
import net.psforever.types.{PlanetSideEmpire, Vector3} import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, Vector3}
class DummyExplodingEntity( class DummyExplodingEntity(
private val obj: PlanetSideGameObject, private val obj: PlanetSideGameObject,
@ -14,7 +15,7 @@ class DummyExplodingEntity(
extends PlanetSideGameObject extends PlanetSideGameObject
with FactionAffinity with FactionAffinity
with Vitality { with Vitality {
override def GUID = obj.GUID override def GUID: PlanetSideGUID = obj.GUID
override def Position: Vector3 = { override def Position: Vector3 = {
if (super.Position == Vector3.Zero) { if (super.Position == Vector3.Zero) {
@ -41,20 +42,29 @@ class DummyExplodingEntity(
def DamageModel: DamageAndResistance = DummyExplodingEntity.DefaultDamageResistanceModel def DamageModel: DamageAndResistance = DummyExplodingEntity.DefaultDamageResistanceModel
def Definition: ObjectDefinition with VitalityDefinition = { def Definition: ObjectDefinition with VitalityDefinition = {
new DefinitionWrappedInVitality(obj.Definition) new DefinitionWrappedInVitality(obj)
} }
} }
private class DefinitionWrappedInVitality(definition: ObjectDefinition) private class DefinitionWrappedInVitality(private val entity: PlanetSideGameObject)
extends ObjectDefinition(definition.ObjectId) extends ObjectDefinition(entity.Definition.ObjectId)
with VitalityDefinition { with VitalityDefinition {
innateDamage = definition match { private val internalDefinition = entity.Definition
innateDamage = internalDefinition match {
case v: VitalityDefinition if v.innateDamage.nonEmpty => v.innateDamage.get case v: VitalityDefinition if v.innateDamage.nonEmpty => v.innateDamage.get
case p: ProjectileDefinition => p case p: ProjectileDefinition => p
case _ => GlobalDefinitions.no_projectile case _ => GlobalDefinitions.no_projectile
} }
Name = { definition.Name }
Name = internalDefinition.Name
DefaultHealth = 1 //just cuz DefaultHealth = 1 //just cuz
override def ObjectId: Int = entity match {
case p: Projectile => p.tool_def.ObjectId //projectiles point back to the weapon of origin
case _ => internalDefinition.ObjectId //what are we?
}
} }
object DummyExplodingEntity { object DummyExplodingEntity {

View file

@ -0,0 +1,26 @@
package net.psforever.objects.vital.etc
import net.psforever.objects.GlobalDefinitions
import net.psforever.objects.sourcing.SourceEntry
import net.psforever.objects.vital.base.{DamageReason, DamageResolution}
import net.psforever.objects.vital.prop.DamageProperties
import net.psforever.objects.vital.resolution.DamageAndResistance
case class OicwLilBuddyReason(
entity: SourceEntry,
projectileId: Long,
damageModel: DamageAndResistance
) extends DamageReason {
def resolution: DamageResolution.Value = DamageResolution.Explosion
def same(test: DamageReason): Boolean = test match {
case eer: OicwLilBuddyReason => eer.projectileId == projectileId
case _ => false
}
def adversary: Option[SourceEntry] = Some(entity)
def source: DamageProperties = GlobalDefinitions.oicw_little_buddy
override def attribution: Int = GlobalDefinitions.oicw.ObjectId
}