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] = { override def ConstructorData(obj : CaptureFlag) : Try[CaptureFlagData] = {
val hackInfo = obj.Owner.asInstanceOf[Building].CaptureTerminal.get.HackedBy match { val hackInfo = obj.Owner.asInstanceOf[Building].CaptureTerminal.get.HackedBy match {
case Some(hackInfo) => hackInfo 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()) 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] = { def HackedBy_=(agent: Option[Player]): Option[HackInfo] = {
(hackedBy, agent) match { (hackedBy, agent) match {
case (None, Some(actor)) => 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)) => case (Some(info), Some(actor)) =>
if (actor.Faction == this.Faction) { if (actor.Faction == this.Faction) {
//hack cleared //hack cleared
hackedBy = None hackedBy = None
} else if (actor.Faction != info.hackerFaction) { } else if (actor.Faction != info.hackerFaction) {
//override the hack state with a new hack state if the new user has different faction affiliation //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) => case (_, None) =>
hackedBy = None hackedBy = None
@ -73,14 +73,15 @@ trait Hackable {
object Hackable { object Hackable {
final case class HackInfo( final case class HackInfo(
player: PlayerSource, player: PlayerSource,
hackerGUID: PlanetSideGUID, hackerGUID: PlanetSideGUID,
hackStartTime: Long, hackStartTime: Long,
hackDuration: Long hackDuration: Long,
originalFaction: PlanetSideEmpire.Value
) { ) {
def hackerName: String = player.Name def hackerName: String = player.Name
def hackerFaction: PlanetSideEmpire.Value = player.Faction def hackerFaction: PlanetSideEmpire.Value = player.Faction
def hackerPos: Vector3 = player.Position 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 { val (hacking, hackingFaction, hackTime): (Boolean, PlanetSideEmpire.Value, Long) = CaptureTerminal match {
case Some(obj: CaptureTerminal with Hackable) => case Some(obj: CaptureTerminal with Hackable) =>
obj.HackedBy match { 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()) val hack_time_remaining_ms = math.max(0, start + length - System.currentTimeMillis())
(true, p.Faction, hack_time_remaining_ms) (true, p.Faction, hack_time_remaining_ms)
case _ => 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 playerContribution: mutable.LongMap[(Player, Int, Long)] = mutable.LongMap[(Player, Int, Long)]()
protected var playerPopulationOverTime: Seq[Map[PlanetSideEmpire.Value, Int]] = Seq[Map[PlanetSideEmpire.Value, Int]]() 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] = { def PlayerContribution(timeDelay: Long): Map[Long, Float] = {
playerContribution playerContribution
.collect { .collect {

View file

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

View file

@ -1,6 +1,7 @@
// Copyright (c) 2023 PSForever // Copyright (c) 2023 PSForever
package net.psforever.objects.serverobject.structures.participation package net.psforever.objects.serverobject.structures.participation
import net.psforever.objects.Player
import net.psforever.objects.serverobject.structures.Building import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.sourcing.PlayerSource import net.psforever.objects.sourcing.PlayerSource
import net.psforever.types.PlanetSideEmpire import net.psforever.types.PlanetSideEmpire
@ -31,5 +32,7 @@ trait ParticipationLogic {
isResecured: Boolean isResecured: Boolean
): Unit ): Unit
def PlayerContributionRaw: Map[Long, (Player, Int, Long)]
def PlayerContribution(timeDelay: Long = 600): Map[Long, Float] 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 = { override def toString: String = {
val guid = if (HasGUID) { val guid = if (HasGUID) {
s" ${Continent}-${GUID.guid}" s" $Continent-${GUID.guid}"
} else { } else {
"" ""
} }

View file

@ -320,33 +320,25 @@ object KillAssists {
0L 0L
} else if (base > 1) { } else if (base > 1) {
//include battle rank disparity modifier //include battle rank disparity modifier
val battleRankDisparity = { val battleRankDisparity: Long = {
import net.psforever.objects.avatar.BattleRank import net.psforever.objects.avatar.BattleRank
val killerLevel = BattleRank.withExperience(killer.bep).value val killerLevel = BattleRank.withExperience(killer.bep).value
val victimLevel = BattleRank.withExperience(victim.bep).value val victimLevel = BattleRank.withExperience(victim.bep).value
if (victimLevel > killerLevel || killerLevel - victimLevel < 6) { val victimMinusKiller = victimLevel - killerLevel
if (killerLevel < 7) { if (victimMinusKiller > -1) {
6 * victimLevel + 10 victimMinusKiller * 10 + victimLevel
} else if (killerLevel < 12) {
(12 - killerLevel) * victimLevel + 10
} else if (killerLevel < 25) {
25 + victimLevel - killerLevel
} else {
25
}
} else { } 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)
})
} }
} }.toLong
val baseWithDisparity: Long = base + battleRankDisparity //include menace modifier
val killCount: Long = victim.progress.kills.size base + battleRankDisparity + (victim.progress.kills.size.toFloat * (1f + calculateMenace(victim).toFloat / 10f)).toLong
if (battleRankDisparity > 0) {
//include menace modifier
val pureMenace = calculateMenace(victim)
baseWithDisparity + (killCount * (1f + pureMenace.toFloat / 10f)).toLong
} else {
math.max(baseWithDisparity, killCount)
}
} else { } else {
base 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 // Timed hack finished (or neutral LLU base with no neighbour as timed hack), capture the base
val hackTime = terminal.Definition.FacilityHackTime.toMillis val hackTime = terminal.Definition.FacilityHackTime.toMillis
HackCompleted(terminal, hackedByFaction) 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 // 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) case flag: CaptureFlag => target.Zone.LocalEvents ! CaptureFlagManager.Lost(flag, CaptureFlagLostReasonEnum.Resecured)
} }
NotifyHackStateChange(target, isResecured = true) 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 // Restart the timer in case the object we just removed was the next one scheduled
RestartTimer() RestartTimer()
@ -111,7 +125,14 @@ class HackCaptureActor extends Actor {
val hackedByFaction = hackInfo.hackerFaction val hackedByFaction = hackInfo.hackerFaction
hackedObjects = hackedObjects.filterNot(x => x == entry) hackedObjects = hackedObjects.filterNot(x => x == entry)
HackCompleted(terminal, hackedByFaction) 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() entry.target.Actor ! CommonMessages.ClearHack()
flag.Zone.LocalEvents ! CaptureFlagManager.Captured(flag) flag.Zone.LocalEvents ! CaptureFlagManager.Captured(flag)
// If there's hacked objects left in the list restart the timer with the shortest hack time left // 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 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] = { def GetHackingFaction(terminal: CaptureTerminal): Option[PlanetSideEmpire.Value] = {
terminal.HackedBy.map { a => a.player.Faction } terminal.HackedBy.map { a => a.player.Faction }
} }
@ -255,7 +314,7 @@ object HackCaptureActor {
terminal.HackedBy match { terminal.HackedBy match {
case _ if isResecured => case _ if isResecured =>
17039360L 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 // See PlanetSideAttributeMessage #20 documentation for an explanation of how the timer is calculated
val hackTimeRemainingMS = math.max(0, start + length - System.currentTimeMillis()) val hackTimeRemainingMS = math.max(0, start + length - System.currentTimeMillis())
val startNum = p.Faction match { val startNum = p.Faction match {