fix handling of empty and invalid item clobs

This commit is contained in:
Jakob Gillich 2022-05-17 20:50:08 +02:00
parent 0d4a5ad40e
commit 60caf2c76b

View file

@ -193,10 +193,10 @@ object AvatarActor {
def changeRibbons(ribbons: RibbonBars, ribbon: MeritCommendation.Value, bar: RibbonBarSlot.Value): RibbonBars = { def changeRibbons(ribbons: RibbonBars, ribbon: MeritCommendation.Value, bar: RibbonBarSlot.Value): RibbonBars = {
bar match { bar match {
case RibbonBarSlot.Top => ribbons.copy(upper = ribbon) case RibbonBarSlot.Top => ribbons.copy(upper = ribbon)
case RibbonBarSlot.Middle => ribbons.copy(middle = ribbon) case RibbonBarSlot.Middle => ribbons.copy(middle = ribbon)
case RibbonBarSlot.Bottom => ribbons.copy(lower = ribbon) case RibbonBarSlot.Bottom => ribbons.copy(lower = ribbon)
case RibbonBarSlot.TermOfService => ribbons.copy(tos = ribbon) case RibbonBarSlot.TermOfService => ribbons.copy(tos = ribbon)
} }
} }
} }
@ -380,14 +380,16 @@ class AvatarActor(
result.onComplete { result.onComplete {
case Success((loadouts, implants, certs, locker)) => case Success((loadouts, implants, certs, locker)) =>
avatarCopy(avatar.copy( avatarCopy(
loadouts = loadouts, avatar.copy(
// make sure we always have the base certifications loadouts = loadouts,
certifications = // make sure we always have the base certifications
certs.map(cert => Certification.withValue(cert.id)).toSet ++ Config.app.game.baseCertifications, certifications =
implants = implants.map(implant => Some(Implant(implant.toImplantDefinition))).padTo(3, None), certs.map(cert => Certification.withValue(cert.id)).toSet ++ Config.app.game.baseCertifications,
locker = locker implants = implants.map(implant => Some(Implant(implant.toImplantDefinition))).padTo(3, None),
)) locker = locker
)
)
// if we need to start stamina regeneration // if we need to start stamina regeneration
tryRestoreStaminaForSession(stamina = 1) match { tryRestoreStaminaForSession(stamina = 1) match {
case Some(_) => case Some(_) =>
@ -524,7 +526,8 @@ class AvatarActor(
if (certification == Certification.ReinforcedExoSuit) player.ExoSuit == ExoSuitType.Reinforced if (certification == Certification.ReinforcedExoSuit) player.ExoSuit == ExoSuitType.Reinforced
else if (certification == Certification.InfiltrationSuit) player.ExoSuit == ExoSuitType.Infiltration else if (certification == Certification.InfiltrationSuit) player.ExoSuit == ExoSuitType.Infiltration
else if (player.ExoSuit == ExoSuitType.MAX) { else if (player.ExoSuit == ExoSuitType.MAX) {
lazy val subtype = InfantryLoadout.DetermineSubtypeA(ExoSuitType.MAX, player.Slot(slot = 0).Equipment) lazy val subtype =
InfantryLoadout.DetermineSubtypeA(ExoSuitType.MAX, player.Slot(slot = 0).Equipment)
if (certification == Certification.UniMAX) true if (certification == Certification.UniMAX) true
else if (certification == Certification.AAMAX) subtype == 1 else if (certification == Certification.AAMAX) subtype == 1
else if (certification == Certification.AIMAX) subtype == 2 else if (certification == Certification.AIMAX) subtype == 2
@ -598,7 +601,7 @@ class AvatarActor(
// TODO there used to be a terminal check here, do we really need it? // TODO there used to be a terminal check here, do we really need it?
val index = avatar.implants.zipWithIndex.collectFirst { val index = avatar.implants.zipWithIndex.collectFirst {
case (Some(implant), _index) if implant.definition.implantType == definition.implantType => _index case (Some(implant), _index) if implant.definition.implantType == definition.implantType => _index
case (None, _index) if _index < avatar.br.implantSlots => _index case (None, _index) if _index < avatar.br.implantSlots => _index
} }
index match { index match {
case Some(_index) => case Some(_index) =>
@ -668,7 +671,7 @@ class AvatarActor(
Behaviors.same Behaviors.same
case SaveLoadout(player, loadoutType, label, number) => case SaveLoadout(player, loadoutType, label, number) =>
log.info(s"${player.Name} wishes to save a favorite $loadoutType loadout as #${number+1}") log.info(s"${player.Name} wishes to save a favorite $loadoutType loadout as #${number + 1}")
val name = label.getOrElse(s"missing_loadout_${number + 1}") val name = label.getOrElse(s"missing_loadout_${number + 1}")
val (lineNo, result): (Int, Future[Loadout]) = loadoutType match { val (lineNo, result): (Int, Future[Loadout]) = loadoutType match {
case LoadoutType.Infantry => case LoadoutType.Infantry =>
@ -692,8 +695,7 @@ class AvatarActor(
( (
number + 15, number + 15,
player.Zone.GUID(avatar.vehicle) match { player.Zone.GUID(avatar.vehicle) match {
case Some(vehicle: Vehicle) case Some(vehicle: Vehicle) if GlobalDefinitions.isBattleFrameVehicle(vehicle.Definition) =>
if GlobalDefinitions.isBattleFrameVehicle(vehicle.Definition) =>
storeVehicleLoadout(player, name, number + 5, vehicle) storeVehicleLoadout(player, name, number + 5, vehicle)
case _ => case _ =>
throwLoadoutFailure(s"no owned battleframe found for ${player.Name}") throwLoadoutFailure(s"no owned battleframe found for ${player.Name}")
@ -710,7 +712,7 @@ class AvatarActor(
Behaviors.same Behaviors.same
case DeleteLoadout(player, loadoutType, number) => case DeleteLoadout(player, loadoutType, number) =>
log.info(s"${player.Name} wishes to delete a favorite $loadoutType loadout - #${number+1}") log.info(s"${player.Name} wishes to delete a favorite $loadoutType loadout - #${number + 1}")
import ctx._ import ctx._
val (lineNo, result) = loadoutType match { val (lineNo, result) = loadoutType match {
case LoadoutType.Infantry if avatar.loadouts(number).nonEmpty => case LoadoutType.Infantry if avatar.loadouts(number).nonEmpty =>
@ -814,9 +816,11 @@ class AvatarActor(
} else if (implant.definition.implantType.disabledFor.contains(session.get.player.ExoSuit)) { } else if (implant.definition.implantType.disabledFor.contains(session.get.player.ExoSuit)) {
// TODO can this really happen? can we prevent it? // TODO can this really happen? can we prevent it?
} else { } else {
avatarCopy(avatar.copy( avatarCopy(
implants = avatar.implants.updated(slot, Some(implant.copy(active = true))) avatar.copy(
)) implants = avatar.implants.updated(slot, Some(implant.copy(active = true)))
)
)
sessionActor ! SessionActor.SendResponse( sessionActor ! SessionActor.SendResponse(
AvatarImplantMessage(session.get.player.GUID, ImplantAction.Activation, slot, 1) AvatarImplantMessage(session.get.player.GUID, ImplantAction.Activation, slot, 1)
) )
@ -835,32 +839,34 @@ class AvatarActor(
if (interval.toMillis > 0) { if (interval.toMillis > 0) {
implantTimers(slot) = context.system.scheduler.scheduleWithFixedDelay(interval, interval)(() => { implantTimers(slot) = context.system.scheduler.scheduleWithFixedDelay(interval, interval)(() => {
val player = session.get.player val player = session.get.player
if (implantType match { if (
case ImplantType.AdvancedRegen => implantType match {
//for every 1hp: 2sp (running), 1.5sp (standing), 1sp (crouched) case ImplantType.AdvancedRegen =>
// to simulate '1.5sp (standing)', find if 0.0...1.0 * 100 is an even number //for every 1hp: 2sp (running), 1.5sp (standing), 1sp (crouched)
val cost = implant.definition.StaminaCost - // to simulate '1.5sp (standing)', find if 0.0...1.0 * 100 is an even number
(if (player.Crouching || (!player.isMoving && (math.random() * 100) % 2 == 1)) 1 else 0) val cost = implant.definition.StaminaCost -
val aliveAndWounded = player.isAlive && player.Health < player.MaxHealth (if (player.Crouching || (!player.isMoving && (math.random() * 100) % 2 == 1)) 1 else 0)
if (aliveAndWounded && consumeThisMuchStamina(cost)) { val aliveAndWounded = player.isAlive && player.Health < player.MaxHealth
//heal if (aliveAndWounded && consumeThisMuchStamina(cost)) {
val originalHealth = player.Health //heal
val zone = player.Zone val originalHealth = player.Health
val events = zone.AvatarEvents val zone = player.Zone
val guid = player.GUID val events = zone.AvatarEvents
val newHealth = player.Health = originalHealth + 1 val guid = player.GUID
player.History(HealFromImplant(PlayerSource(player), 1, implantType)) val newHealth = player.Health = originalHealth + 1
events ! AvatarServiceMessage( player.History(HealFromImplant(PlayerSource(player), 1, implantType))
zone.id, events ! AvatarServiceMessage(
AvatarAction.PlanetsideAttributeToAll(guid, 0, newHealth) zone.id,
) AvatarAction.PlanetsideAttributeToAll(guid, 0, newHealth)
false )
} else { false
!aliveAndWounded } else {
} !aliveAndWounded
case _ => }
!player.isAlive || !consumeThisMuchStamina(implant.definition.StaminaCost) case _ =>
}) { !player.isAlive || !consumeThisMuchStamina(implant.definition.StaminaCost)
}
) {
context.self ! DeactivateImplant(implantType) context.self ! DeactivateImplant(implantType)
} }
}) })
@ -1024,7 +1030,7 @@ class AvatarActor(
} }
replaceAvatar(avatar.copy(ribbonBars = AvatarActor.changeRibbons(useRibbonBars, ribbon, bar))) replaceAvatar(avatar.copy(ribbonBars = AvatarActor.changeRibbons(useRibbonBars, ribbon, bar)))
val player = session.get.player val player = session.get.player
val zone = player.Zone val zone = player.Zone
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! AvatarServiceMessage(
zone.id, zone.id,
AvatarAction.SendResponse(Service.defaultPlayerGUID, DisplayedAwardMessage(player.GUID, ribbon, bar)) AvatarAction.SendResponse(Service.defaultPlayerGUID, DisplayedAwardMessage(player.GUID, ribbon, bar))
@ -1103,11 +1109,11 @@ class AvatarActor(
def actuallyRestoreStamina(stamina: Int, session: Session): Unit = { def actuallyRestoreStamina(stamina: Int, session: Session): Unit = {
val originalStamina = avatar.stamina val originalStamina = avatar.stamina
val maxStamina = avatar.maxStamina val maxStamina = avatar.maxStamina
val totalStamina = math.min(maxStamina, originalStamina + stamina) val totalStamina = math.min(maxStamina, originalStamina + stamina)
if (originalStamina < totalStamina) { if (originalStamina < totalStamina) {
val originalFatigued = avatar.fatigued val originalFatigued = avatar.fatigued
val isFatigued = totalStamina < 20 val isFatigued = totalStamina < 20
avatar = avatar.copy(stamina = totalStamina, fatigued = isFatigued) avatar = avatar.copy(stamina = totalStamina, fatigued = isFatigued)
if (totalStamina == maxStamina) { if (totalStamina == maxStamina) {
staminaRegenTimer.cancel() staminaRegenTimer.cancel()
@ -1150,9 +1156,9 @@ class AvatarActor(
true true
} else { } else {
val resultingStamina = avatar.stamina - stamina val resultingStamina = avatar.stamina - stamina
val totalStamina = math.max(0, resultingStamina) val totalStamina = math.max(0, resultingStamina)
val alreadyFatigued = avatar.fatigued val alreadyFatigued = avatar.fatigued
val becomeFatigued = !alreadyFatigued && totalStamina == 0 val becomeFatigued = !alreadyFatigued && totalStamina == 0
avatarCopy(avatar.copy(stamina = totalStamina, fatigued = alreadyFatigued || becomeFatigued)) avatarCopy(avatar.copy(stamina = totalStamina, fatigued = alreadyFatigued || becomeFatigued))
startIfStoppedStaminaRegen(initialDelay = 0.5f seconds) startIfStoppedStaminaRegen(initialDelay = 0.5f seconds)
val player = session.get.player val player = session.get.player
@ -1253,9 +1259,11 @@ class AvatarActor(
AvatarImplantMessage(session.get.player.GUID, ImplantAction.Initialization, index, 0) AvatarImplantMessage(session.get.player.GUID, ImplantAction.Initialization, index, 0)
) )
) )
avatarCopy(avatar.copy( avatarCopy(
implants = avatar.implants.updated(index, Some(imp.copy(initialized = false, active = false))) avatar.copy(
)) implants = avatar.implants.updated(index, Some(imp.copy(initialized = false, active = false)))
)
)
//restart initialization process //restart initialization process
implantTimers.get(index).foreach(_.cancel()) implantTimers.get(index).foreach(_.cancel())
implantTimers(index) = context.scheduleOnce( implantTimers(index) = context.scheduleOnce(
@ -1277,9 +1285,11 @@ class AvatarActor(
} match { } match {
case Some((implant, slot)) => case Some((implant, slot)) =>
implantTimers.get(slot).foreach(_.cancel()) implantTimers.get(slot).foreach(_.cancel())
avatarCopy(avatar.copy( avatarCopy(
implants = avatar.implants.updated(slot, Some(implant.copy(active = false))) avatar.copy(
)) implants = avatar.implants.updated(slot, Some(implant.copy(active = false)))
)
)
// Deactivation sound / effect // Deactivation sound / effect
session.get.zone.AvatarEvents ! AvatarServiceMessage( session.get.zone.AvatarEvents ! AvatarServiceMessage(
session.get.zone.id, session.get.zone.id,
@ -1434,8 +1444,7 @@ class AvatarActor(
val items: String = { val items: String = {
val clobber: StringBuilder = new StringBuilder() val clobber: StringBuilder = new StringBuilder()
//encode holsters //encode holsters
vehicle vehicle.Weapons
.Weapons
.collect { .collect {
case (index, slot: EquipmentSlot) if slot.Equipment.nonEmpty => case (index, slot: EquipmentSlot) if slot.Equipment.nonEmpty =>
clobber.append(encodeLoadoutClobFragment(slot.Equipment.get, index)) clobber.append(encodeLoadoutClobFragment(slot.Equipment.get, index))
@ -1477,8 +1486,8 @@ class AvatarActor(
def storeNewLocker(): Unit = { def storeNewLocker(): Unit = {
if (_avatar.nonEmpty) { if (_avatar.nonEmpty) {
val items : String = { val items: String = {
val clobber : StringBuilder = new StringBuilder() val clobber: StringBuilder = new StringBuilder()
avatar.locker.Inventory.Items.foreach { avatar.locker.Inventory.Items.foreach {
case InventoryItem(obj, index) => case InventoryItem(obj, index) =>
clobber.append(encodeLoadoutClobFragment(obj, index)) clobber.append(encodeLoadoutClobFragment(obj, index))
@ -1488,18 +1497,20 @@ class AvatarActor(
if (items.nonEmpty) { if (items.nonEmpty) {
saveLockerFunc = storeLocker saveLockerFunc = storeLocker
import ctx._ import ctx._
ctx.run( ctx
query[persistence.Locker].insert( .run(
_.avatarId -> lift(avatar.id), query[persistence.Locker].insert(
_.items -> lift(items) _.avatarId -> lift(avatar.id),
_.items -> lift(items)
)
) )
).onComplete { .onComplete {
case Success(_) => case Success(_) =>
log.debug(s"saving locker contents belonging to ${avatar.name}") log.debug(s"saving locker contents belonging to ${avatar.name}")
case Failure(e) => case Failure(e) =>
saveLockerFunc = doNotStoreLocker saveLockerFunc = doNotStoreLocker
log.error(e)("db failure") log.error(e)("db failure")
} }
} }
} }
} }
@ -1510,8 +1521,8 @@ class AvatarActor(
def storeLocker(): Unit = { def storeLocker(): Unit = {
import ctx._ import ctx._
val items : String = { val items: String = {
val clobber : StringBuilder = new StringBuilder() val clobber: StringBuilder = new StringBuilder()
avatar.locker.Inventory.Items.foreach { avatar.locker.Inventory.Items.foreach {
case InventoryItem(obj, index) => case InventoryItem(obj, index) =>
clobber.append(encodeLoadoutClobFragment(obj, index)) clobber.append(encodeLoadoutClobFragment(obj, index))
@ -1543,11 +1554,11 @@ class AvatarActor(
for { for {
infantry <- loadLoadouts().andThen { infantry <- loadLoadouts().andThen {
case out @ Success(_) => out case out @ Success(_) => out
case Failure(_) => Future(Array.fill[Option[Loadout]](10)(None).toSeq) case Failure(_) => Future(Array.fill[Option[Loadout]](10)(None).toSeq)
} }
vehicles <- loadVehicleLoadouts().andThen { vehicles <- loadVehicleLoadouts().andThen {
case out @ Success(_) => out case out @ Success(_) => out
case Failure(_) => Future(Array.fill[Option[Loadout]](10)(None).toSeq) case Failure(_) => Future(Array.fill[Option[Loadout]](10)(None).toSeq)
} }
} yield infantry ++ vehicles } yield infantry ++ vehicles
} }
@ -1580,7 +1591,7 @@ class AvatarActor(
.map { loadouts => .map { loadouts =>
loadouts.map { loadout => loadouts.map { loadout =>
val definition = DefinitionUtil.idToDefinition(loadout.vehicle).asInstanceOf[VehicleDefinition] val definition = DefinitionUtil.idToDefinition(loadout.vehicle).asInstanceOf[VehicleDefinition]
val toy = new Vehicle(definition) val toy = new Vehicle(definition)
buildContainedEquipmentFromClob(toy, loadout.items) buildContainedEquipmentFromClob(toy, loadout.items)
val result = (loadout.loadoutNumber, Loadout.Create(toy, loadout.name)) val result = (loadout.loadoutNumber, Loadout.Create(toy, loadout.name))
@ -1595,44 +1606,46 @@ class AvatarActor(
} }
def refreshLoadouts(loadouts: Iterable[(Option[Loadout], Int)]): Unit = { def refreshLoadouts(loadouts: Iterable[(Option[Loadout], Int)]): Unit = {
loadouts.map { loadouts
case (Some(loadout: InfantryLoadout), index) => .map {
FavoritesMessage.Infantry( case (Some(loadout: InfantryLoadout), index) =>
session.get.player.GUID, FavoritesMessage.Infantry(
index, session.get.player.GUID,
loadout.label, index,
InfantryLoadout.DetermineSubtypeB(loadout.exosuit, loadout.subtype) loadout.label,
) InfantryLoadout.DetermineSubtypeB(loadout.exosuit, loadout.subtype)
case (Some(loadout: VehicleLoadout), index) )
if GlobalDefinitions.isBattleFrameVehicle(loadout.vehicle_definition) => case (Some(loadout: VehicleLoadout), index)
FavoritesMessage.Battleframe( if GlobalDefinitions.isBattleFrameVehicle(loadout.vehicle_definition) =>
session.get.player.GUID, FavoritesMessage.Battleframe(
index - 15, session.get.player.GUID,
loadout.label, index - 15,
VehicleLoadout.DetermineBattleframeSubtype(loadout.vehicle_definition) loadout.label,
) VehicleLoadout.DetermineBattleframeSubtype(loadout.vehicle_definition)
case (Some(loadout: VehicleLoadout), index) => )
FavoritesMessage.Vehicle( case (Some(loadout: VehicleLoadout), index) =>
session.get.player.GUID, FavoritesMessage.Vehicle(
index - 10, session.get.player.GUID,
loadout.label index - 10,
) loadout.label
case (_, index) => )
val (mtype, lineNo) = if (index > 14) { case (_, index) =>
(LoadoutType.Battleframe, index - 15) val (mtype, lineNo) = if (index > 14) {
} else if (index < 10) { (LoadoutType.Battleframe, index - 15)
(LoadoutType.Infantry, index) } else if (index < 10) {
} else { (LoadoutType.Infantry, index)
(LoadoutType.Vehicle, index - 10) } else {
} (LoadoutType.Vehicle, index - 10)
FavoritesMessage( }
mtype, FavoritesMessage(
session.get.player.GUID, mtype,
lineNo, session.get.player.GUID,
"", lineNo,
0 "",
) 0
}.foreach { sessionActor ! SessionActor.SendResponse(_) } )
}
.foreach { sessionActor ! SessionActor.SendResponse(_) }
} }
def refreshLoadout(line: Int): Unit = { def refreshLoadout(line: Int): Unit = {
@ -1646,8 +1659,7 @@ class AvatarActor(
InfantryLoadout.DetermineSubtypeB(loadout.exosuit, loadout.subtype) InfantryLoadout.DetermineSubtypeB(loadout.exosuit, loadout.subtype)
) )
) )
case Some(Some(loadout: VehicleLoadout)) case Some(Some(loadout: VehicleLoadout)) if GlobalDefinitions.isBattleFrameVehicle(loadout.vehicle_definition) =>
if GlobalDefinitions.isBattleFrameVehicle(loadout.vehicle_definition) =>
sessionActor ! SessionActor.SendResponse( sessionActor ! SessionActor.SendResponse(
FavoritesMessage.Battleframe( FavoritesMessage.Battleframe(
session.get.player.GUID, session.get.player.GUID,
@ -1698,47 +1710,49 @@ class AvatarActor(
} }
def buildContainedEquipmentFromClob(container: Container, clob: String): Unit = { def buildContainedEquipmentFromClob(container: Container, clob: String): Unit = {
clob.split("/").foreach { clob.split("/").filter(_.trim.nonEmpty).foreach { value =>
value => val (objectType, objectIndex, objectId, toolAmmo) = value.split(",") match {
val (objectType, objectIndex, objectId, toolAmmo) = value.split(",") match { case Array(a, b: String, c: String) => (a, b.toInt, c.toInt, None)
case Array(a, b: String, c: String) => (a, b.toInt, c.toInt, None) case Array(a, b: String, c: String, d) => (a, b.toInt, c.toInt, Some(d))
case Array(a, b: String, c: String, d) => (a, b.toInt, c.toInt, Some(d)) case _ =>
} log.warn(s"ignoring invalid item string: '$value'")
return
}
objectType match { objectType match {
case "Tool" => case "Tool" =>
container.Slot(objectIndex).Equipment = container.Slot(objectIndex).Equipment =
Tool(DefinitionUtil.idToDefinition(objectId).asInstanceOf[ToolDefinition]) Tool(DefinitionUtil.idToDefinition(objectId).asInstanceOf[ToolDefinition])
case "AmmoBox" => case "AmmoBox" =>
container.Slot(objectIndex).Equipment = container.Slot(objectIndex).Equipment =
AmmoBox(DefinitionUtil.idToDefinition(objectId).asInstanceOf[AmmoBoxDefinition]) AmmoBox(DefinitionUtil.idToDefinition(objectId).asInstanceOf[AmmoBoxDefinition])
case "ConstructionItem" => case "ConstructionItem" =>
container.Slot(objectIndex).Equipment = ConstructionItem( container.Slot(objectIndex).Equipment = ConstructionItem(
DefinitionUtil.idToDefinition(objectId).asInstanceOf[ConstructionItemDefinition] DefinitionUtil.idToDefinition(objectId).asInstanceOf[ConstructionItemDefinition]
) )
case "SimpleItem" => case "SimpleItem" =>
container.Slot(objectIndex).Equipment = container.Slot(objectIndex).Equipment =
SimpleItem(DefinitionUtil.idToDefinition(objectId).asInstanceOf[SimpleItemDefinition]) SimpleItem(DefinitionUtil.idToDefinition(objectId).asInstanceOf[SimpleItemDefinition])
case "Kit" => case "Kit" =>
container.Slot(objectIndex).Equipment = container.Slot(objectIndex).Equipment =
Kit(DefinitionUtil.idToDefinition(objectId).asInstanceOf[KitDefinition]) Kit(DefinitionUtil.idToDefinition(objectId).asInstanceOf[KitDefinition])
case "Telepad" | "BoomerTrigger" => ; case "Telepad" | "BoomerTrigger" => ;
//special types of equipment that are not actually loaded //special types of equipment that are not actually loaded
case name => case name =>
log.error(s"failing to add unknown equipment to a locker - $name") log.error(s"failing to add unknown equipment to a locker - $name")
} }
toolAmmo foreach { toolAmmo => toolAmmo foreach { toolAmmo =>
toolAmmo.toString.split("_").drop(1).foreach { value => toolAmmo.split("_").drop(1).foreach { value =>
val (ammoSlots, ammoTypeIndex, ammoBoxDefinition) = value.split("-") match { val (ammoSlots, ammoTypeIndex, ammoBoxDefinition) = value.split("-") match {
case Array(a: String, b: String, c: String) => (a.toInt, b.toInt, c.toInt) case Array(a: String, b: String, c: String) => (a.toInt, b.toInt, c.toInt)
}
container.Slot(objectIndex).Equipment.get.asInstanceOf[Tool].AmmoSlots(ammoSlots).AmmoTypeIndex =
ammoTypeIndex
container.Slot(objectIndex).Equipment.get.asInstanceOf[Tool].AmmoSlots(ammoSlots).Box =
AmmoBox(AmmoBoxDefinition(ammoBoxDefinition))
} }
container.Slot(objectIndex).Equipment.get.asInstanceOf[Tool].AmmoSlots(ammoSlots).AmmoTypeIndex =
ammoTypeIndex
container.Slot(objectIndex).Equipment.get.asInstanceOf[Tool].AmmoSlots(ammoSlots).Box =
AmmoBox(AmmoBoxDefinition(ammoBoxDefinition))
} }
}
} }
} }
@ -1768,21 +1782,16 @@ class AvatarActor(
} }
def resolvePurchaseTimeName(faction: PlanetSideEmpire.Value, item: BasicDefinition): (BasicDefinition, String) = { def resolvePurchaseTimeName(faction: PlanetSideEmpire.Value, item: BasicDefinition): (BasicDefinition, String) = {
val factionName : String = faction.toString.toLowerCase val factionName: String = faction.toString.toLowerCase
val name = item match { val name = item match {
case GlobalDefinitions.trhev_dualcycler | case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.nchev_scattercannon |
GlobalDefinitions.nchev_scattercannon | GlobalDefinitions.vshev_quasar =>
GlobalDefinitions.vshev_quasar =>
s"${factionName}hev_antipersonnel" s"${factionName}hev_antipersonnel"
case GlobalDefinitions.trhev_pounder | case GlobalDefinitions.trhev_pounder | GlobalDefinitions.nchev_falcon | GlobalDefinitions.vshev_comet =>
GlobalDefinitions.nchev_falcon |
GlobalDefinitions.vshev_comet =>
s"${factionName}hev_antivehicular" s"${factionName}hev_antivehicular"
case GlobalDefinitions.trhev_burster | case GlobalDefinitions.trhev_burster | GlobalDefinitions.nchev_sparrow | GlobalDefinitions.vshev_starfire =>
GlobalDefinitions.nchev_sparrow |
GlobalDefinitions.vshev_starfire =>
s"${factionName}hev_antiaircraft" s"${factionName}hev_antiaircraft"
case _ => case _ =>
item.Name item.Name
} }
(item, name) (item, name)
@ -1793,28 +1802,24 @@ class AvatarActor(
if (name.matches("(tr|nc|vs)hev_.+") && Config.app.game.sharedMaxCooldown) { if (name.matches("(tr|nc|vs)hev_.+") && Config.app.game.sharedMaxCooldown) {
val faction = name.take(2) val faction = name.take(2)
(if (faction.equals("nc")) { (if (faction.equals("nc")) {
Seq(GlobalDefinitions.nchev_scattercannon, GlobalDefinitions.nchev_falcon, GlobalDefinitions.nchev_sparrow) Seq(GlobalDefinitions.nchev_scattercannon, GlobalDefinitions.nchev_falcon, GlobalDefinitions.nchev_sparrow)
} } else if (faction.equals("vs")) {
else if (faction.equals("vs")) { Seq(GlobalDefinitions.vshev_quasar, GlobalDefinitions.vshev_comet, GlobalDefinitions.vshev_starfire)
Seq(GlobalDefinitions.vshev_quasar, GlobalDefinitions.vshev_comet, GlobalDefinitions.vshev_starfire) } else {
} Seq(GlobalDefinitions.trhev_dualcycler, GlobalDefinitions.trhev_pounder, GlobalDefinitions.trhev_burster)
else { }).zip(
Seq(GlobalDefinitions.trhev_dualcycler, GlobalDefinitions.trhev_pounder, GlobalDefinitions.trhev_burster)
}).zip(
Seq(s"${faction}hev_antipersonnel", s"${faction}hev_antivehicular", s"${faction}hev_antiaircraft") Seq(s"${faction}hev_antipersonnel", s"${faction}hev_antivehicular", s"${faction}hev_antiaircraft")
) )
} else { } else {
definition match { definition match {
case vdef: VehicleDefinition case vdef: VehicleDefinition if GlobalDefinitions.isBattleFrameFlightVehicle(vdef) =>
if GlobalDefinitions.isBattleFrameFlightVehicle(vdef) =>
val bframe = name.substring(0, name.indexOf('_')) val bframe = name.substring(0, name.indexOf('_'))
val gunner = bframe+"_gunner" val gunner = bframe + "_gunner"
Seq((DefinitionUtil.fromString(gunner), gunner), (vdef, name)) Seq((DefinitionUtil.fromString(gunner), gunner), (vdef, name))
case vdef: VehicleDefinition case vdef: VehicleDefinition if GlobalDefinitions.isBattleFrameGunnerVehicle(vdef) =>
if GlobalDefinitions.isBattleFrameGunnerVehicle(vdef) =>
val bframe = name.substring(0, name.indexOf('_')) val bframe = name.substring(0, name.indexOf('_'))
val flight = bframe+"_flight" val flight = bframe + "_flight"
Seq((vdef, name), (DefinitionUtil.fromString(flight), flight)) Seq((vdef, name), (DefinitionUtil.fromString(flight), flight))
case _ => case _ =>
@ -1835,7 +1840,7 @@ class AvatarActor(
updatePurchaseTimer(name, cooldown.toSeconds - secondsSincePurchase, unk1 = true) updatePurchaseTimer(name, cooldown.toSeconds - secondsSincePurchase, unk1 = true)
case _ => case _ =>
keysToDrop = keysToDrop :+ key //key has timed-out keysToDrop = keysToDrop :+ key //key has timed-out
} }
case _ => ; case _ => ;
} }