mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-07-16 08:55:18 +00:00
redid combat engineering explosive logic
This commit is contained in:
parent
fa9ba7e7da
commit
38f25f5bcc
7 changed files with 202 additions and 166 deletions
|
|
@ -5,7 +5,6 @@ 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.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.Vitality
|
||||||
|
|
@ -39,7 +38,8 @@ class BoomerDeployable(cdef: ExplosiveDeployableDefinition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BoomerDeployableDefinition(private val objectId: Int) extends ExplosiveDeployableDefinition(objectId) {
|
class BoomerDeployableDefinition(private val objectId: Int)
|
||||||
|
extends ExplosiveDeployableDefinition(objectId) {
|
||||||
override def Initialize(obj: Deployable, context: ActorContext): Unit = {
|
override def Initialize(obj: Deployable, context: ActorContext): Unit = {
|
||||||
obj.Actor =
|
obj.Actor =
|
||||||
context.actorOf(Props(classOf[BoomerDeployableControl], obj), PlanetSideServerObject.UniqueActorName(obj))
|
context.actorOf(Props(classOf[BoomerDeployableControl], obj), PlanetSideServerObject.UniqueActorName(obj))
|
||||||
|
|
@ -119,6 +119,6 @@ class BoomerDeployableControl(mine: BoomerDeployable)
|
||||||
* `false`, otherwise
|
* `false`, otherwise
|
||||||
*/
|
*/
|
||||||
override def CanDetonate(obj: Vitality with FactionAffinity, damage: Int, data: DamageInteraction): Boolean = {
|
override def CanDetonate(obj: Vitality with FactionAffinity, damage: Int, data: DamageInteraction): Boolean = {
|
||||||
!mine.Destroyed && (data.cause.isInstanceOf[TriggerUsedReason] || Damageable.CanJammer(obj, data))
|
super.CanDetonate(obj, damage, data) || data.cause.isInstanceOf[TriggerUsedReason]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright (c) 2018 PSForever
|
// Copyright (c) 2018 PSForever
|
||||||
package net.psforever.objects
|
package net.psforever.objects
|
||||||
|
|
||||||
import akka.actor.{Actor, ActorContext, ActorRef, Props}
|
import akka.actor.Actor
|
||||||
import net.psforever.objects.ce._
|
import net.psforever.objects.ce._
|
||||||
import net.psforever.objects.definition.DeployableDefinition
|
import net.psforever.objects.definition.DeployableDefinition
|
||||||
import net.psforever.objects.definition.converter.SmallDeployableConverter
|
import net.psforever.objects.definition.converter.SmallDeployableConverter
|
||||||
|
|
@ -11,8 +11,6 @@ import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
import net.psforever.objects.serverobject.damage.{Damageable, DamageableEntity}
|
import net.psforever.objects.serverobject.damage.{Damageable, DamageableEntity}
|
||||||
import net.psforever.objects.serverobject.damage.Damageable.Target
|
import net.psforever.objects.serverobject.damage.Damageable.Target
|
||||||
import net.psforever.objects.sourcing.{DeployableSource, PlayerSource, SourceEntry}
|
|
||||||
import net.psforever.objects.vital.etc.TrippedMineReason
|
|
||||||
import net.psforever.objects.vital.resolution.ResolutionCalculations.Output
|
import net.psforever.objects.vital.resolution.ResolutionCalculations.Output
|
||||||
import net.psforever.objects.vital.{SimpleResolutions, Vitality}
|
import net.psforever.objects.vital.{SimpleResolutions, Vitality}
|
||||||
import net.psforever.objects.vital.interaction.{DamageInteraction, DamageResult}
|
import net.psforever.objects.vital.interaction.{DamageInteraction, DamageResult}
|
||||||
|
|
@ -23,6 +21,7 @@ import net.psforever.services.Service
|
||||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||||
|
|
||||||
|
import scala.annotation.unused
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
class ExplosiveDeployable(cdef: ExplosiveDeployableDefinition)
|
class ExplosiveDeployable(cdef: ExplosiveDeployableDefinition)
|
||||||
|
|
@ -36,7 +35,7 @@ object ExplosiveDeployable {
|
||||||
final case class TriggeredBy(obj: PlanetSideServerObject)
|
final case class TriggeredBy(obj: PlanetSideServerObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExplosiveDeployableDefinition(private val objectId: Int)
|
abstract class ExplosiveDeployableDefinition(private val objectId: Int)
|
||||||
extends DeployableDefinition(objectId) {
|
extends DeployableDefinition(objectId) {
|
||||||
Name = "explosive_deployable"
|
Name = "explosive_deployable"
|
||||||
DeployCategory = DeployableCategory.Mines
|
DeployCategory = DeployableCategory.Mines
|
||||||
|
|
@ -45,6 +44,8 @@ class ExplosiveDeployableDefinition(private val objectId: Int)
|
||||||
|
|
||||||
private var detonateOnJamming: Boolean = true
|
private var detonateOnJamming: Boolean = true
|
||||||
|
|
||||||
|
private var stability: Boolean = false
|
||||||
|
|
||||||
var triggerRadius: Float = 0f
|
var triggerRadius: Float = 0f
|
||||||
|
|
||||||
def DetonateOnJamming: Boolean = detonateOnJamming
|
def DetonateOnJamming: Boolean = detonateOnJamming
|
||||||
|
|
@ -54,15 +55,11 @@ class ExplosiveDeployableDefinition(private val objectId: Int)
|
||||||
DetonateOnJamming
|
DetonateOnJamming
|
||||||
}
|
}
|
||||||
|
|
||||||
override def Initialize(obj: Deployable, context: ActorContext): Unit = {
|
def Stable: Boolean = stability
|
||||||
obj.Actor =
|
|
||||||
context.actorOf(Props(classOf[MineDeployableControl], obj), PlanetSideServerObject.UniqueActorName(obj))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object ExplosiveDeployableDefinition {
|
def Stable_=(stableState: Boolean): Boolean = {
|
||||||
def apply(dtype: DeployedItem.Value): ExplosiveDeployableDefinition = {
|
stability = stableState
|
||||||
new ExplosiveDeployableDefinition(dtype.id)
|
Stable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,19 +95,10 @@ abstract class ExplosiveDeployableControl(mine: ExplosiveDeployable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 = {
|
final def HandleDamage(target: ExplosiveDeployable, cause: DamageResult, damage: Int): Unit = {
|
||||||
target.LogActivity(cause)
|
target.LogActivity(cause)
|
||||||
if (CanDetonate(target, damage, cause.interaction)) {
|
if (CanDetonate(target, damage, cause.interaction)) {
|
||||||
ExplosiveDeployableControl.explodes(target, cause)
|
ExplosiveDeployableControl.doExplosion(target, cause)
|
||||||
ExplosiveDeployableControl.DestructionAwareness(target, cause)
|
|
||||||
} else if (target.Health == 0) {
|
} else if (target.Health == 0) {
|
||||||
ExplosiveDeployableControl.DestructionAwareness(target, cause)
|
ExplosiveDeployableControl.DestructionAwareness(target, cause)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -118,6 +106,17 @@ abstract class ExplosiveDeployableControl(mine: ExplosiveDeployable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def Interaction(obj: Vitality with FactionAffinity, damage: Int, data: DamageInteraction): Boolean = {
|
||||||
|
val actualDamage: Int = if (!mine.Definition.Stable && data.cause.source.SympatheticExplosion) {
|
||||||
|
math.max(damage, 1)
|
||||||
|
} else {
|
||||||
|
damage
|
||||||
|
}
|
||||||
|
!mine.Destroyed &&
|
||||||
|
Damageable.adversarialOrHackableChecks(obj, data) &&
|
||||||
|
(CanDetonate(obj, actualDamage, data) || Damageable.CanDamage(obj, actualDamage, data))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
|
|
@ -130,21 +129,22 @@ abstract class ExplosiveDeployableControl(mine: ExplosiveDeployable)
|
||||||
* @return `true`, if the target can be affected;
|
* @return `true`, if the target can be affected;
|
||||||
* `false`, otherwise
|
* `false`, otherwise
|
||||||
*/
|
*/
|
||||||
def CanDetonate(obj: Vitality with FactionAffinity, damage: Int, data: DamageInteraction): Boolean = {
|
def CanDetonate(obj: Vitality with FactionAffinity, @unused damage: Int, data: DamageInteraction): Boolean = {
|
||||||
!mine.Destroyed && (if (damage == 0 && data.cause.source.SympatheticExplosion) {
|
val sourceDef = data.cause.source
|
||||||
Damageable.CanDamageOrJammer(mine, damage = 1, data)
|
val mineDef = mine.Definition
|
||||||
} else {
|
val explodeFromSympathy: Boolean = sourceDef.SympatheticExplosion && !mineDef.Stable
|
||||||
Damageable.CanDamageOrJammer(mine, damage, data)
|
val explodeFromJammer: Boolean = ExplosiveDeployableControl.CanJammer(mine, data)
|
||||||
})
|
!mine.Destroyed && (explodeFromSympathy || explodeFromJammer)
|
||||||
}
|
|
||||||
|
|
||||||
def explode(target: ExplosiveDeployable, cause: DamageResult): Unit = {
|
|
||||||
ExplosiveDeployableControl.explodes(target, cause)
|
|
||||||
ExplosiveDeployableControl.DestructionAwareness(target, cause)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object ExplosiveDeployableControl {
|
object ExplosiveDeployableControl {
|
||||||
|
def CanJammer(mine: ExplosiveDeployable, data: DamageInteraction): Boolean = {
|
||||||
|
Damageable.adversarialOrHackableChecks(mine, data) &&
|
||||||
|
data.cause.source.AdditionalEffect &&
|
||||||
|
mine.Definition.DetonateOnJamming
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* na
|
* na
|
||||||
* @param target na
|
* @param target na
|
||||||
|
|
@ -152,22 +152,23 @@ object ExplosiveDeployableControl {
|
||||||
* @param damage na
|
* @param damage na
|
||||||
*/
|
*/
|
||||||
def DamageAwareness(target: ExplosiveDeployable, cause: DamageResult, damage: Int): Unit = {
|
def DamageAwareness(target: ExplosiveDeployable, cause: DamageResult, damage: Int): Unit = {
|
||||||
if (!target.Jammed && Damageable.CanJammer(target, cause.interaction)) {
|
if (
|
||||||
if ( {
|
!target.Jammed &&
|
||||||
target.Jammed = cause.interaction.cause match {
|
CanJammer(target, cause.interaction) &&
|
||||||
case o: ProjectileReason =>
|
{
|
||||||
val radius = o.projectile.profile.DamageRadius
|
target.Jammed = cause.interaction.cause match {
|
||||||
Vector3.DistanceSquared(cause.interaction.hitPos, cause.interaction.target.Position) < radius * radius
|
case o: ProjectileReason =>
|
||||||
case _ =>
|
val radius = o.projectile.profile.DamageRadius
|
||||||
true
|
Vector3.DistanceSquared(cause.interaction.hitPos, cause.interaction.target.Position) < radius * radius
|
||||||
|
case _ =>
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
) {
|
||||||
|
if (target.Definition.DetonateOnJamming) {
|
||||||
|
explodes(target, cause)
|
||||||
}
|
}
|
||||||
) {
|
DestructionAwareness(target, cause)
|
||||||
if (target.Definition.DetonateOnJamming) {
|
|
||||||
explodes(target, cause)
|
|
||||||
}
|
|
||||||
DestructionAwareness(target, cause)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -190,6 +191,11 @@ object ExplosiveDeployableControl {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def doExplosion(target: ExplosiveDeployable, cause: DamageResult): Unit = {
|
||||||
|
explodes(target, cause)
|
||||||
|
DestructionAwareness(target, cause)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* na
|
* na
|
||||||
* @param target na
|
* @param target na
|
||||||
|
|
@ -272,112 +278,3 @@ object ExplosiveDeployableControl {
|
||||||
) <= maxDistance
|
) <= maxDistance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MineDeployableControl(mine: ExplosiveDeployable)
|
|
||||||
extends ExplosiveDeployableControl(mine) {
|
|
||||||
|
|
||||||
def receive: Receive =
|
|
||||||
commonMineBehavior
|
|
||||||
.orElse {
|
|
||||||
case ExplosiveDeployable.TriggeredBy(obj) =>
|
|
||||||
setTriggered(Some(obj), delay = 200)
|
|
||||||
|
|
||||||
case MineDeployableControl.Triggered() =>
|
|
||||||
explodes(testForTriggeringTarget(
|
|
||||||
mine,
|
|
||||||
mine.Definition.innateDamage.map { _.DamageRadius }.getOrElse(mine.Definition.triggerRadius)
|
|
||||||
))
|
|
||||||
|
|
||||||
case _ => ()
|
|
||||||
}
|
|
||||||
|
|
||||||
override def finalizeDeployable(callback: ActorRef): Unit = {
|
|
||||||
super.finalizeDeployable(callback)
|
|
||||||
//initial triggering upon build
|
|
||||||
setTriggered(testForTriggeringTarget(mine, mine.Definition.triggerRadius), delay = 1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
def testForTriggeringTarget(mine: ExplosiveDeployable, range: Float): Option[PlanetSideServerObject] = {
|
|
||||||
val position = mine.Position
|
|
||||||
val faction = mine.Faction
|
|
||||||
val range2 = range * range
|
|
||||||
val sector = mine.Zone.blockMap.sector(position, range)
|
|
||||||
(sector.livePlayerList ++ sector.vehicleList)
|
|
||||||
.find { thing => thing.Faction != faction && Vector3.DistanceSquared(thing.Position, position) < range2 }
|
|
||||||
}
|
|
||||||
|
|
||||||
def setTriggered(instigator: Option[PlanetSideServerObject], delay: Long): Unit = {
|
|
||||||
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
|
|
||||||
.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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object MineDeployableControl {
|
|
||||||
private case class Triggered()
|
|
||||||
|
|
||||||
def trippedMineReason(mine: ExplosiveDeployable): TrippedMineReason = {
|
|
||||||
lazy val deployableSource = DeployableSource(mine)
|
|
||||||
val zone = mine.Zone
|
|
||||||
val ownerName = mine.OwnerName
|
|
||||||
val blame = zone
|
|
||||||
.Players
|
|
||||||
.find(a => ownerName.contains(a.name))
|
|
||||||
.collect { a =>
|
|
||||||
val name = a.name
|
|
||||||
assignBlameToFrom(name, zone.LivePlayers)
|
|
||||||
.orElse(assignBlameToFrom(name, zone.Corpses))
|
|
||||||
.getOrElse {
|
|
||||||
val player = PlayerSource(name, mine.Faction, mine.Position) //might report minor inconsistencies, e.g., exo-suit type
|
|
||||||
player.copy(unique = player.unique.copy(charId = a.id), progress = a.scorecard.CurrentLife)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.getOrElse(deployableSource)
|
|
||||||
TrippedMineReason(deployableSource, blame)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find a player with a given name from this list of possible players.
|
|
||||||
* If the player is seated, attach a shallow copy of the mounting information.
|
|
||||||
* @param name player name
|
|
||||||
* @param blameList possible players in which to find the player name
|
|
||||||
* @return discovered player as a reference, or `None` if not found
|
|
||||||
*/
|
|
||||||
private def assignBlameToFrom(name: String, blameList: List[Player]): Option[SourceEntry] = {
|
|
||||||
blameList
|
|
||||||
.find(_.Name.equals(name))
|
|
||||||
.map { player =>
|
|
||||||
PlayerSource
|
|
||||||
.mountableAndSeat(player)
|
|
||||||
.map { case (mount, seat) => PlayerSource.inSeat(player, mount, seat) }
|
|
||||||
.getOrElse { PlayerSource(player) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1019,9 +1019,9 @@ object GlobalDefinitions {
|
||||||
*/
|
*/
|
||||||
val boomer: BoomerDeployableDefinition = BoomerDeployableDefinition(DeployedItem.boomer)
|
val boomer: BoomerDeployableDefinition = BoomerDeployableDefinition(DeployedItem.boomer)
|
||||||
|
|
||||||
val he_mine: ExplosiveDeployableDefinition = ExplosiveDeployableDefinition(DeployedItem.he_mine)
|
val he_mine: MineDeployableDefinition = MineDeployableDefinition(DeployedItem.he_mine)
|
||||||
|
|
||||||
val jammer_mine: ExplosiveDeployableDefinition = ExplosiveDeployableDefinition(DeployedItem.jammer_mine)
|
val jammer_mine: MineDeployableDefinition = MineDeployableDefinition(DeployedItem.jammer_mine)
|
||||||
|
|
||||||
val spitfire_turret: TurretDeployableDefinition = TurretDeployableDefinition(DeployedItem.spitfire_turret)
|
val spitfire_turret: TurretDeployableDefinition = TurretDeployableDefinition(DeployedItem.spitfire_turret)
|
||||||
|
|
||||||
|
|
|
||||||
137
src/main/scala/net/psforever/objects/MineDeployableControl.scala
Normal file
137
src/main/scala/net/psforever/objects/MineDeployableControl.scala
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
// Copyright (c) 2024 PSForever
|
||||||
|
package net.psforever.objects
|
||||||
|
|
||||||
|
import akka.actor.{ActorContext, ActorRef, Props}
|
||||||
|
import net.psforever.objects.ce.{Deployable, DeployedItem}
|
||||||
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
|
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||||
|
import net.psforever.objects.sourcing.{DeployableSource, PlayerSource, SourceEntry}
|
||||||
|
import net.psforever.objects.vital.Vitality
|
||||||
|
import net.psforever.objects.vital.etc.TrippedMineReason
|
||||||
|
import net.psforever.objects.vital.interaction.DamageInteraction
|
||||||
|
import net.psforever.types.Vector3
|
||||||
|
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
class MineDeployableDefinition(private val objectId: Int)
|
||||||
|
extends ExplosiveDeployableDefinition(objectId) {
|
||||||
|
override def Initialize(obj: Deployable, context: ActorContext): Unit = {
|
||||||
|
obj.Actor =
|
||||||
|
context.actorOf(Props(classOf[MineDeployableControl], obj), PlanetSideServerObject.UniqueActorName(obj))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object MineDeployableDefinition {
|
||||||
|
def apply(dtype: DeployedItem.Value): MineDeployableDefinition = {
|
||||||
|
new MineDeployableDefinition(dtype.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MineDeployableControl(mine: ExplosiveDeployable)
|
||||||
|
extends ExplosiveDeployableControl(mine) {
|
||||||
|
|
||||||
|
def receive: Receive =
|
||||||
|
commonMineBehavior
|
||||||
|
.orElse {
|
||||||
|
case ExplosiveDeployable.TriggeredBy(obj) =>
|
||||||
|
setTriggered(Some(obj), delay = 200)
|
||||||
|
|
||||||
|
case MineDeployableControl.Triggered() =>
|
||||||
|
explodes(testForTriggeringTarget(
|
||||||
|
mine,
|
||||||
|
mine.Definition.innateDamage.map { _.DamageRadius }.getOrElse(mine.Definition.triggerRadius)
|
||||||
|
))
|
||||||
|
|
||||||
|
case _ => ()
|
||||||
|
}
|
||||||
|
|
||||||
|
override def finalizeDeployable(callback: ActorRef): Unit = {
|
||||||
|
super.finalizeDeployable(callback)
|
||||||
|
//initial triggering upon build
|
||||||
|
setTriggered(testForTriggeringTarget(mine, mine.Definition.triggerRadius), delay = 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
def testForTriggeringTarget(mine: ExplosiveDeployable, range: Float): Option[PlanetSideServerObject] = {
|
||||||
|
val position = mine.Position
|
||||||
|
val faction = mine.Faction
|
||||||
|
val range2 = range * range
|
||||||
|
val sector = mine.Zone.blockMap.sector(position, range)
|
||||||
|
(sector.livePlayerList ++ sector.vehicleList)
|
||||||
|
.find { thing => thing.Faction != faction && Vector3.DistanceSquared(thing.Position, position) < range2 }
|
||||||
|
}
|
||||||
|
|
||||||
|
def setTriggered(instigator: Option[PlanetSideServerObject], delay: Long): Unit = {
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override def CanDetonate(obj: Vitality with FactionAffinity, damage: Int, data: DamageInteraction): Boolean = {
|
||||||
|
super.CanDetonate(obj, damage, data) || data.cause.isInstanceOf[TrippedMineReason]
|
||||||
|
}
|
||||||
|
|
||||||
|
def explodes(instigator: Option[PlanetSideServerObject]): Unit = {
|
||||||
|
//reset
|
||||||
|
setup = Default.Cancellable
|
||||||
|
instigator
|
||||||
|
.collect {
|
||||||
|
case _ =>
|
||||||
|
//explosion
|
||||||
|
HandleDamage(
|
||||||
|
mine,
|
||||||
|
DamageInteraction(
|
||||||
|
SourceEntry(mine),
|
||||||
|
MineDeployableControl.trippedMineReason(mine),
|
||||||
|
mine.Position
|
||||||
|
).calculate()(mine),
|
||||||
|
damage = 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object MineDeployableControl {
|
||||||
|
private case class Triggered()
|
||||||
|
|
||||||
|
def trippedMineReason(mine: ExplosiveDeployable): TrippedMineReason = {
|
||||||
|
lazy val deployableSource = DeployableSource(mine)
|
||||||
|
val zone = mine.Zone
|
||||||
|
val ownerName = mine.OwnerName
|
||||||
|
val blame = zone
|
||||||
|
.Players
|
||||||
|
.find(a => ownerName.contains(a.name))
|
||||||
|
.collect { a =>
|
||||||
|
val name = a.name
|
||||||
|
assignBlameToFrom(name, zone.LivePlayers)
|
||||||
|
.orElse(assignBlameToFrom(name, zone.Corpses))
|
||||||
|
.getOrElse {
|
||||||
|
val player = PlayerSource(name, mine.Faction, mine.Position) //might report minor inconsistencies, e.g., exo-suit type
|
||||||
|
player.copy(unique = player.unique.copy(charId = a.id), progress = a.scorecard.CurrentLife)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.getOrElse(deployableSource)
|
||||||
|
TrippedMineReason(deployableSource, blame)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a player with a given name from this list of possible players.
|
||||||
|
* If the player is seated, attach a shallow copy of the mounting information.
|
||||||
|
* @param name player name
|
||||||
|
* @param blameList possible players in which to find the player name
|
||||||
|
* @return discovered player as a reference, or `None` if not found
|
||||||
|
*/
|
||||||
|
private def assignBlameToFrom(name: String, blameList: List[Player]): Option[SourceEntry] = {
|
||||||
|
blameList
|
||||||
|
.find(_.Name.equals(name))
|
||||||
|
.map { player =>
|
||||||
|
PlayerSource
|
||||||
|
.mountableAndSeat(player)
|
||||||
|
.map { case (mount, seat) => PlayerSource.inSeat(player, mount, seat) }
|
||||||
|
.getOrElse { PlayerSource(player) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -42,6 +42,7 @@ object GlobalDefinitionsDeployable {
|
||||||
boomer.DeployTime = Duration.create(1000, "ms")
|
boomer.DeployTime = Duration.create(1000, "ms")
|
||||||
boomer.deployAnimation = DeployAnimation.Standard
|
boomer.deployAnimation = DeployAnimation.Standard
|
||||||
boomer.interference = InterferenceRange(main = 0.2f)
|
boomer.interference = InterferenceRange(main = 0.2f)
|
||||||
|
boomer.Stable = true
|
||||||
boomer.innateDamage = new DamageWithPosition {
|
boomer.innateDamage = new DamageWithPosition {
|
||||||
CausesDamageType = DamageType.Splash
|
CausesDamageType = DamageType.Splash
|
||||||
SympatheticExplosion = true
|
SympatheticExplosion = true
|
||||||
|
|
@ -58,7 +59,7 @@ object GlobalDefinitionsDeployable {
|
||||||
|
|
||||||
he_mine.Name = "he_mine"
|
he_mine.Name = "he_mine"
|
||||||
he_mine.Descriptor = "Mines"
|
he_mine.Descriptor = "Mines"
|
||||||
he_mine.MaxHealth = 50
|
he_mine.MaxHealth = 25
|
||||||
he_mine.Damageable = true
|
he_mine.Damageable = true
|
||||||
he_mine.DamageableByFriendlyFire = false
|
he_mine.DamageableByFriendlyFire = false
|
||||||
he_mine.Repairable = false
|
he_mine.Repairable = false
|
||||||
|
|
@ -91,12 +92,12 @@ object GlobalDefinitionsDeployable {
|
||||||
jammer_mine.interference = InterferenceRange(main = 7f, sharedGroupId = 1, shared = 7f, deployables = 0.1f)
|
jammer_mine.interference = InterferenceRange(main = 7f, sharedGroupId = 1, shared = 7f, deployables = 0.1f)
|
||||||
jammer_mine.DetonateOnJamming = false
|
jammer_mine.DetonateOnJamming = false
|
||||||
jammer_mine.triggerRadius = 3f
|
jammer_mine.triggerRadius = 3f
|
||||||
|
jammer_mine.Stable = true
|
||||||
jammer_mine.innateDamage = new DamageWithPosition {
|
jammer_mine.innateDamage = new DamageWithPosition {
|
||||||
CausesDamageType = DamageType.Splash
|
CausesDamageType = DamageType.Splash
|
||||||
Damage0 = 0
|
Damage0 = 0
|
||||||
DamageRadius = 10f
|
DamageRadius = 10f
|
||||||
DamageAtEdge = 1.0f
|
DamageAtEdge = 1.0f
|
||||||
AdditionalEffect = true
|
|
||||||
JammedEffectDuration += TargetValidation(
|
JammedEffectDuration += TargetValidation(
|
||||||
EffectTarget.Category.Player,
|
EffectTarget.Category.Player,
|
||||||
EffectTarget.Validation.Player
|
EffectTarget.Validation.Player
|
||||||
|
|
|
||||||
|
|
@ -94,12 +94,12 @@ object Damageable {
|
||||||
* `false`, otherwise
|
* `false`, otherwise
|
||||||
*/
|
*/
|
||||||
def CanJammer(obj: Vitality with FactionAffinity, data: DamageInteraction): Boolean = {
|
def CanJammer(obj: Vitality with FactionAffinity, data: DamageInteraction): Boolean = {
|
||||||
data.cause.source.HasJammedEffectDuration &&
|
(data.cause.source.HasJammedEffectDuration || data.cause.source.AdditionalEffect) &&
|
||||||
obj.isInstanceOf[JammableUnit] &&
|
obj.isInstanceOf[JammableUnit] &&
|
||||||
adversarialOrHackableChecks(obj, data)
|
adversarialOrHackableChecks(obj, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def adversarialOrHackableChecks(obj: Vitality with FactionAffinity, data: DamageInteraction): Boolean = {
|
def adversarialOrHackableChecks(obj: Vitality with FactionAffinity, data: DamageInteraction): Boolean = {
|
||||||
(data.adversarial match {
|
(data.adversarial match {
|
||||||
case Some(adversarial) => adversarial.attacker.Faction != adversarial.defender.Faction
|
case Some(adversarial) => adversarial.attacker.Faction != adversarial.defender.Faction
|
||||||
case None => true
|
case None => true
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,8 @@ trait DamageProperties
|
||||||
* also used to produce staged projectiles */
|
* also used to produce staged projectiles */
|
||||||
private var damageProxy: List[Int] = Nil
|
private var damageProxy: List[Int] = Nil
|
||||||
/** na;
|
/** na;
|
||||||
* currently used with jammer properties only */
|
* currently used with jammer properties only;
|
||||||
|
* used sepcifically to indicate jammering effect targets explosive deployables */
|
||||||
private var additionalEffect: Boolean = false
|
private var additionalEffect: Boolean = false
|
||||||
/** confers aggravated damage burn to its target */
|
/** confers aggravated damage burn to its target */
|
||||||
private var aggravatedDamage: Option[AggravatedDamage] = None
|
private var aggravatedDamage: Option[AggravatedDamage] = None
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue