make a better guess on the wonership of a facility during a capture/resecure; during a neutral capture, an 'owning side' will be decalred based on effort; changed the calculation of kill experience to simplify the modifiers and reduce the potential to have 0 bep

This commit is contained in:
Fate-JH 2023-11-13 02:24:36 -05:00
parent 7f61206ddd
commit cc2089b513
9 changed files with 95 additions and 35 deletions

View file

@ -14,7 +14,7 @@ class CaptureFlagConverter extends ObjectCreateConverter[CaptureFlag]() {
override def ConstructorData(obj : CaptureFlag) : Try[CaptureFlagData] = {
val hackInfo = obj.Owner.asInstanceOf[Building].CaptureTerminal.get.HackedBy match {
case Some(hackInfo) => hackInfo
case _ => Hackable.HackInfo(PlayerSource("", PlanetSideEmpire.NEUTRAL, Vector3.Zero), PlanetSideGUID(0), 0L, 0L)
case _ => Hackable.HackInfo(PlayerSource("", PlanetSideEmpire.NEUTRAL, Vector3.Zero), PlanetSideGUID(0), 0L, 0L, obj.Faction)
}
val millisecondsRemaining = math.max(0, hackInfo.hackStartTime + hackInfo.hackDuration - System.currentTimeMillis())

View file

@ -25,14 +25,14 @@ trait Hackable {
def HackedBy_=(agent: Option[Player]): Option[HackInfo] = {
(hackedBy, agent) match {
case (None, Some(actor)) =>
hackedBy = Some(HackInfo(PlayerSource(actor), actor.GUID, System.currentTimeMillis(), 0L))
hackedBy = Some(HackInfo(PlayerSource(actor), actor.GUID, System.currentTimeMillis(), 0L, Faction))
case (Some(info), Some(actor)) =>
if (actor.Faction == this.Faction) {
//hack cleared
hackedBy = None
} else if (actor.Faction != info.hackerFaction) {
//override the hack state with a new hack state if the new user has different faction affiliation
hackedBy = Some(HackInfo(PlayerSource(actor), actor.GUID, System.currentTimeMillis(), 0L))
hackedBy = Some(HackInfo(PlayerSource(actor), actor.GUID, System.currentTimeMillis(), 0L, Faction))
}
case (_, None) =>
hackedBy = None
@ -73,14 +73,15 @@ trait Hackable {
object Hackable {
final case class HackInfo(
player: PlayerSource,
hackerGUID: PlanetSideGUID,
hackStartTime: Long,
hackDuration: Long
hackerGUID: PlanetSideGUID,
hackStartTime: Long,
hackDuration: Long,
originalFaction: PlanetSideEmpire.Value
) {
def hackerName: String = player.Name
def hackerFaction: PlanetSideEmpire.Value = player.Faction
def hackerPos: Vector3 = player.Position
def Duration(time: Long): HackInfo = HackInfo(player, hackerGUID, hackStartTime, time)
def Duration(time: Long): HackInfo = HackInfo(player, hackerGUID, hackStartTime, time, originalFaction)
}
}

View file

@ -182,7 +182,7 @@ class Building(
val (hacking, hackingFaction, hackTime): (Boolean, PlanetSideEmpire.Value, Long) = CaptureTerminal match {
case Some(obj: CaptureTerminal with Hackable) =>
obj.HackedBy match {
case Some(Hackable.HackInfo(p, _, start, length)) =>
case Some(Hackable.HackInfo(p, _, start, length, _)) =>
val hack_time_remaining_ms = math.max(0, start + length - System.currentTimeMillis())
(true, p.Faction, hack_time_remaining_ms)
case _ =>

View file

@ -18,6 +18,8 @@ trait FacilityHackParticipation extends ParticipationLogic {
protected var playerContribution: mutable.LongMap[(Player, Int, Long)] = mutable.LongMap[(Player, Int, Long)]()
protected var playerPopulationOverTime: Seq[Map[PlanetSideEmpire.Value, Int]] = Seq[Map[PlanetSideEmpire.Value, Int]]()
def PlayerContributionRaw: Map[Long, (Player, Int, Long)] = playerContribution.toMap
def PlayerContribution(timeDelay: Long): Map[Long, Float] = {
playerContribution
.collect {

View file

@ -1,6 +1,7 @@
// Copyright (c) 2023 PSForever
package net.psforever.objects.serverobject.structures.participation
import net.psforever.objects.Player
import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.sourcing.PlayerSource
import net.psforever.types.PlanetSideEmpire
@ -16,5 +17,7 @@ case object NoParticipation extends ParticipationLogic {
completionTime: Long,
isResecured: Boolean
): Unit = { /* nothing here */ }
override def PlayerContributionRaw: Map[Long, (Player, Int, Long)] = Map.empty[Long, (Player, Int, Long)]
override def PlayerContribution(timeDelay: Long): Map[Long, Float] = Map.empty[Long, Float]
}

View file

@ -1,6 +1,7 @@
// Copyright (c) 2023 PSForever
package net.psforever.objects.serverobject.structures.participation
import net.psforever.objects.Player
import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.sourcing.PlayerSource
import net.psforever.types.PlanetSideEmpire
@ -31,5 +32,7 @@ trait ParticipationLogic {
isResecured: Boolean
): Unit
def PlayerContributionRaw: Map[Long, (Player, Int, Long)]
def PlayerContribution(timeDelay: Long = 600): Map[Long, Float]
}

View file

@ -12,7 +12,7 @@ class CaptureTerminal(private val idef: CaptureTerminalDefinition) extends Ameni
override def toString: String = {
val guid = if (HasGUID) {
s" ${Continent}-${GUID.guid}"
s" $Continent-${GUID.guid}"
} else {
""
}

View file

@ -320,33 +320,25 @@ object KillAssists {
0L
} else if (base > 1) {
//include battle rank disparity modifier
val battleRankDisparity = {
val battleRankDisparity: Long = {
import net.psforever.objects.avatar.BattleRank
val killerLevel = BattleRank.withExperience(killer.bep).value
val victimLevel = BattleRank.withExperience(victim.bep).value
if (victimLevel > killerLevel || killerLevel - victimLevel < 6) {
if (killerLevel < 7) {
6 * victimLevel + 10
} else if (killerLevel < 12) {
(12 - killerLevel) * victimLevel + 10
} else if (killerLevel < 25) {
25 + victimLevel - killerLevel
} else {
25
}
val victimMinusKiller = victimLevel - killerLevel
if (victimMinusKiller > -1) {
victimMinusKiller * 10 + victimLevel
} else {
math.floor(-0.15f * base - killerLevel + victimLevel).toLong
val bothLevels = killerLevel + victimLevel
val pointFive = (base.toFloat * 0.25f).toInt
-1 * (if (bothLevels >= base) {
pointFive
} else {
math.min(bothLevels, pointFive)
})
}
}
val baseWithDisparity: Long = base + battleRankDisparity
val killCount: Long = victim.progress.kills.size
if (battleRankDisparity > 0) {
//include menace modifier
val pureMenace = calculateMenace(victim)
baseWithDisparity + (killCount * (1f + pureMenace.toFloat / 10f)).toLong
} else {
math.max(baseWithDisparity, killCount)
}
}.toLong
//include menace modifier
base + battleRankDisparity + (victim.progress.kills.size.toFloat * (1f + calculateMenace(victim).toFloat / 10f)).toLong
} else {
base
}

View file

@ -78,7 +78,14 @@ class HackCaptureActor extends Actor {
// Timed hack finished (or neutral LLU base with no neighbour as timed hack), capture the base
val hackTime = terminal.Definition.FacilityHackTime.toMillis
HackCompleted(terminal, hackedByFaction)
building.Participation.RewardFacilityCapture(terminal.Faction, hackedByFaction, hacker, hackTime, hackTime, isResecured = false)
building.Participation.RewardFacilityCapture(
HackCaptureActor.GetDefendingFaction(terminal, building, hackedByFaction),
hackedByFaction,
hacker,
hackTime,
hackTime,
isResecured = false
)
}
}
// If there's hacked objects left in the list restart the timer with the shortest hack time left
@ -95,7 +102,14 @@ class HackCaptureActor extends Actor {
case flag: CaptureFlag => target.Zone.LocalEvents ! CaptureFlagManager.Lost(flag, CaptureFlagLostReasonEnum.Resecured)
}
NotifyHackStateChange(target, isResecured = true)
building.Participation.RewardFacilityCapture(target.Faction, faction, hacker, target.Definition.FacilityHackTime.toMillis, System.currentTimeMillis() - results.head.hack_timestamp, isResecured = true)
building.Participation.RewardFacilityCapture(
target.Faction,
faction,
hacker,
target.Definition.FacilityHackTime.toMillis,
System.currentTimeMillis() - results.head.hack_timestamp,
isResecured = true
)
// Restart the timer in case the object we just removed was the next one scheduled
RestartTimer()
@ -111,7 +125,14 @@ class HackCaptureActor extends Actor {
val hackedByFaction = hackInfo.hackerFaction
hackedObjects = hackedObjects.filterNot(x => x == entry)
HackCompleted(terminal, hackedByFaction)
building.Participation.RewardFacilityCapture(terminal.Faction, hacker.Faction, hacker, terminal.Definition.FacilityHackTime.toMillis, System.currentTimeMillis() - entry.hack_timestamp, isResecured = false)
building.Participation.RewardFacilityCapture(
HackCaptureActor.GetDefendingFaction(terminal, building, hackedByFaction),
hackedByFaction,
hacker,
terminal.Definition.FacilityHackTime.toMillis,
System.currentTimeMillis() - entry.hack_timestamp,
isResecured = false
)
entry.target.Actor ! CommonMessages.ClearHack()
flag.Zone.LocalEvents ! CaptureFlagManager.Captured(flag)
// If there's hacked objects left in the list restart the timer with the shortest hack time left
@ -247,6 +268,44 @@ object HackCaptureActor {
hack_timestamp: Long
)
def GetDefendingFaction(
terminal: CaptureTerminal,
building: Building,
excludeThisFaction: PlanetSideEmpire.Value
): PlanetSideEmpire.Value = {
terminal.HackedBy
.map { _.originalFaction }
.orElse { Some(terminal.Faction) }
.collect {
case PlanetSideEmpire.NEUTRAL =>
val factionEfforts = building.Participation
.PlayerContributionRaw
.values
.foldLeft(Array.fill(4)(0L))({ case (a, b) =>
val (player, duration, _) = b
val index = player.Faction.id
a.update(index, a(index) + duration.toLong)
a
})
factionEfforts.update(excludeThisFaction.id, Long.MinValue)
factionEfforts
.indices
.maxByOption(factionEfforts)
.map { index => PlanetSideEmpire(index) }
.getOrElse {
val test = PlanetSideEmpire(0)
if (excludeThisFaction == test) {
PlanetSideEmpire(1)
} else {
test
}
}
case faction =>
faction
}
.get
}
def GetHackingFaction(terminal: CaptureTerminal): Option[PlanetSideEmpire.Value] = {
terminal.HackedBy.map { a => a.player.Faction }
}
@ -255,7 +314,7 @@ object HackCaptureActor {
terminal.HackedBy match {
case _ if isResecured =>
17039360L
case Some(Hackable.HackInfo(p, _, start, length)) =>
case Some(Hackable.HackInfo(p, _, start, length, _)) =>
// See PlanetSideAttributeMessage #20 documentation for an explanation of how the timer is calculated
val hackTimeRemainingMS = math.max(0, start + length - System.currentTimeMillis())
val startNum = p.Faction match {