Battleframe Branch Bugfixes (#985)

* restored control of bfr gunner weapon; attempted to restore shield functionality given unspecified problem statement; bfr's can drown like ground vehicles, not aircraft; siphons can not drain a facility when equal to or less than 40% ntu; corrected oversight with implant timers; accidentally got assertion for TradeMessage backwards

* fixed bfr shield charge display; phantasm driver seat is now bailable

* this test never passes, but the test based on this test passing passes

* correction to support bfr flight variant waterlog recovery
This commit is contained in:
Fate-JH 2022-02-03 23:23:22 -05:00 committed by GitHub
parent 6ae0b44848
commit f1a9809c54
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 140 additions and 116 deletions

View file

@ -1146,7 +1146,7 @@ class AvatarActor(
} else if (becomeFatigued) {
avatarCopy(avatar.copy(implants = avatar.implants.zipWithIndex.collect {
case (Some(implant), slot) if implant.active =>
implantTimers(slot).cancel()
implantTimers.get(slot).foreach(_.cancel())
Some(implant.copy(active = false))
case (out, _) =>
out
@ -1230,7 +1230,7 @@ class AvatarActor(
implants = avatar.implants.updated(index, Some(imp.copy(initialized = false, active = false)))
))
//restart initialization process
implantTimers(index).cancel()
implantTimers.get(index).foreach(_.cancel())
implantTimers(index) = context.scheduleOnce(
imp.definition.InitializationDuration.seconds,
context.self,
@ -1249,7 +1249,7 @@ class AvatarActor(
case (Some(implant), index) if implant.definition.implantType == implantType => (implant, index)
} match {
case Some((implant, slot)) =>
implantTimers(slot).cancel()
implantTimers.get(slot).foreach(_.cancel())
avatarCopy(avatar.copy(
implants = avatar.implants.updated(slot, Some(implant.copy(active = false)))
))

View file

@ -9308,7 +9308,8 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
val filteredTools = tools.filter { tool: Tool =>
v.Weapons.find {
case (index, slot) =>
//index = 2 or 3 for bfr_gunner; index = 1 or 2 for bfr_flight
//arm mounted weapon?
//index = 1 or 2 for bfr_flight; index = 2 3 or 4 for bfr_gunner
index > 0 && index < 4 && slot.Equipment.nonEmpty && (tool eq slot.Equipment.get)
} match {
case Some((index, _)) =>
@ -9323,7 +9324,8 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
}
mountIsEnabled
case None =>
false
//gunner mounted weapon?
tool.Size == EquipmentSize.BFRGunnerWeapon
}
}
filteredTools

View file

@ -4698,6 +4698,8 @@ object GlobalDefinitions {
ntu_siphon_emp.DamageAtEdge = 0.1f
ntu_siphon_emp.DamageRadius = 50f
ntu_siphon_emp.ProjectileDamageType = DamageType.Splash
ntu_siphon_emp.AdditionalEffect = true
ntu_siphon_emp.SympatheticExplosion = true
ntu_siphon_emp.JammedEffectDuration += TargetValidation(
EffectTarget.Category.Player,
EffectTarget.Validation.Player
@ -8433,7 +8435,7 @@ object GlobalDefinitions {
phantasm.MaxShields = 500
phantasm.CanCloak = true
phantasm.CanFly = true
phantasm.Seats += 0 -> new SeatDefinition()
phantasm.Seats += 0 -> bailableSeat
phantasm.Seats += 1 -> bailableSeat
phantasm.Seats += 2 -> bailableSeat
phantasm.Seats += 3 -> bailableSeat

View file

@ -87,6 +87,15 @@ trait DamageableVehicle
}
}
/**
* Produce the event system channel names required for updating helath and shield values.
* @param obj the vehicle
* @return the channel for updating health values, the channel for updating shield values
*/
def damageChannels(obj: Vehicle): (String, String) = {
(obj.Zone.id, obj.Actor.toString)
}
/**
* Most all vehicles and the weapons mounted to them can jam
* if the projectile that strikes (near) them has jammering properties.
@ -104,8 +113,7 @@ trait DamageableVehicle
val zone = target.Zone
val events = zone.VehicleEvents
val targetGUID = target.GUID
val zoneId = zone.id
val vehicleChannel = s"${obj.Actor}"
val (healthChannel, shieldChannel) = damageChannels(obj)
val (damageToHealth, damageToShields, totalDamage) = amount match {
case (a: Int, b: Int) => (a, b, a+b)
case _ => (0, 0, 0)
@ -133,14 +141,14 @@ trait DamageableVehicle
//stat changes
if (damageToShields > 0) {
events ! VehicleServiceMessage(
vehicleChannel,
shieldChannel,
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, obj.Definition.shieldUiAttribute, obj.Shields)
)
announceConfrontation = true
}
if (damageToHealth > 0) {
events ! VehicleServiceMessage(
zoneId,
healthChannel,
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, obj.Health)
)
announceConfrontation = true

View file

@ -60,8 +60,11 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
//bfr's discharge into friendly silos and charge from enemy and neutral silos
if (siloFaction == playerFaction) {
Some(TransferBehavior.Discharging(Ntu.Nanites))
} else {
} else if (resourceSilo.MaxNtuCapacitor * 0.4f < resourceSilo.NtuCapacitor) {
//the bfr never drains below 40%
Some(TransferBehavior.Charging(Ntu.Nanites))
} else {
None
}
} else if(siloFaction == PlanetSideEmpire.NEUTRAL || siloFaction == playerFaction) {
//ants discharge into neutral and friendly silos

View file

@ -31,7 +31,10 @@ class BfrControl(vehicle: Vehicle)
extends VehicleControl(vehicle)
with BfrTransferBehavior
with ArmorSiphonBehavior.SiphonOwner {
/** shield-auto charge */
/** shield-auto charge;
* active timer indicates a charging shield;
* `Default.Cancellable` indicates a technical pause in charging;
* `Cancellable.alreadyCancelled` indicates a permanant cessation of charging activity (vehicle destruction) */
var shieldCharge: Cancellable = Default.Cancellable
def SiphoningObject = vehicle
@ -90,11 +93,16 @@ class BfrControl(vehicle: Vehicle)
}
}
override def damageChannels(obj: Vehicle): (String, String) = {
val channel = obj.Zone.id
(channel, channel)
}
override def DamageAwareness(target: Target, cause: DamageResult, amount: Any) : Unit = {
super.DamageAwareness(target, cause, amount)
//manage shield display and charge
disableShieldIfDrained()
if (shieldCharge != Default.Cancellable && vehicle.Shields < vehicle.MaxShields) {
if (shieldCharge != Cancellable.alreadyCancelled && vehicle.Shields < vehicle.MaxShields) {
shieldCharge.cancel()
shieldCharge = context.system.scheduler.scheduleOnce(
delay = vehicle.Definition.ShieldDamageDelay milliseconds,
@ -107,7 +115,7 @@ class BfrControl(vehicle: Vehicle)
override def destructionDelayed(delay: Long, cause: DamageResult): Unit = {
super.destructionDelayed(delay, cause)
shieldCharge.cancel()
shieldCharge = Default.Cancellable
shieldCharge = Cancellable.alreadyCancelled
//harmless boom boom's
context.system.scheduler.scheduleOnce(delay = 0 milliseconds, self, BfrControl.VehicleExplosion)
}
@ -115,7 +123,7 @@ class BfrControl(vehicle: Vehicle)
override def DestructionAwareness(target: Target, cause: DamageResult): Unit = {
super.DestructionAwareness(target, cause)
shieldCharge.cancel()
shieldCharge = Default.Cancellable
shieldCharge = Cancellable.alreadyCancelled
disableShield()
}
@ -332,7 +340,7 @@ class BfrControl(vehicle: Vehicle)
shieldCharge(vehicle.Shields, vehicle.Definition, delay)
}
def shieldCharge(after:Int, definition: VehicleDefinition, delay: Long): Unit = {
def shieldCharge(after: Int, definition: VehicleDefinition, delay: Long): Unit = {
shieldCharge.cancel()
if (after < definition.MaxShields && !vehicle.Jammed) {
shieldCharge = context.system.scheduler.scheduleOnce(
@ -350,7 +358,7 @@ class BfrControl(vehicle: Vehicle)
val zone = vehicle.Zone
val shields = vehicle.Shields
zone.VehicleEvents ! VehicleServiceMessage(
s"${vehicle.Actor}",
zone.id,
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, vguid, vehicle.Definition.shieldUiAttribute, shields)
)
}

View file

@ -81,7 +81,8 @@ class VehicleControl(vehicle: Vehicle)
SetInteraction(EnvironmentAttribute.Water, doInteractingWithWater)
SetInteraction(EnvironmentAttribute.Lava, doInteractingWithLava)
SetInteraction(EnvironmentAttribute.Death, doInteractingWithDeath)
if (!vehicle.Definition.CanFly) { //can not recover from sinking disability
if (!vehicle.Definition.CanFly || GlobalDefinitions.isBattleFrameFlightVehicle(vehicle.Definition)) {
//can recover from sinking disability
SetInteractionStop(EnvironmentAttribute.Water, stopInteractingWithWater)
}
@ -188,7 +189,7 @@ class VehicleControl(vehicle: Vehicle)
)
zone.AvatarEvents ! AvatarServiceMessage(
player.Name,
AvatarAction.TerminalOrderResult(msg.terminal_guid, msg.transaction_type, true)
AvatarAction.TerminalOrderResult(msg.terminal_guid, msg.transaction_type, result = true)
)
case _ => ;
@ -196,7 +197,7 @@ class VehicleControl(vehicle: Vehicle)
} else {
zone.AvatarEvents ! AvatarServiceMessage(
player.Name,
AvatarAction.TerminalOrderResult(msg.terminal_guid, msg.transaction_type, false)
AvatarAction.TerminalOrderResult(msg.terminal_guid, msg.transaction_type, result = false)
)
}
@ -385,7 +386,7 @@ class VehicleControl(vehicle: Vehicle)
zone.actor ! ZoneActor.AddToBlockMap(player, vehicle.Position)
}
if (player.HasGUID) {
events ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(player.GUID, 4, true, guid))
events ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(player.GUID, 4, unk2 = true, guid))
}
case None => ;
}
@ -582,7 +583,7 @@ class VehicleControl(vehicle: Vehicle)
def doInteractingWithWater(obj: PlanetSideServerObject, body: PieceOfEnvironment, data: Option[OxygenStateTarget]): Unit = {
val (effect: Boolean, time: Long, percentage: Float) = {
val (a, b, c) = RespondsToZoneEnvironment.drowningInWateryConditions(obj, submergedCondition, interactionTime)
if (a && vehicle.Definition.CanFly) {
if (a && vehicle.Definition.CanFly && !GlobalDefinitions.isBattleFrameFlightVehicle(vehicle.Definition)) {
(true, 0L, 0f) //no progress bar
} else {
(a, b, c)
@ -796,7 +797,7 @@ class VehicleControl(vehicle: Vehicle)
tplayer.VehicleSeated = None
zone.VehicleEvents ! VehicleServiceMessage(
zone.id,
VehicleAction.KickPassenger(tplayer.GUID, 4, false, vguid)
VehicleAction.KickPassenger(tplayer.GUID, 4, unk2 = false, vguid)
)
}
case _ => ; // No player seated
@ -809,7 +810,7 @@ class VehicleControl(vehicle: Vehicle)
if (vehicle.SeatPermissionGroup(cargoIndex).contains(group)) {
//todo: this probably doesn't work for passengers within the cargo vehicle
// Instruct client to start bail dismount procedure
self ! DismountVehicleCargoMsg(dguid, cargo.GUID, true, false, false)
self ! DismountVehicleCargoMsg(dguid, cargo.GUID, bailed = true, requestedByPassenger = false, kicked = false)
}
case None => ; // No vehicle in cargo
}

View file

@ -29,7 +29,7 @@ final case class TradeThree(value: Int, unk: PlanetSideGUID) extends Trade {
final case class TradeFour(value: Int, unk: Int) extends Trade {
assert(value == 9, s"TradeFour has wrong code value - $value not in [9]")
assert(unk < 0 || unk > 15, s"TradeFour value is out of bounds - $unk not in [0-f]")
assert(unk > -1 && unk < 16, s"TradeFour value is out of bounds - $unk not in [0-f]")
}
final case class TradeMessage(trade: Trade)