mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-03-25 14:59:07 +00:00
timing and damage tuning around: standard, reinforced, max; plasma grenades, dragon
This commit is contained in:
parent
d149e07e89
commit
97e64d5edc
16 changed files with 500 additions and 136 deletions
|
|
@ -3,19 +3,24 @@ package net.psforever.objects.avatar
|
|||
|
||||
import akka.actor.{Actor, Cancellable}
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.objects.ballistics.{AggravatedDamage, AggravatedInfo, ResolvedProjectile}
|
||||
import net.psforever.objects.vital.DamageType
|
||||
import net.psforever.objects.ballistics._
|
||||
import net.psforever.objects.serverobject.damage.Damageable
|
||||
import net.psforever.objects.vital.{DamageType, Vitality}
|
||||
import net.psforever.types.Vector3
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
|
||||
trait AuraEffectBehavior {
|
||||
_ : Actor =>
|
||||
private var activeEffectIndex : Long = 0
|
||||
private var effectsToIds : mutable.HashMap[Aura.Value, List[Long]] = mutable.HashMap.empty[Aura.Value, List[Long]]
|
||||
private var idsToTimers : mutable.LongMap[Cancellable] = mutable.LongMap.empty[Cancellable]
|
||||
private var idsToEntries : mutable.LongMap[AuraEffectBehavior.Entry] = mutable.LongMap.empty[AuraEffectBehavior.Entry]
|
||||
_ : Actor with Damageable =>
|
||||
private var activeEffectIndex: Long = 0
|
||||
private val effectToEntryId: mutable.HashMap[Aura.Value, List[Long]] =
|
||||
mutable.HashMap.empty[Aura.Value, List[Long]]
|
||||
private val entryIdToTimer: mutable.LongMap[Cancellable] =
|
||||
mutable.LongMap.empty[Cancellable]
|
||||
private val entryIdToEntry: mutable.LongMap[AuraEffectBehavior.Entry] =
|
||||
mutable.LongMap.empty[AuraEffectBehavior.Entry]
|
||||
|
||||
def AuraTargetObject : Player
|
||||
|
||||
|
|
@ -25,114 +30,181 @@ trait AuraEffectBehavior {
|
|||
PerformCleanupEffect(id)
|
||||
|
||||
case AuraEffectBehavior.Aggravate(id, 0, leftoverTime) =>
|
||||
PerformAggravationAndRetimeEvent(id, iteration = 0, Some(leftoverTime), leftoverTime = 0)
|
||||
RemoveEffectEntry(id)
|
||||
RetimeEvent(id, iteration = 0, Some(leftoverTime), leftoverTime = 0)
|
||||
|
||||
case AuraEffectBehavior.Aggravate(id, iteration, leftover) => ;
|
||||
PerformAggravationAndRetimeEvent(id, iteration - 1, None, leftover)
|
||||
RetimeEventAndPerformAggravation(id, iteration - 1, None, leftover)
|
||||
}
|
||||
|
||||
def PerformAggravationAndRetimeEvent(id : Long, iteration : Int, time : Option[Long], leftoverTime : Long) : Unit = {
|
||||
private def RetimeEvent(
|
||||
id: Long,
|
||||
iteration: Int,
|
||||
time: Option[Long],
|
||||
leftoverTime: Long
|
||||
): Option[AuraEffectBehavior.Entry] = {
|
||||
CancelEffectTimer(id)
|
||||
idsToEntries.get(id) match {
|
||||
case Some(entry) =>
|
||||
//TODO stuff ...
|
||||
idsToTimers += id -> context.system.scheduler.scheduleOnce(
|
||||
time.getOrElse(entry.effect.infliction_rate) milliseconds,
|
||||
entryIdToEntry.get(id) match {
|
||||
case Some(oldEntry) =>
|
||||
val target = SourceEntry(AuraTargetObject)
|
||||
val entry = PairIdWithAggravationEntry(
|
||||
id,
|
||||
oldEntry.effect,
|
||||
oldEntry.retime,
|
||||
oldEntry.data,
|
||||
target,
|
||||
target.Position - oldEntry.data.target.Position
|
||||
)
|
||||
entryIdToTimer += id -> context.system.scheduler.scheduleOnce(
|
||||
time.getOrElse(entry.retime) milliseconds,
|
||||
self,
|
||||
AuraEffectBehavior.Aggravate(id, iteration, leftoverTime)
|
||||
)
|
||||
Some(entry)
|
||||
case _ =>
|
||||
PerformCleanupEffect(id)
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
def CancelEffectTimer(id : Long) : Unit = {
|
||||
idsToTimers.remove(id) match {
|
||||
private def RetimeEventAndPerformAggravation(id: Long, iteration: Int, time: Option[Long], leftoverTime: Long) : Unit = {
|
||||
RetimeEvent(id, iteration, time, leftoverTime) match {
|
||||
case Some(entry) =>
|
||||
PerformAggravation(entry)
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
||||
def CancelEffectTimer(id: Long) : Unit = {
|
||||
entryIdToTimer.remove(id) match {
|
||||
case Some(timer) => timer.cancel
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
||||
def PerformCleanupEffect(id : Long) : Unit = {
|
||||
def PerformCleanupEffect(id: Long) : Unit = {
|
||||
CleanupEffect(id) match {
|
||||
case Aura.None => ;
|
||||
case _ => UpdateAggravatedEffect(AuraTargetObject)
|
||||
}
|
||||
}
|
||||
|
||||
def TryAggravationEffect(data : ResolvedProjectile) : Unit = {
|
||||
def TryAggravationEffect(data: ResolvedProjectile) : Unit = {
|
||||
data.projectile.profile.Aggravated match {
|
||||
case Some(damage)
|
||||
if data.projectile.profile.ProjectileDamageType == DamageType.Aggravated && damage.effect_type != Aura.None =>
|
||||
if data.projectile.profile.ProjectileDamageTypes.contains(DamageType.Aggravated) &&
|
||||
damage.effect_type != Aura.None =>
|
||||
TryAggravationEffect(damage, data)
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
||||
private def TryAggravationEffect(aggravation : AggravatedDamage, data : ResolvedProjectile) : Unit = {
|
||||
private def TryAggravationEffect(aggravation: AggravatedDamage, data: ResolvedProjectile) : Unit = {
|
||||
val effect = aggravation.effect_type
|
||||
val obj = AuraTargetObject
|
||||
if(obj.Aura.contains(effect)) { //TODO cumulative?
|
||||
SetupAggravationEntry(aggravation)
|
||||
}
|
||||
else if(obj.Aura.diff(obj.AddEffectToAura(effect)).contains(effect)) {
|
||||
SetupAggravationEntry(aggravation)
|
||||
UpdateAggravatedEffect(obj)
|
||||
}
|
||||
}
|
||||
|
||||
private def SetupAggravationEntry(aggravation : AggravatedDamage) : Unit = {
|
||||
val effect = aggravation.effect_type
|
||||
aggravation.info.foreach { infos =>
|
||||
//get unused id
|
||||
val id = activeEffectIndex
|
||||
activeEffectIndex += 1
|
||||
//pair aura effect with id
|
||||
effectsToIds.get(effect) match {
|
||||
case None | Some(Nil) => effectsToIds += effect -> List(id)
|
||||
case Some(list) => effectsToIds -> (list :+ id)
|
||||
if(CheckForUniqueUnqueuedProjectile(data.projectile)) {
|
||||
val auraEffects = obj.Aura
|
||||
if(auraEffects.contains(effect) && aggravation.cumulative_damage_degrade) { //TODO cumulative?
|
||||
SetupAggravationEntry(aggravation, data)
|
||||
}
|
||||
else if(obj.AddEffectToAura(effect).diff(auraEffects).contains(effect)) {
|
||||
SetupAggravationEntry(aggravation, data)
|
||||
UpdateAggravatedEffect(obj)
|
||||
}
|
||||
//pair id with entry
|
||||
idsToEntries += id -> AuraEffectBehavior.Entry(id, infos, aggravation, 0)
|
||||
//pair id with timer
|
||||
val iterations = (aggravation.duration / infos.infliction_rate).toInt
|
||||
val leftoverTime = aggravation.duration % infos.infliction_rate
|
||||
idsToTimers += id -> context.system.scheduler.scheduleOnce(infos.infliction_rate milliseconds, self, AuraEffectBehavior.Aggravate(id, iterations, leftoverTime))
|
||||
}
|
||||
}
|
||||
|
||||
def CleanupEffect(id : Long) : Aura.Value = {
|
||||
private def CheckForUniqueUnqueuedProjectile(projectile : Projectile) : Boolean = {
|
||||
!entryIdToEntry.values.exists { entry => entry.data.projectile eq projectile }
|
||||
}
|
||||
|
||||
private def SetupAggravationEntry(aggravation: AggravatedDamage, data: ResolvedProjectile) : Unit = {
|
||||
val effect = aggravation.effect_type
|
||||
aggravation.info.find(_.damage_type == AuraEffectBehavior.basicDamageType(data.resolution)) match {
|
||||
case Some(info) =>
|
||||
//get unused id
|
||||
val id = activeEffectIndex
|
||||
activeEffectIndex += 1
|
||||
//pair aura effect with id
|
||||
effectToEntryId.get(effect) match {
|
||||
case None | Some(Nil) => effectToEntryId += effect -> List(id)
|
||||
case Some(list) => effectToEntryId -> (list :+ id)
|
||||
}
|
||||
//pair id with timer
|
||||
val inflictionRate = info.infliction_rate
|
||||
val iterations = (aggravation.duration / inflictionRate).toInt
|
||||
val leftoverTime = aggravation.duration % inflictionRate
|
||||
entryIdToTimer += id -> context.system.scheduler.scheduleOnce(inflictionRate milliseconds, self, AuraEffectBehavior.Aggravate(id, iterations, leftoverTime))
|
||||
//pair id with entry
|
||||
PairIdWithAggravationEntry(id, effect, inflictionRate, data, data.target, Vector3.Zero)
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
||||
private def PairIdWithAggravationEntry(
|
||||
id: Long,
|
||||
effect: Aura.Value,
|
||||
retime:Long,
|
||||
data: ResolvedProjectile,
|
||||
target: SourceEntry,
|
||||
offset: Vector3
|
||||
): AuraEffectBehavior.Entry = {
|
||||
val aggravatedDamageInfo = ResolvedProjectile(
|
||||
AuraEffectBehavior.burning(data.resolution),
|
||||
data.projectile,
|
||||
target,
|
||||
data.damage_model,
|
||||
data.hit_pos + offset
|
||||
)
|
||||
val entry = AuraEffectBehavior.Entry(id, effect, retime, aggravatedDamageInfo)
|
||||
entryIdToEntry += id -> entry
|
||||
entry
|
||||
}
|
||||
|
||||
def RemoveEffectEntry(id: Long) : Aura.Value = {
|
||||
entryIdToEntry.remove(id) match {
|
||||
case Some(entry) =>
|
||||
entry.data.projectile.profile.Aggravated.get.effect_type
|
||||
case None =>
|
||||
effectToEntryId.find { case (_, values) => values.contains(id) } match {
|
||||
case Some((effect, _)) => effect
|
||||
case _ => Aura.None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def CleanupEffect(id: Long) : Aura.Value = {
|
||||
//remove and cancel timer
|
||||
idsToTimers.remove(id) match {
|
||||
entryIdToTimer.remove(id) match {
|
||||
case Some(timer) => timer.cancel
|
||||
case _ => ;
|
||||
}
|
||||
//remove entry and cache effect
|
||||
val out = idsToEntries.remove(id) match {
|
||||
case Some(entry) => entry.aggravation.effect_type
|
||||
case _ => Aura.None
|
||||
}
|
||||
val out = RemoveEffectEntry(id)
|
||||
//remove id and, if now unsupported, effect
|
||||
(effectsToIds.get(out) match {
|
||||
(effectToEntryId.get(out) match {
|
||||
case Some(list) => (out, list.filterNot(_ == id))
|
||||
case _ => (Aura.None, Nil)
|
||||
}) match {
|
||||
case (Aura.None, _) =>
|
||||
Aura.None
|
||||
case (effect, Nil) =>
|
||||
effectsToIds.remove(effect)
|
||||
AuraTargetObject.RemoveEffectFromAura(effect)
|
||||
effectToEntryId.remove(effect)
|
||||
effect
|
||||
case (effect, list) =>
|
||||
effectsToIds += effect -> list
|
||||
effectToEntryId += effect -> list
|
||||
Aura.None
|
||||
}
|
||||
}
|
||||
|
||||
def EndAllEffects() : Unit = {
|
||||
idsToEntries.clear
|
||||
idsToTimers.values.foreach { _.cancel }
|
||||
idsToTimers.clear
|
||||
effectsToIds.clear
|
||||
entryIdToEntry.clear
|
||||
entryIdToTimer.values.foreach { _.cancel }
|
||||
entryIdToTimer.clear
|
||||
effectToEntryId.clear
|
||||
val obj = AuraTargetObject
|
||||
obj.Aura.foreach { obj.RemoveEffectFromAura }
|
||||
}
|
||||
|
||||
def EndAllEffectsAndUpdate() : Unit = {
|
||||
|
|
@ -140,16 +212,39 @@ trait AuraEffectBehavior {
|
|||
UpdateAggravatedEffect(AuraTargetObject)
|
||||
}
|
||||
|
||||
def UpdateAggravatedEffect(target : Player) : Unit = {
|
||||
def UpdateAggravatedEffect(target: Player) : Unit = {
|
||||
import services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||
val zone = target.Zone
|
||||
val value = target.Aura.foldLeft(0)(_ + _.id)
|
||||
zone.AvatarEvents ! AvatarServiceMessage(zone.Id, AvatarAction.PlanetsideAttributeToAll(target.GUID, 54, value))
|
||||
}
|
||||
|
||||
private def PerformAggravation(entry: AuraEffectBehavior.Entry) : Unit = {
|
||||
TakesDamage.apply(Vitality.Damage(entry.data.damage_model.Calculate(entry.data)))
|
||||
}
|
||||
}
|
||||
|
||||
object AuraEffectBehavior {
|
||||
private case class Entry(id : Long, effect : AggravatedInfo, aggravation : AggravatedDamage, damage : Any)
|
||||
private case class Entry(id: Long, effect: Aura.Value, retime: Long, data: ResolvedProjectile)
|
||||
|
||||
private case class Aggravate(id : Long, iterations : Int, leftover : Long)
|
||||
private case class Aggravate(id: Long, iterations: Int, leftover: Long)
|
||||
|
||||
private def burning(resolution: ProjectileResolution.Value): ProjectileResolution.Value = {
|
||||
resolution match {
|
||||
case ProjectileResolution.AggravatedDirect => ProjectileResolution.AggravatedDirectBurn
|
||||
case ProjectileResolution.AggravatedSplash => ProjectileResolution.AggravatedSplashBurn
|
||||
case _ => resolution
|
||||
}
|
||||
}
|
||||
|
||||
private def basicDamageType(resolution: ProjectileResolution.Value): DamageType.Value = {
|
||||
resolution match {
|
||||
case ProjectileResolution.AggravatedDirect | ProjectileResolution.AggravatedDirectBurn =>
|
||||
DamageType.Direct
|
||||
case ProjectileResolution.AggravatedSplash | ProjectileResolution.AggravatedSplashBurn =>
|
||||
DamageType.Splash
|
||||
case _ =>
|
||||
DamageType.None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue