From f557ecc13d2205dfb038cad23fd1d2cf0d3efa01 Mon Sep 17 00:00:00 2001 From: "Jason_DiDonato@yahoo.com" Date: Tue, 12 Jan 2021 23:01:08 -0500 Subject: [PATCH] using the boomer trigger now causes boomers to explode and harm targets --- .../resources/overrides/game_objects0.adb.lst | 4 +- .../actors/session/SessionActor.scala | 35 ++++++---- .../objects/ExplosiveDeployable.scala | 64 ++++++++++++++++--- .../objects/vital/etc/TriggerUsedReason.scala | 61 ++++++++++++++++++ 4 files changed, 138 insertions(+), 26 deletions(-) create mode 100644 src/main/scala/net/psforever/objects/vital/etc/TriggerUsedReason.scala diff --git a/server/src/main/resources/overrides/game_objects0.adb.lst b/server/src/main/resources/overrides/game_objects0.adb.lst index 2b6529ea..a44d9237 100644 --- a/server/src/main/resources/overrides/game_objects0.adb.lst +++ b/server/src/main/resources/overrides/game_objects0.adb.lst @@ -1,7 +1,7 @@ -add_property ace allowed false +add_property ace allowed true add_property ace equiptime 500 add_property ace holstertime 500 -add_property ace_deployable allowed false +add_property ace_deployable allowed true add_property ace_deployable equiptime 500 add_property ace_deployable holstertime 500 add_property advanced_ace equiptime 750 diff --git a/src/main/scala/net/psforever/actors/session/SessionActor.scala b/src/main/scala/net/psforever/actors/session/SessionActor.scala index f29757b0..d0b120fb 100644 --- a/src/main/scala/net/psforever/actors/session/SessionActor.scala +++ b/src/main/scala/net/psforever/actors/session/SessionActor.scala @@ -2184,6 +2184,17 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con if (player.HasGUID) player.GUID else PlanetSideGUID(0) reply match { + case LocalResponse.AlertDestroyDeployable(obj: BoomerDeployable) => + //the (former) owner (obj.OwnerName) should process this message + obj.Trigger match { + case Some(item: BoomerTrigger) => + FindEquipmentToDelete(item.GUID, item) + item.Companion = None + case _ => ; + } + avatar.deployables.Remove(obj) + UpdateDeployableUIElements(avatar.deployables.UpdateUIElement(obj.Definition.Item)) + case LocalResponse.AlertDestroyDeployable(obj) => //the (former) owner (obj.OwnerName) should process this message avatar.deployables.Remove(obj) @@ -2194,17 +2205,17 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con sendResponse(DeployableObjectsInfoMessage(behavior, deployInfo)) } - case LocalResponse.Detonate(guid, obj: BoomerDeployable) => - sendResponse(TriggerEffectMessage(guid, "detonate_boomer")) - sendResponse(PlanetsideAttributeMessage(guid, 29, 1)) - sendResponse(ObjectDeleteMessage(guid, 0)) + case LocalResponse.Detonate(dguid, obj: BoomerDeployable) => + sendResponse(TriggerEffectMessage(dguid, "detonate_boomer")) + sendResponse(PlanetsideAttributeMessage(dguid, 29, 1)) + sendResponse(ObjectDeleteMessage(dguid, 0)) - case LocalResponse.Detonate(guid, obj: ExplosiveDeployable) => - sendResponse(GenericObjectActionMessage(guid, 19)) - sendResponse(PlanetsideAttributeMessage(guid, 29, 1)) - sendResponse(ObjectDeleteMessage(guid, 0)) + case LocalResponse.Detonate(dguid, obj: ExplosiveDeployable) => + sendResponse(GenericObjectActionMessage(dguid, 19)) + sendResponse(PlanetsideAttributeMessage(dguid, 29, 1)) + sendResponse(ObjectDeleteMessage(dguid, 0)) - case LocalResponse.Detonate(guid, obj) => + case LocalResponse.Detonate(_, obj) => log.warn(s"LocalResponse.Detonate: ${obj.Definition.Name} not configured to explode correctly") case LocalResponse.DoorOpens(door_guid) => @@ -4039,13 +4050,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con ) continent.GUID(trigger.Companion) match { case Some(boomer: BoomerDeployable) => - boomer.Destroyed = true - continent.LocalEvents ! LocalServiceMessage(continent.id, LocalAction.Detonate(boomer.GUID, boomer)) - Deployables.AnnounceDestroyDeployable(boomer, Some(500 milliseconds)) + boomer.Actor ! CommonMessages.Use(player, Some(trigger)) case Some(_) | None => ; } - FindEquipmentToDelete(item_guid, trigger) - trigger.Companion = None case _ => ; } progressBarUpdate.cancel() diff --git a/src/main/scala/net/psforever/objects/ExplosiveDeployable.scala b/src/main/scala/net/psforever/objects/ExplosiveDeployable.scala index 8b749a60..591d004f 100644 --- a/src/main/scala/net/psforever/objects/ExplosiveDeployable.scala +++ b/src/main/scala/net/psforever/objects/ExplosiveDeployable.scala @@ -2,16 +2,18 @@ package net.psforever.objects import akka.actor.{Actor, ActorContext, Props} +import net.psforever.objects.ballistics.{PlayerSource, SourceEntry} import net.psforever.objects.ce._ import net.psforever.objects.definition.{ComplexDeployableDefinition, SimpleDeployableDefinition} import net.psforever.objects.definition.converter.SmallDeployableConverter import net.psforever.objects.equipment.JammableUnit -import net.psforever.objects.serverobject.PlanetSideServerObject +import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject} import net.psforever.objects.serverobject.damage.{Damageable, DamageableEntity} import net.psforever.objects.serverobject.damage.Damageable.Target import net.psforever.objects.vital.resolution.ResolutionCalculations.Output import net.psforever.objects.vital.SimpleResolutions -import net.psforever.objects.vital.interaction.DamageResult +import net.psforever.objects.vital.etc.TriggerUsedReason +import net.psforever.objects.vital.interaction.{DamageInteraction, DamageResult} import net.psforever.objects.vital.projectile.ProjectileReason import net.psforever.objects.zones.Zone import net.psforever.types.Vector3 @@ -21,7 +23,9 @@ import net.psforever.services.local.{LocalAction, LocalServiceMessage} import scala.concurrent.duration._ -class ExplosiveDeployable(cdef: ExplosiveDeployableDefinition) extends ComplexDeployable(cdef) with JammableUnit { +class ExplosiveDeployable(cdef: ExplosiveDeployableDefinition) + extends ComplexDeployable(cdef) + with JammableUnit { override def Definition: ExplosiveDeployableDefinition = cdef } @@ -63,6 +67,24 @@ class ExplosiveDeployableControl(mine: ExplosiveDeployable) extends Actor with D def receive: Receive = takesDamage .orElse { + case CommonMessages.Use(player, Some(trigger: BoomerTrigger)) if { + mine match { + case boomer: BoomerDeployable => boomer.Trigger.contains(trigger) && mine.Definition.Damageable + case _ => false + } + } => + // the mine damages itself, which sets it off, which causes an explosion + // think of this as an initiator to the proper explosion + mine.Destroyed = true + ExplosiveDeployableControl.DamageResolution( + mine, + DamageInteraction( + SourceEntry(mine), + TriggerUsedReason(PlayerSource(player), trigger), + mine.Position + ).calculate()(mine), + damage = 0 + ) case _ => ; } @@ -84,9 +106,18 @@ class ExplosiveDeployableControl(mine: ExplosiveDeployable) extends Actor with D } object ExplosiveDeployableControl { + /** + * na + * @param target na + * @param cause na + * @param damage na + */ def DamageResolution(target: ExplosiveDeployable, cause: DamageResult, damage: Int): Unit = { target.History(cause) - if (target.Health == 0) { + 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 ( { @@ -99,17 +130,27 @@ object ExplosiveDeployableControl { } } ) { - if (cause.interaction.cause.source.SympatheticExplosion || target.Definition.DetonateOnJamming) { - val zone = target.Zone - zone.Activity ! Zone.HotSpot.Activity(cause) - zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.Detonate(target.GUID, target)) - Zone.causeExplosion(zone, target, Some(cause)) + if (target.Definition.DetonateOnJamming) { + explodes(target, cause) } DestructionAwareness(target, cause) } } } + /** + * na + * @param target na + * @param cause na + */ + def explodes(target: Damageable.Target, cause: DamageResult): Unit = { + target.Health = 1 // short-circuit logic in DestructionAwareness + val zone = target.Zone + zone.Activity ! Zone.HotSpot.Activity(cause) + zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.Detonate(target.GUID, target)) + Zone.causeExplosion(zone, target, Some(cause)) + } + /** * na * @param target na @@ -118,8 +159,11 @@ object ExplosiveDeployableControl { def DestructionAwareness(target: ExplosiveDeployable, cause: DamageResult): Unit = { val zone = target.Zone val attribution = DamageableEntity.attributionTo(cause, target.Zone) + Deployables.AnnounceDestroyDeployable( + target, + Some(if (target.Jammed || target.Destroyed) 0 seconds else 500 milliseconds) + ) target.Destroyed = true - Deployables.AnnounceDestroyDeployable(target, Some(if (target.Jammed) 0 seconds else 500 milliseconds)) zone.AvatarEvents ! AvatarServiceMessage( zone.id, AvatarAction.Destroy(target.GUID, attribution, Service.defaultPlayerGUID, target.Position) diff --git a/src/main/scala/net/psforever/objects/vital/etc/TriggerUsedReason.scala b/src/main/scala/net/psforever/objects/vital/etc/TriggerUsedReason.scala new file mode 100644 index 00000000..57561336 --- /dev/null +++ b/src/main/scala/net/psforever/objects/vital/etc/TriggerUsedReason.scala @@ -0,0 +1,61 @@ +// Copyright (c) 2020 PSForever +package net.psforever.objects.vital.etc + +import net.psforever.objects.BoomerTrigger +import net.psforever.objects.ballistics.{PlayerSource, SourceEntry} +import net.psforever.objects.vital.{NoResistanceSelection, SimpleResolutions} +import net.psforever.objects.vital.base.{DamageReason, DamageResolution} +import net.psforever.objects.vital.damage.DamageCalculations.AgainstExoSuit +import net.psforever.objects.vital.prop.DamageProperties +import net.psforever.objects.vital.resolution.{DamageAndResistance, DamageResistanceModel} + +/** + * A wrapper for a "damage source" in damage calculations + * that parameterizes information necessary to explain a `BoomerDeployable` being detonated + * using its complementary trigger. + * Should be applied as the reason applied to the Boomer + * in `DamageInteractions` that lead up to the Boomer exploding + * which will carry the trigger as the reason and the user as the culprit. + * Due to faction affiliation complicity between the user and the Boomer, however, + * normal `Damageable` functionality would have to interject in a way where the trigger works anyway. + * @see `BoomerDeployable` + * @see `BoomerTrigger` + * @see `DamageCalculations` + * @see `VitalityDefinition.DamageableByFriendlyFire` + * @param user the player who is holding the trigger + * @param item the trigger + */ +final case class TriggerUsedReason(user: PlayerSource, item: BoomerTrigger) + extends DamageReason { + def source: DamageProperties = TriggerUsedReason.triggered + + def resolution: DamageResolution.Value = DamageResolution.Resolved + + def same(test: DamageReason): Boolean = test match { + case tur: TriggerUsedReason => tur.item eq item + case _ => false + } + + /** lay the blame on the player who caused this explosion to occur */ + def adversary: Option[SourceEntry] = Some(user) + + override def damageModel : DamageAndResistance = TriggerUsedReason.drm + + /** while weird, the trigger was accredited as the method of death on Gemini Live; + * even though its icon looks like an misshapen AMS */ + override def attribution: Int = item.Definition.ObjectId +} + +object TriggerUsedReason { + private val triggered = new DamageProperties { + Damage0 = 1 //token damage + SympatheticExplosion = true //sets off a boomer + } + + /** basic damage, no resisting, quick and simple */ + private val drm = new DamageResistanceModel { + DamageUsing = AgainstExoSuit + ResistUsing = NoResistanceSelection + Model = SimpleResolutions.calculate + } +} \ No newline at end of file