mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-14 16:04:41 +00:00
exp for ntu and ntu silo operation restored; message about progress system given more limited scope; adjusted cep for llu carrier kill; kd accumulates by kills and maintains between lives; ifflock does not discriminate rehack faction; no rewards for killing allies, or self
This commit is contained in:
parent
52deb2b212
commit
7f61206ddd
14 changed files with 257 additions and 125 deletions
|
|
@ -362,7 +362,7 @@ game {
|
||||||
# If a player died while carrying an lattice logic unit,
|
# If a player died while carrying an lattice logic unit,
|
||||||
# award the player who is accredited with the kill command experience as long as the time it had been carried longer than this duration.
|
# award the player who is accredited with the kill command experience as long as the time it had been carried longer than this duration.
|
||||||
# Can set to Duration.Inf to never pass.
|
# Can set to Duration.Inf to never pass.
|
||||||
llu-slayer-credit-duration = 1 minute
|
llu-slayer-credit-duration = 30 seconds
|
||||||
# If a player died while carrying an lattice logic unit,
|
# If a player died while carrying an lattice logic unit,
|
||||||
# and satisfies the carrying duration,
|
# and satisfies the carrying duration,
|
||||||
# award the player who is accredited with the kill command experience.
|
# award the player who is accredited with the kill command experience.
|
||||||
|
|
@ -389,6 +389,11 @@ game {
|
||||||
# Anyone who is currently enrolled in the promotion system remains enrolled during normal game play.
|
# Anyone who is currently enrolled in the promotion system remains enrolled during normal game play.
|
||||||
# Relenting on the promotion debt back to battle rank 2 is still possible.
|
# Relenting on the promotion debt back to battle rank 2 is still possible.
|
||||||
active = true
|
active = true
|
||||||
|
# This battle rank and any battle ranks of ordinal decrement that allow opt-in to the progression system.
|
||||||
|
broadcast-battle-rank = 1
|
||||||
|
# This is the minimum battle rank that can be set as part of the promotion system.
|
||||||
|
# Used to escape debt and return to normal play.
|
||||||
|
reset-battle-rank = 2
|
||||||
# This is the maximum battle rank that can be set as part of the promotion system.
|
# This is the maximum battle rank that can be set as part of the promotion system.
|
||||||
max-battle-rank = 13
|
max-battle-rank = 13
|
||||||
# How much direct combat contributes to paying back promotion debt.
|
# How much direct combat contributes to paying back promotion debt.
|
||||||
|
|
|
||||||
|
|
@ -1063,6 +1063,9 @@ class AvatarActor(
|
||||||
case DeleteAvatar(id) =>
|
case DeleteAvatar(id) =>
|
||||||
import ctx._
|
import ctx._
|
||||||
val performDeletion = for {
|
val performDeletion = for {
|
||||||
|
_ <- ctx.run(query[persistence.Weaponstatsession].filter(_.avatarId == lift(id)).delete)
|
||||||
|
_ <- ctx.run(query[persistence.Kdasession].filter(_.avatarId == lift(id)).delete)
|
||||||
|
_ <- ctx.run(query[persistence.Buildingcapture].filter(_.avatarId == lift(id)).delete)
|
||||||
_ <- ctx.run(query[persistence.Shortcut].filter(_.avatarId == lift(id)).delete)
|
_ <- ctx.run(query[persistence.Shortcut].filter(_.avatarId == lift(id)).delete)
|
||||||
_ <- ctx.run(query[persistence.Implant].filter(_.avatarId == lift(id)).delete)
|
_ <- ctx.run(query[persistence.Implant].filter(_.avatarId == lift(id)).delete)
|
||||||
_ <- ctx.run(query[persistence.Loadout].filter(_.avatarId == lift(id)).delete)
|
_ <- ctx.run(query[persistence.Loadout].filter(_.avatarId == lift(id)).delete)
|
||||||
|
|
@ -1646,11 +1649,16 @@ class AvatarActor(
|
||||||
if ({
|
if ({
|
||||||
val oldBr = BattleRank.withExperience(avatar.bep).value
|
val oldBr = BattleRank.withExperience(avatar.bep).value
|
||||||
val newBr = BattleRank.withExperience(bep).value
|
val newBr = BattleRank.withExperience(bep).value
|
||||||
if (Config.app.game.promotion.active && oldBr == 1 && newBr > 1 && newBr < Config.app.game.promotion.maxBattleRank + 1) {
|
val resetBr = Config.app.game.promotion.resetBattleRank
|
||||||
|
if (
|
||||||
|
Config.app.game.promotion.active &&
|
||||||
|
oldBr <= Config.app.game.promotion.broadcastBattleRank &&
|
||||||
|
newBr > resetBr && newBr < Config.app.game.promotion.maxBattleRank + 1
|
||||||
|
) {
|
||||||
experienceDebt = bep
|
experienceDebt = bep
|
||||||
AvatarActor.saveExperienceDebt(avatar.id, bep, bep)
|
AvatarActor.saveExperienceDebt(avatar.id, bep, bep)
|
||||||
true
|
true
|
||||||
} else if (experienceDebt > 0 && newBr == 2) {
|
} else if (experienceDebt > 0 && newBr == resetBr) {
|
||||||
experienceDebt = 0
|
experienceDebt = 0
|
||||||
AvatarActor.saveExperienceDebt(avatar.id, exp = 0, bep)
|
AvatarActor.saveExperienceDebt(avatar.id, exp = 0, bep)
|
||||||
true
|
true
|
||||||
|
|
@ -1663,7 +1671,6 @@ class AvatarActor(
|
||||||
setCep(0L)
|
setCep(0L)
|
||||||
}
|
}
|
||||||
restoreBasicCerts()
|
restoreBasicCerts()
|
||||||
removeAllImplants()
|
|
||||||
sessionActor ! SessionActor.CharSaved
|
sessionActor ! SessionActor.CharSaved
|
||||||
sessionActor ! SessionActor.SendResponse(ChatMsg(ChatMessageType.UNK_229, "@AckSuccessSetBattleRank"))
|
sessionActor ! SessionActor.SendResponse(ChatMsg(ChatMessageType.UNK_229, "@AckSuccessSetBattleRank"))
|
||||||
} else if (experienceDebt > 0) {
|
} else if (experienceDebt > 0) {
|
||||||
|
|
@ -1674,9 +1681,9 @@ class AvatarActor(
|
||||||
Behaviors.same
|
Behaviors.same
|
||||||
|
|
||||||
case AwardCep(cep) =>
|
case AwardCep(cep) =>
|
||||||
if (experienceDebt > 0L) {
|
if (experienceDebt == 0L) {
|
||||||
setCep(avatar.cep + cep)
|
setCep(avatar.cep + cep)
|
||||||
} else {
|
} else if (cep > 0) {
|
||||||
sessionActor ! SessionActor.SendResponse(ExperienceAddedMessage(0))
|
sessionActor ! SessionActor.SendResponse(ExperienceAddedMessage(0))
|
||||||
}
|
}
|
||||||
Behaviors.same
|
Behaviors.same
|
||||||
|
|
@ -1851,16 +1858,77 @@ class AvatarActor(
|
||||||
}
|
}
|
||||||
|
|
||||||
def performAvatarLogin(avatarId: Long, accountId: Long, replyTo: ActorRef[AvatarLoginResponse]): Unit = {
|
def performAvatarLogin(avatarId: Long, accountId: Long, replyTo: ActorRef[AvatarLoginResponse]): Unit = {
|
||||||
|
performAvatarLogin0(avatarId, accountId, replyTo)
|
||||||
|
// import ctx._
|
||||||
|
// val result = for {
|
||||||
|
// //log this login
|
||||||
|
// _ <- ctx.run(
|
||||||
|
// query[persistence.Avatar]
|
||||||
|
// .filter(_.id == lift(avatarId))
|
||||||
|
// .update(_.lastLogin -> lift(LocalDateTime.now()))
|
||||||
|
// )
|
||||||
|
// //log this choice of faction (no empire switching)
|
||||||
|
// _ <- ctx.run(
|
||||||
|
// query[persistence.Account]
|
||||||
|
// .filter(_.id == lift(accountId))
|
||||||
|
// .update(
|
||||||
|
// _.lastFactionId -> lift(avatar.faction.id),
|
||||||
|
// _.avatarLoggedIn -> lift(avatarId)
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
// //retrieve avatar data
|
||||||
|
// loadouts <- initializeAllLoadouts()
|
||||||
|
// implants <- ctx.run(query[persistence.Implant].filter(_.avatarId == lift(avatarId)))
|
||||||
|
// certs <- ctx.run(query[persistence.Certification].filter(_.avatarId == lift(avatarId)))
|
||||||
|
// locker <- loadLocker(avatarId)
|
||||||
|
// friends <- loadFriendList(avatarId)
|
||||||
|
// ignored <- loadIgnoredList(avatarId)
|
||||||
|
// shortcuts <- loadShortcuts(avatarId)
|
||||||
|
// saved <- AvatarActor.loadSavedAvatarData(avatarId)
|
||||||
|
// debt <- AvatarActor.loadExperienceDebt(avatarId)
|
||||||
|
// card <- AvatarActor.loadCampaignKdaData(avatarId)
|
||||||
|
// } yield (loadouts, implants, certs, locker, friends, ignored, shortcuts, saved, debt, card)
|
||||||
|
// result.onComplete {
|
||||||
|
// case Success((_loadouts, implants, certs, lockerInv, friendsList, ignoredList, shortcutList, saved, debt, card)) =>
|
||||||
|
// avatarCopy(
|
||||||
|
// avatar.copy(
|
||||||
|
// loadouts = avatar.loadouts.copy(suit = _loadouts),
|
||||||
|
// certifications =
|
||||||
|
// certs.map(cert => Certification.withValue(cert.id)).toSet ++ Config.app.game.baseCertifications,
|
||||||
|
// implants = implants.map(implant => Some(Implant(implant.toImplantDefinition))).padTo(3, None),
|
||||||
|
// shortcuts = shortcutList,
|
||||||
|
// locker = lockerInv,
|
||||||
|
// people = MemberLists(
|
||||||
|
// friend = friendsList,
|
||||||
|
// ignored = ignoredList
|
||||||
|
// ),
|
||||||
|
// cooldowns = Cooldowns(
|
||||||
|
// purchase = AvatarActor.buildCooldownsFromClob(saved.purchaseCooldowns, Avatar.purchaseCooldowns, log),
|
||||||
|
// use = AvatarActor.buildCooldownsFromClob(saved.useCooldowns, Avatar.useCooldowns, log)
|
||||||
|
// ),
|
||||||
|
// scorecard = card
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
// // if we need to start stamina regeneration
|
||||||
|
// tryRestoreStaminaForSession(stamina = 1).collect { _ => defaultStaminaRegen(initialDelay = 0.5f seconds) }
|
||||||
|
// experienceDebt = debt
|
||||||
|
// replyTo ! AvatarLoginResponse(avatar)
|
||||||
|
// case Failure(e) =>
|
||||||
|
// log.error(e)("db failure")
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
def performAvatarLogin0(avatarId: Long, accountId: Long, replyTo: ActorRef[AvatarLoginResponse]): Unit = {
|
||||||
import ctx._
|
import ctx._
|
||||||
val result = for {
|
val result = for {
|
||||||
//log this login
|
//log this login
|
||||||
_ <- ctx.run(
|
loginTime <- ctx.run(
|
||||||
query[persistence.Avatar]
|
query[persistence.Avatar]
|
||||||
.filter(_.id == lift(avatarId))
|
.filter(_.id == lift(avatarId))
|
||||||
.update(_.lastLogin -> lift(LocalDateTime.now()))
|
.update(_.lastLogin -> lift(LocalDateTime.now()))
|
||||||
)
|
)
|
||||||
//log this choice of faction (no empire switching)
|
//log this choice of faction (no empire switching)
|
||||||
_ <- ctx.run(
|
loginFaction <- ctx.run(
|
||||||
query[persistence.Account]
|
query[persistence.Account]
|
||||||
.filter(_.id == lift(accountId))
|
.filter(_.id == lift(accountId))
|
||||||
.update(
|
.update(
|
||||||
|
|
@ -1868,50 +1936,64 @@ class AvatarActor(
|
||||||
_.avatarLoggedIn -> lift(avatarId)
|
_.avatarLoggedIn -> lift(avatarId)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
//retrieve avatar data
|
} yield (loginTime, loginFaction)
|
||||||
loadouts <- initializeAllLoadouts()
|
result.onComplete {
|
||||||
|
case Success(_) =>
|
||||||
|
sessionActor ! SessionActor.AvatarLoadingSync(step = 0)
|
||||||
|
performAvatarLogin1(avatarId, replyTo)
|
||||||
|
case Failure(e) =>
|
||||||
|
log.error(e)("db failure")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def performAvatarLogin1(avatarId: Long, replyTo: ActorRef[AvatarLoginResponse]): Unit = {
|
||||||
|
import ctx._
|
||||||
|
val result = for {
|
||||||
|
//retrieve avatar data for OCDM packet
|
||||||
implants <- ctx.run(query[persistence.Implant].filter(_.avatarId == lift(avatarId)))
|
implants <- ctx.run(query[persistence.Implant].filter(_.avatarId == lift(avatarId)))
|
||||||
certs <- ctx.run(query[persistence.Certification].filter(_.avatarId == lift(avatarId)))
|
certs <- ctx.run(query[persistence.Certification].filter(_.avatarId == lift(avatarId)))
|
||||||
|
debt <- AvatarActor.loadExperienceDebt(avatarId)
|
||||||
locker <- loadLocker(avatarId)
|
locker <- loadLocker(avatarId)
|
||||||
|
} yield (certs, implants, locker, debt)
|
||||||
|
result.onComplete {
|
||||||
|
case Success((certs, implants, lockerInv, debt)) =>
|
||||||
|
avatarCopy(
|
||||||
|
avatar.copy(
|
||||||
|
certifications =
|
||||||
|
certs.map(cert => Certification.withValue(cert.id)).toSet ++ Config.app.game.baseCertifications,
|
||||||
|
implants = implants.map(implant => Some(Implant(implant.toImplantDefinition))).padTo(3, None),
|
||||||
|
locker = lockerInv
|
||||||
|
)
|
||||||
|
)
|
||||||
|
experienceDebt = debt
|
||||||
|
// if we need to start stamina regeneration
|
||||||
|
tryRestoreStaminaForSession(stamina = 1).collect { _ => defaultStaminaRegen(initialDelay = 0.5f seconds) }
|
||||||
|
sessionActor ! SessionActor.AvatarLoadingSync(step = 1)
|
||||||
|
replyTo ! AvatarLoginResponse(avatar)
|
||||||
|
performAvatarLogin2(avatarId, replyTo)
|
||||||
|
case Failure(e) =>
|
||||||
|
log.error(e)("db failure")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//noinspection ScalaUnusedSymbol
|
||||||
|
def performAvatarLogin2(avatarId: Long, replyTo: ActorRef[AvatarLoginResponse]): Unit = {
|
||||||
|
val result = for {
|
||||||
|
//retrieve avatar data for other packets
|
||||||
|
loadouts <- initializeAllLoadouts()
|
||||||
friends <- loadFriendList(avatarId)
|
friends <- loadFriendList(avatarId)
|
||||||
ignored <- loadIgnoredList(avatarId)
|
ignored <- loadIgnoredList(avatarId)
|
||||||
shortcuts <- loadShortcuts(avatarId)
|
shortcuts <- loadShortcuts(avatarId)
|
||||||
saved <- AvatarActor.loadSavedAvatarData(avatarId)
|
saved <- AvatarActor.loadSavedAvatarData(avatarId)
|
||||||
debt <- AvatarActor.loadExperienceDebt(avatarId)
|
|
||||||
card <- AvatarActor.loadCampaignKdaData(avatarId)
|
card <- AvatarActor.loadCampaignKdaData(avatarId)
|
||||||
} yield (loadouts, implants, certs, locker, friends, ignored, shortcuts, saved, debt, card)
|
} yield (loadouts, friends, ignored, shortcuts, saved, card)
|
||||||
result.onComplete {
|
result.onComplete {
|
||||||
case Success((_loadouts, implants, certs, lockerInv, friendsList, ignoredList, shortcutList, saved, debt, card)) =>
|
case Success((loadoutList, friendsList, ignoredList, shortcutList, saved, card)) =>
|
||||||
//shortcuts must have a hotbar option for each implant
|
|
||||||
// val implantShortcuts = shortcutList.filter {
|
|
||||||
// case Some(e) => e.purpose == 0
|
|
||||||
// case None => false
|
|
||||||
// }
|
|
||||||
// implants.filterNot { implant =>
|
|
||||||
// implantShortcuts.exists {
|
|
||||||
// case Some(a) => a.tile.equals(implant.name)
|
|
||||||
// case None => false
|
|
||||||
// }
|
|
||||||
// }.foreach { c =>
|
|
||||||
// shortcutList.indexWhere { _.isEmpty } match {
|
|
||||||
// case -1 => ()
|
|
||||||
// case index =>
|
|
||||||
// shortcutList.update(index, Some(AvatarShortcut(2, c.name)))
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
avatarCopy(
|
avatarCopy(
|
||||||
avatar.copy(
|
avatar.copy(
|
||||||
loadouts = avatar.loadouts.copy(suit = _loadouts),
|
loadouts = avatar.loadouts.copy(suit = loadoutList),
|
||||||
certifications =
|
|
||||||
certs.map(cert => Certification.withValue(cert.id)).toSet ++ Config.app.game.baseCertifications,
|
|
||||||
implants = implants.map(implant => Some(Implant(implant.toImplantDefinition))).padTo(3, None),
|
|
||||||
shortcuts = shortcutList,
|
shortcuts = shortcutList,
|
||||||
locker = lockerInv,
|
people = MemberLists(friend = friendsList, ignored = ignoredList),
|
||||||
people = MemberLists(
|
|
||||||
friend = friendsList,
|
|
||||||
ignored = ignoredList
|
|
||||||
),
|
|
||||||
cooldowns = Cooldowns(
|
cooldowns = Cooldowns(
|
||||||
purchase = AvatarActor.buildCooldownsFromClob(saved.purchaseCooldowns, Avatar.purchaseCooldowns, log),
|
purchase = AvatarActor.buildCooldownsFromClob(saved.purchaseCooldowns, Avatar.purchaseCooldowns, log),
|
||||||
use = AvatarActor.buildCooldownsFromClob(saved.useCooldowns, Avatar.useCooldowns, log)
|
use = AvatarActor.buildCooldownsFromClob(saved.useCooldowns, Avatar.useCooldowns, log)
|
||||||
|
|
@ -1919,10 +2001,7 @@ class AvatarActor(
|
||||||
scorecard = card
|
scorecard = card
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
// if we need to start stamina regeneration
|
sessionActor ! SessionActor.AvatarLoadingSync(step = 2)
|
||||||
tryRestoreStaminaForSession(stamina = 1).collect { _ => defaultStaminaRegen(initialDelay = 0.5f seconds) }
|
|
||||||
experienceDebt = debt
|
|
||||||
replyTo ! AvatarLoginResponse(avatar)
|
|
||||||
case Failure(e) =>
|
case Failure(e) =>
|
||||||
log.error(e)("db failure")
|
log.error(e)("db failure")
|
||||||
}
|
}
|
||||||
|
|
@ -3046,7 +3125,6 @@ class AvatarActor(
|
||||||
}
|
}
|
||||||
player.HistoryAndContributions()
|
player.HistoryAndContributions()
|
||||||
}
|
}
|
||||||
zone.actor ! ZoneActor.RewardOurSupporters(playerSource, historyTranscript, killStat, exp)
|
|
||||||
val target = killStat.info.targetAfter.asInstanceOf[PlayerSource]
|
val target = killStat.info.targetAfter.asInstanceOf[PlayerSource]
|
||||||
val targetMounted = target.seatedIn.map { case (v: VehicleSource, seat) =>
|
val targetMounted = target.seatedIn.map { case (v: VehicleSource, seat) =>
|
||||||
val definition = v.Definition
|
val definition = v.Definition
|
||||||
|
|
@ -3077,6 +3155,7 @@ class AvatarActor(
|
||||||
}
|
}
|
||||||
if (exp > 0L) {
|
if (exp > 0L) {
|
||||||
setBep(avatar.bep + exp, msg)
|
setBep(avatar.bep + exp, msg)
|
||||||
|
zone.actor ! ZoneActor.RewardOurSupporters(playerSource, historyTranscript, killStat, exp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1282,7 +1282,10 @@ class ChatActor(
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
} else if (contents.startsWith("!progress")) {
|
} else if (contents.startsWith("!progress")) {
|
||||||
if (!session.account.gm && BattleRank.withExperience(session.avatar.bep).value < Config.app.game.promotion.maxBattleRank + 1) {
|
val ourRank = BattleRank.withExperience(session.avatar.bep).value
|
||||||
|
if (!session.account.gm &&
|
||||||
|
(ourRank <= Config.app.game.promotion.broadcastBattleRank ||
|
||||||
|
ourRank > Config.app.game.promotion.resetBattleRank && ourRank < Config.app.game.promotion.maxBattleRank + 1)) {
|
||||||
setBattleRank(dropFirstWord(contents), session, AvatarActor.Progress)
|
setBattleRank(dropFirstWord(contents), session, AvatarActor.Progress)
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1299,7 +1302,7 @@ class ChatActor(
|
||||||
|
|
||||||
private def dropFirstWord(str: String): String = {
|
private def dropFirstWord(str: String): String = {
|
||||||
val noExtraSpaces = str.replaceAll("\\s+", " ").toLowerCase.trim
|
val noExtraSpaces = str.replaceAll("\\s+", " ").toLowerCase.trim
|
||||||
noExtraSpaces.indexOf({ char: String => char.equals(" ") }) match {
|
noExtraSpaces.indexOf(" ") match {
|
||||||
case -1 => ""
|
case -1 => ""
|
||||||
case beforeFirstBlank => noExtraSpaces.drop(beforeFirstBlank + 1)
|
case beforeFirstBlank => noExtraSpaces.drop(beforeFirstBlank + 1)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,8 @@ object SessionActor {
|
||||||
|
|
||||||
final case class UpdateIgnoredPlayers(msg: FriendsResponse) extends Command
|
final case class UpdateIgnoredPlayers(msg: FriendsResponse) extends Command
|
||||||
|
|
||||||
|
final case class AvatarLoadingSync(step: Int) extends Command
|
||||||
|
|
||||||
final case object CharSaved extends Command
|
final case object CharSaved extends Command
|
||||||
|
|
||||||
private[session] case object CharSavedMsg extends Command
|
private[session] case object CharSavedMsg extends Command
|
||||||
|
|
@ -255,6 +257,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
|
||||||
case SessionActor.SetConnectionState(state) =>
|
case SessionActor.SetConnectionState(state) =>
|
||||||
sessionFuncs.connectionState = state
|
sessionFuncs.connectionState = state
|
||||||
|
|
||||||
|
case SessionActor.AvatarLoadingSync(state) =>
|
||||||
|
sessionFuncs.zoning.spawn.handleAvatarLoadingSync(state)
|
||||||
|
|
||||||
/* uncommon messages (utility, or once in a while) */
|
/* uncommon messages (utility, or once in a while) */
|
||||||
case SessionActor.AvatarAwardMessageBundle(pkts, delay) =>
|
case SessionActor.AvatarAwardMessageBundle(pkts, delay) =>
|
||||||
sessionFuncs.zoning.spawn.performAvatarAwardMessageDelivery(pkts, delay)
|
sessionFuncs.zoning.spawn.performAvatarAwardMessageDelivery(pkts, delay)
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@ package net.psforever.actors.session.support
|
||||||
|
|
||||||
import akka.actor.typed.scaladsl.adapter._
|
import akka.actor.typed.scaladsl.adapter._
|
||||||
import akka.actor.{ActorContext, typed}
|
import akka.actor.{ActorContext, typed}
|
||||||
import net.psforever.objects.avatar.SpecialCarry
|
|
||||||
import net.psforever.objects.serverobject.llu.CaptureFlag
|
|
||||||
import net.psforever.packet.game.objectcreate.ConstructorData
|
import net.psforever.packet.game.objectcreate.ConstructorData
|
||||||
import net.psforever.services.Service
|
import net.psforever.services.Service
|
||||||
import net.psforever.objects.zones.exp
|
import net.psforever.objects.zones.exp
|
||||||
|
|
@ -496,25 +494,6 @@ class SessionAvatarHandlers(
|
||||||
sendResponse(ChatMsg(ChatMessageType.UNK_227, "@SVCP_Killed_OnPadOnCreate"))
|
sendResponse(ChatMsg(ChatMessageType.UNK_227, "@SVCP_Killed_OnPadOnCreate"))
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
adversarial.collect {
|
|
||||||
case attacker
|
|
||||||
if player.Carrying.contains(SpecialCarry.CaptureFlag) &&
|
|
||||||
attacker.Faction != player.Faction &&
|
|
||||||
sessionData
|
|
||||||
.specialItemSlotGuid
|
|
||||||
.flatMap { continent.GUID }
|
|
||||||
.collect {
|
|
||||||
case llu: CaptureFlag =>
|
|
||||||
System.currentTimeMillis() - llu.LastCollectionTime > Config.app.game.experience.cep.lluSlayerCreditDuration.toMillis
|
|
||||||
case _ =>
|
|
||||||
false
|
|
||||||
}
|
|
||||||
.contains(true) =>
|
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(
|
|
||||||
attacker.Name,
|
|
||||||
AvatarAction.AwardCep(attacker.CharId, Config.app.game.experience.cep.lluSlayerCredit)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
adversarial.map {_.Name }.orElse { Some(s"a ${reason.getClass.getSimpleName}") }
|
adversarial.map {_.Name }.orElse { Some(s"a ${reason.getClass.getSimpleName}") }
|
||||||
}.getOrElse { s"an unfortunate circumstance (probably ${player.Sex.pronounObject} own fault)" }
|
}.getOrElse { s"an unfortunate circumstance (probably ${player.Sex.pronounObject} own fault)" }
|
||||||
log.info(s"${player.Name} has died, killed by $cause")
|
log.info(s"${player.Name} has died, killed by $cause")
|
||||||
|
|
|
||||||
|
|
@ -1579,6 +1579,24 @@ class SessionData(
|
||||||
case Some(llu: CaptureFlag) => Some((llu, llu.Carrier))
|
case Some(llu: CaptureFlag) => Some((llu, llu.Carrier))
|
||||||
case _ => None
|
case _ => None
|
||||||
}) match {
|
}) match {
|
||||||
|
case Some((llu, Some(carrier: Player)))
|
||||||
|
if carrier.GUID == player.GUID && !player.isAlive =>
|
||||||
|
player.LastDamage.foreach { damage =>
|
||||||
|
damage
|
||||||
|
.interaction
|
||||||
|
.adversarial
|
||||||
|
.map { _.attacker }
|
||||||
|
.collect {
|
||||||
|
case attacker
|
||||||
|
if attacker.Faction != player.Faction &&
|
||||||
|
System.currentTimeMillis() - llu.LastCollectionTime >= Config.app.game.experience.cep.lluSlayerCreditDuration.toMillis =>
|
||||||
|
continent.AvatarEvents ! AvatarServiceMessage(
|
||||||
|
attacker.Name,
|
||||||
|
AvatarAction.AwardCep(attacker.CharId, Config.app.game.experience.cep.lluSlayerCredit)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continent.LocalEvents ! CaptureFlagManager.DropFlag(llu)
|
||||||
case Some((llu, Some(carrier: Player))) if carrier.GUID == player.GUID =>
|
case Some((llu, Some(carrier: Player))) if carrier.GUID == player.GUID =>
|
||||||
continent.LocalEvents ! CaptureFlagManager.DropFlag(llu)
|
continent.LocalEvents ! CaptureFlagManager.DropFlag(llu)
|
||||||
case Some((_, Some(carrier: Player))) =>
|
case Some((_, Some(carrier: Player))) =>
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import net.psforever.objects.inventory.InventoryItem
|
||||||
import net.psforever.objects.serverobject.mount.Seat
|
import net.psforever.objects.serverobject.mount.Seat
|
||||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||||
import net.psforever.objects.sourcing.{PlayerSource, SourceEntry, VehicleSource}
|
import net.psforever.objects.sourcing.{PlayerSource, SourceEntry, VehicleSource}
|
||||||
import net.psforever.objects.vital.{InGameHistory, ReconstructionActivity, SpawningActivity}
|
import net.psforever.objects.vital.{InGameHistory, IncarnationActivity, ReconstructionActivity, SpawningActivity}
|
||||||
import net.psforever.packet.game.{CampaignStatistic, MailMessage, SessionStatistic}
|
import net.psforever.packet.game.{CampaignStatistic, MailMessage, SessionStatistic}
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
|
@ -79,7 +79,7 @@ object ZoningOperations {
|
||||||
"High Command",
|
"High Command",
|
||||||
"Progress versus Promotion",
|
"Progress versus Promotion",
|
||||||
"If you consider yourself as a veteran soldier, despite looking so green, please read this.\n" ++
|
"If you consider yourself as a veteran soldier, despite looking so green, please read this.\n" ++
|
||||||
"You only have this opportunity while you are battle rank 1." ++
|
s"You only have this opportunity while you are less than or equal to battle rank ${Config.app.game.promotion.broadcastBattleRank}." ++
|
||||||
"\n\n" ++
|
"\n\n" ++
|
||||||
"The normal method of rank advancement comes from the battlefield - fighting enemies, helping allies, and capturing facilities. " ++
|
"The normal method of rank advancement comes from the battlefield - fighting enemies, helping allies, and capturing facilities. " ++
|
||||||
"\n\n" ++
|
"\n\n" ++
|
||||||
|
|
@ -91,7 +91,7 @@ object ZoningOperations {
|
||||||
"In addition, you will be ineligible of having your command experience be recognized during this time." ++
|
"In addition, you will be ineligible of having your command experience be recognized during this time." ++
|
||||||
"\n\n" ++
|
"\n\n" ++
|
||||||
"If you wish to continue, set your desired battle rank now - use '!progress' followed by a battle rank index. " ++
|
"If you wish to continue, set your desired battle rank now - use '!progress' followed by a battle rank index. " ++
|
||||||
"If you accept, but it becomes too much of burden, you may ask to revert to battle rank 2 at any time. " ++
|
s"If you accept, but it becomes too much of burden, you may ask to revert to battle rank ${Config.app.game.promotion.resetBattleRank} at any time. " ++
|
||||||
"Your normal sense of progress will be restored."
|
"Your normal sense of progress will be restored."
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -629,22 +629,7 @@ class ZoningOperations(
|
||||||
ServiceManager.serviceManager ! Lookup("propertyOverrideManager")
|
ServiceManager.serviceManager ! Lookup("propertyOverrideManager")
|
||||||
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 112, 0)) // disable festive backpacks
|
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 112, 0)) // disable festive backpacks
|
||||||
sendResponse(ReplicationStreamMessage(5, Some(6), Vector.empty)) //clear squad list
|
sendResponse(ReplicationStreamMessage(5, Some(6), Vector.empty)) //clear squad list
|
||||||
(
|
spawn.initializeFriendsAndIgnoredLists()
|
||||||
FriendsResponse.packetSequence(
|
|
||||||
MemberAction.InitializeFriendList,
|
|
||||||
avatar.people.friend
|
|
||||||
.map { f =>
|
|
||||||
game.Friend(f.name, AvatarActor.onlineIfNotIgnoredEitherWay(avatar, f.name))
|
|
||||||
}
|
|
||||||
) ++
|
|
||||||
//ignored list (no one ever online)
|
|
||||||
FriendsResponse.packetSequence(
|
|
||||||
MemberAction.InitializeIgnoreList,
|
|
||||||
avatar.people.ignored.map { f => game.Friend(f.name) }
|
|
||||||
)
|
|
||||||
).foreach {
|
|
||||||
sendResponse
|
|
||||||
}
|
|
||||||
//the following subscriptions last until character switch/logout
|
//the following subscriptions last until character switch/logout
|
||||||
galaxyService ! Service.Join("galaxy") //for galaxy-wide messages
|
galaxyService ! Service.Join("galaxy") //for galaxy-wide messages
|
||||||
galaxyService ! Service.Join(s"${avatar.faction}") //for hotspots, etc.
|
galaxyService ! Service.Join(s"${avatar.faction}") //for hotspots, etc.
|
||||||
|
|
@ -2797,16 +2782,7 @@ class ZoningOperations(
|
||||||
}
|
}
|
||||||
|
|
||||||
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 82, 0))
|
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 82, 0))
|
||||||
avatar.shortcuts
|
initializeShortcutsAndBank(guid)
|
||||||
.zipWithIndex
|
|
||||||
.collect { case (Some(shortcut), index) =>
|
|
||||||
sendResponse(CreateShortcutMessage(
|
|
||||||
guid,
|
|
||||||
index + 1,
|
|
||||||
Some(AvatarShortcut.convert(shortcut))
|
|
||||||
))
|
|
||||||
}
|
|
||||||
sendResponse(ChangeShortcutBankMessage(guid, 0))
|
|
||||||
//Favorites lists
|
//Favorites lists
|
||||||
avatarActor ! AvatarActor.InitialRefreshLoadouts()
|
avatarActor ! AvatarActor.InitialRefreshLoadouts()
|
||||||
|
|
||||||
|
|
@ -2940,20 +2916,28 @@ class ZoningOperations(
|
||||||
}
|
}
|
||||||
.collect { case Some(thing: PlanetSideGameObject with FactionAffinity) => Some(SourceEntry(thing)) }
|
.collect { case Some(thing: PlanetSideGameObject with FactionAffinity) => Some(SourceEntry(thing)) }
|
||||||
.flatten
|
.flatten
|
||||||
player.LogActivity({
|
val lastEntryOpt = player.History.lastOption
|
||||||
if (player.History.headOption.exists { _.isInstanceOf[SpawningActivity] }) {
|
if (lastEntryOpt.exists { !_.isInstanceOf[IncarnationActivity] }) {
|
||||||
ReconstructionActivity(PlayerSource(player), continent.Number, effortBy)
|
player.LogActivity({
|
||||||
} else {
|
lastEntryOpt match {
|
||||||
SpawningActivity(PlayerSource(player), continent.Number, effortBy)
|
case Some(_) =>
|
||||||
}
|
ReconstructionActivity(PlayerSource(player), continent.Number, effortBy)
|
||||||
})
|
case None =>
|
||||||
|
SpawningActivity(PlayerSource(player), continent.Number, effortBy)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
upstreamMessageCount = 0
|
upstreamMessageCount = 0
|
||||||
setAvatar = true
|
setAvatar = true
|
||||||
if (
|
if (
|
||||||
BattleRank.withExperience(tplayer.avatar.bep).value == 1 &&
|
!account.gm && /* gm's are excluded */
|
||||||
Config.app.game.promotion.active &&
|
Config.app.game.promotion.active && /* play versus progress system must be active */
|
||||||
!account.gm) {
|
BattleRank.withExperience(tplayer.avatar.bep).value <= Config.app.game.promotion.broadcastBattleRank && /* must be below a certain battle rank */
|
||||||
|
avatar.scorecard.Lives.isEmpty && /* first life after login */
|
||||||
|
avatar.scorecard.CurrentLife.prior.isEmpty && /* no revives */
|
||||||
|
player.History.size == 1 /* did nothing but come into existence */
|
||||||
|
) {
|
||||||
ZoningOperations.reportProgressionSystem(context.self)
|
ZoningOperations.reportProgressionSystem(context.self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2968,6 +2952,59 @@ class ZoningOperations(
|
||||||
HandleSetCurrentAvatar(tplayer)
|
HandleSetCurrentAvatar(tplayer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Respond to feedback of how the avatar's data is being handled
|
||||||
|
* in a way that properly reflects the state of the server at the moment.
|
||||||
|
* @param state indicator for the progress of the avatar
|
||||||
|
*/
|
||||||
|
def handleAvatarLoadingSync(state: Int): Unit = {
|
||||||
|
if (state == 2 && zoneLoaded.contains(true)) {
|
||||||
|
initializeFriendsAndIgnoredLists()
|
||||||
|
initializeShortcutsAndBank(player.GUID)
|
||||||
|
avatarActor ! AvatarActor.RefreshPurchaseTimes()
|
||||||
|
loginAvatarStatisticsFields()
|
||||||
|
avatarActor ! AvatarActor.InitialRefreshLoadouts()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up and dispatch a list of `FriendsResponse` packets related to both formal friends and ignored players.
|
||||||
|
*/
|
||||||
|
def initializeFriendsAndIgnoredLists(): Unit = {
|
||||||
|
(
|
||||||
|
FriendsResponse.packetSequence(
|
||||||
|
MemberAction.InitializeFriendList,
|
||||||
|
avatar.people.friend
|
||||||
|
.map { f =>
|
||||||
|
game.Friend(f.name, AvatarActor.onlineIfNotIgnoredEitherWay(avatar, f.name))
|
||||||
|
}
|
||||||
|
) ++
|
||||||
|
//ignored list (no one ever online)
|
||||||
|
FriendsResponse.packetSequence(
|
||||||
|
MemberAction.InitializeIgnoreList,
|
||||||
|
avatar.people.ignored.map { f => game.Friend(f.name) }
|
||||||
|
)
|
||||||
|
).foreach {
|
||||||
|
sendResponse
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up and dispatch a list of `CreateShortcutMessage` packets and a single `ChangeShortcutBankMessage` packet.
|
||||||
|
*/
|
||||||
|
def initializeShortcutsAndBank(guid: PlanetSideGUID): Unit = {
|
||||||
|
avatar.shortcuts
|
||||||
|
.zipWithIndex
|
||||||
|
.collect { case (Some(shortcut), index) =>
|
||||||
|
sendResponse(CreateShortcutMessage(
|
||||||
|
guid,
|
||||||
|
index + 1,
|
||||||
|
Some(AvatarShortcut.convert(shortcut))
|
||||||
|
))
|
||||||
|
}
|
||||||
|
sendResponse(ChangeShortcutBankMessage(guid, 0))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw the icon for this deployable object.<br>
|
* Draw the icon for this deployable object.<br>
|
||||||
* <br>
|
* <br>
|
||||||
|
|
@ -3247,7 +3284,7 @@ class ZoningOperations(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accessible method to switch population of the Character Info window's statistics page
|
* Accessible method to switch population of the Character Info window's statistics page
|
||||||
* from whatever it currently js to after each respawn.
|
* from whatever it currently is to after each respawn.
|
||||||
* At the time of "login", only campaign (total, historical) deaths are reported for convenience.
|
* At the time of "login", only campaign (total, historical) deaths are reported for convenience.
|
||||||
* At the time of "respawn", all fields - campaign and session - should be reported if applicable.
|
* At the time of "respawn", all fields - campaign and session - should be reported if applicable.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -163,6 +163,7 @@ object ScoreCard {
|
||||||
case PlanetSideEmpire.VS => fields.copy(vs_s = fields.vs_s + 1)
|
case PlanetSideEmpire.VS => fields.copy(vs_s = fields.vs_s + 1)
|
||||||
case PlanetSideEmpire.NEUTRAL => fields.copy(ps_s = fields.ps_s + 1)
|
case PlanetSideEmpire.NEUTRAL => fields.copy(ps_s = fields.ps_s + 1)
|
||||||
}
|
}
|
||||||
|
statisticMap.put(objectId, outEntry)
|
||||||
outEntry
|
outEntry
|
||||||
case _ =>
|
case _ =>
|
||||||
val out = Statistic(0, 0, 0, 0, 0, 0, 0, 0)
|
val out = Statistic(0, 0, 0, 0, 0, 0, 0, 0)
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ class IFFLockControl(lock: IFFLock)
|
||||||
.orElse {
|
.orElse {
|
||||||
case CommonMessages.Use(player, Some(item: SimpleItem))
|
case CommonMessages.Use(player, Some(item: SimpleItem))
|
||||||
if item.Definition == GlobalDefinitions.remote_electronics_kit =>
|
if item.Definition == GlobalDefinitions.remote_electronics_kit =>
|
||||||
if (lock.Faction != player.Faction && lock.HackedBy.isEmpty) {
|
if (lock.Faction != player.Faction) {
|
||||||
sender() ! CommonMessages.Progress(
|
sender() ! CommonMessages.Progress(
|
||||||
GenericHackables.GetHackSpeed(player, lock),
|
GenericHackables.GetHackSpeed(player, lock),
|
||||||
GenericHackables.FinishHacking(lock, player, 1114636288L),
|
GenericHackables.FinishHacking(lock, player, 1114636288L),
|
||||||
|
|
@ -42,8 +42,7 @@ class IFFLockControl(lock: IFFLock)
|
||||||
} else {
|
} else {
|
||||||
val log = org.log4s.getLogger
|
val log = org.log4s.getLogger
|
||||||
log.warn(s"IFF lock is being hacked by ${player.Faction}, but don't know how to handle this state:")
|
log.warn(s"IFF lock is being hacked by ${player.Faction}, but don't know how to handle this state:")
|
||||||
log.warn(s"Lock - Faction=${lock.Faction}, HackedBy=${lock.HackedBy}")
|
log.warn(s"Lock - Faction=${lock.Faction}, HackedBy=${lock.HackedBy.map{_.player}}")
|
||||||
log.warn(s"Player - Faction=${player.Faction}")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case IFFLock.DoorOpenRequest(target, door, replyTo) =>
|
case IFFLock.DoorOpenRequest(target, door, replyTo) =>
|
||||||
|
|
|
||||||
|
|
@ -192,12 +192,11 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
|
||||||
//experience is reported as normal
|
//experience is reported as normal
|
||||||
val deposit: Long =
|
val deposit: Long =
|
||||||
(Config.app.game.experience.sep.ntuSiloDepositReward.toFloat *
|
(Config.app.game.experience.sep.ntuSiloDepositReward.toFloat *
|
||||||
math.floor(amount).toFloat /
|
amount / (resourceSilo.MaxNtuCapacitor * resourceSilo.Definition.ChargeTime.toSeconds.toFloat)
|
||||||
math.floor(resourceSilo.MaxNtuCapacitor / resourceSilo.Definition.ChargeTime.toMillis.toFloat)
|
|
||||||
).toLong
|
).toLong
|
||||||
vehicle.Zone.AvatarEvents ! AvatarServiceMessage(
|
vehicle.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
owner.name,
|
owner.name,
|
||||||
AvatarAction.AwardBep(0, deposit, ExperienceType.Normal)
|
AvatarAction.AwardBep(owner.charId, deposit, ExperienceType.Normal)
|
||||||
)
|
)
|
||||||
zones.exp.ToDatabase.reportNtuActivity(owner.charId, resourceSilo.Zone.Number, resourceSilo.Owner.GUID.guid, deposit)
|
zones.exp.ToDatabase.reportNtuActivity(owner.charId, resourceSilo.Zone.Number, resourceSilo.Owner.GUID.guid, deposit)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,7 @@ trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
|
||||||
ActivatePanelsForChargingEvent(ChargeTransferObject)
|
ActivatePanelsForChargingEvent(ChargeTransferObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection ScalaUnusedSymbol
|
||||||
def WithdrawAndTransmit(vehicle: Vehicle, maxRequested: Float): Any = {
|
def WithdrawAndTransmit(vehicle: Vehicle, maxRequested: Float): Any = {
|
||||||
val chargeable = ChargeTransferObject
|
val chargeable = ChargeTransferObject
|
||||||
var chargeToDeposit = Math.min(Math.min(chargeable.NtuCapacitor, 100), maxRequested)
|
var chargeToDeposit = Math.min(Math.min(chargeable.NtuCapacitor, 100), maxRequested)
|
||||||
|
|
@ -188,7 +189,7 @@ trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
|
||||||
transferTarget match {
|
transferTarget match {
|
||||||
case Some(silo: ResourceSilo) =>
|
case Some(silo: ResourceSilo) =>
|
||||||
scala.math.min(
|
scala.math.min(
|
||||||
scala.math.min(silo.MaxNtuCapacitor / silo.Definition.ChargeTime.toMillis.toFloat, chargeable.NtuCapacitor),
|
scala.math.min(silo.MaxNtuCapacitor / silo.Definition.ChargeTime.toSeconds.toFloat, chargeable.NtuCapacitor),
|
||||||
max
|
max
|
||||||
)
|
)
|
||||||
case _ =>
|
case _ =>
|
||||||
|
|
|
||||||
|
|
@ -50,14 +50,16 @@ trait SupportActivityCausedByAnother {
|
||||||
def amount: Int
|
def amount: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait IncarnationActivity extends GeneralActivity
|
||||||
|
|
||||||
final case class SpawningActivity(src: SourceEntry, zoneNumber: Int, unit: Option[SourceEntry])
|
final case class SpawningActivity(src: SourceEntry, zoneNumber: Int, unit: Option[SourceEntry])
|
||||||
extends GeneralActivity
|
extends IncarnationActivity
|
||||||
|
|
||||||
final case class ReconstructionActivity(src: SourceEntry, zoneNumber: Int, unit: Option[SourceEntry])
|
final case class ReconstructionActivity(src: SourceEntry, zoneNumber: Int, unit: Option[SourceEntry])
|
||||||
extends GeneralActivity
|
extends IncarnationActivity
|
||||||
|
|
||||||
final case class RevivingActivity(target: SourceEntry, user: PlayerSource, amount: Int, equipment: EquipmentDefinition)
|
final case class RevivingActivity(target: SourceEntry, user: PlayerSource, amount: Int, equipment: EquipmentDefinition)
|
||||||
extends GeneralActivity with SupportActivityCausedByAnother
|
extends IncarnationActivity with SupportActivityCausedByAnother
|
||||||
|
|
||||||
final case class ShieldCharge(amount: Int, cause: Option[SourceEntry])
|
final case class ShieldCharge(amount: Int, cause: Option[SourceEntry])
|
||||||
extends GeneralActivity
|
extends GeneralActivity
|
||||||
|
|
|
||||||
|
|
@ -315,8 +315,10 @@ object KillAssists {
|
||||||
history: Iterable[InGameActivity]
|
history: Iterable[InGameActivity]
|
||||||
): Long = {
|
): Long = {
|
||||||
//base value (the kill experience before modifiers)
|
//base value (the kill experience before modifiers)
|
||||||
val base = Support.baseExperience(victim, history)
|
lazy val base = Support.baseExperience(victim, history)
|
||||||
if (base > 1) {
|
if (killer.Faction == victim.Faction || killer.unique == victim.unique) {
|
||||||
|
0L
|
||||||
|
} else if (base > 1) {
|
||||||
//include battle rank disparity modifier
|
//include battle rank disparity modifier
|
||||||
val battleRankDisparity = {
|
val battleRankDisparity = {
|
||||||
import net.psforever.objects.avatar.BattleRank
|
import net.psforever.objects.avatar.BattleRank
|
||||||
|
|
|
||||||
|
|
@ -289,9 +289,11 @@ case class CommandExperiencePoints(
|
||||||
)
|
)
|
||||||
|
|
||||||
case class PromotionSystem(
|
case class PromotionSystem(
|
||||||
active: Boolean,
|
active: Boolean,
|
||||||
maxBattleRank: Int,
|
broadcastBattleRank: Int,
|
||||||
battleExperiencePointsModifier: Float,
|
resetBattleRank: Int,
|
||||||
supportExperiencePointsModifier: Float,
|
maxBattleRank: Int,
|
||||||
captureExperiencePointsModifier: Float
|
battleExperiencePointsModifier: Float,
|
||||||
|
supportExperiencePointsModifier: Float,
|
||||||
|
captureExperiencePointsModifier: Float
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue