mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-15 08:24:39 +00:00
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:
parent
7f61206ddd
commit
cc2089b513
9 changed files with 95 additions and 35 deletions
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 _ =>
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue