diff --git a/src/main/scala/net/psforever/actors/session/csr/GeneralLogic.scala b/src/main/scala/net/psforever/actors/session/csr/GeneralLogic.scala index 31ca715e4..4f168065b 100644 --- a/src/main/scala/net/psforever/actors/session/csr/GeneralLogic.scala +++ b/src/main/scala/net/psforever/actors/session/csr/GeneralLogic.scala @@ -5,7 +5,7 @@ import akka.actor.{ActorContext, ActorRef, typed} import net.psforever.actors.session.AvatarActor import net.psforever.actors.session.support.{GeneralFunctions, GeneralOperations, SessionData} import net.psforever.objects.{Account, BoomerDeployable, BoomerTrigger, ConstructionItem, GlobalDefinitions, LivePlayerList, Player, SensorDeployable, ShieldGeneratorDeployable, SpecialEmp, TelepadDeployable, Tool, TrapDeployable, TurretDeployable, Vehicle} -import net.psforever.objects.avatar.{Avatar, PlayerControl} +import net.psforever.objects.avatar.{Avatar, AvatarBot, PlayerControl} import net.psforever.objects.ballistics.Projectile import net.psforever.objects.ce.Deployable import net.psforever.objects.definition.{BasicDefinition, KitDefinition, SpecialExoSuitDefinition} @@ -286,6 +286,8 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex ops.handleUseGeneralEntity(panel, equipment) case Some(obj: Player) => ops.handleUsePlayer(obj, equipment, pkt) + case Some(obj: AvatarBot) => + ops.handleUseBot(obj, equipment, pkt) case Some(locker: Locker) => ops.handleUseLocker(locker, equipment, pkt) case Some(gen: Generator) => diff --git a/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala b/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala index 823d09923..af2f9a693 100644 --- a/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala +++ b/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala @@ -6,7 +6,7 @@ import akka.actor.{ActorContext, ActorRef, typed} import net.psforever.actors.session.{AvatarActor, SessionActor} import net.psforever.actors.session.support.{GeneralFunctions, GeneralOperations, SessionData, SessionOutfitHandlers} import net.psforever.objects.{Account, BoomerDeployable, BoomerTrigger, ConstructionItem, GlobalDefinitions, LivePlayerList, Player, SensorDeployable, ShieldGeneratorDeployable, SpecialEmp, TelepadDeployable, Tool, TrapDeployable, TurretDeployable, Vehicle} -import net.psforever.objects.avatar.{Avatar, PlayerControl, SpecialCarry} +import net.psforever.objects.avatar.{Avatar, AvatarBot, PlayerControl, SpecialCarry} import net.psforever.objects.ballistics.Projectile import net.psforever.objects.ce.{Deployable, DeployedItem} import net.psforever.objects.definition.{BasicDefinition, KitDefinition, SpecialExoSuitDefinition} @@ -356,6 +356,8 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex ops.handleUseGeneralEntity(panel, equipment) case Some(obj: Player) => ops.handleUsePlayer(obj, equipment, pkt) + case Some(obj: AvatarBot) => + ops.handleUseBot(obj, equipment, pkt) case Some(locker: Locker) => ops.handleUseLocker(locker, equipment, pkt) case Some(gen: Generator) => diff --git a/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala b/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala index 3d2a92e95..76459ff0a 100644 --- a/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala +++ b/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala @@ -1206,6 +1206,27 @@ class GeneralOperations( } } + def handleUseBot(obj: AvatarBot, equipment: Option[Equipment], msg: UseItemMessage): Unit = { + sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_use") + if (msg.unk3) { + msg.object_id match { + case ObjectClass.avatar | ObjectClass.avatar_bot | ObjectClass.avatar_bot_agile | ObjectClass.avatar_bot_agile_no_weapon | + ObjectClass.avatar_bot_max | ObjectClass.avatar_bot_max_no_weapon | ObjectClass.avatar_bot_reinforced | + ObjectClass.avatar_bot_reinforced_no_weapon | ObjectClass.avatar_bot_standard | ObjectClass.avatar_bot_standard_no_weapon => + equipment match { + case Some(tool: Tool) if tool.Definition == GlobalDefinitions.bank => + obj.Actor ! CommonMessages.Use(player, equipment) + + case Some(tool: Tool) if tool.Definition == GlobalDefinitions.medicalapplicator => + obj.Actor ! CommonMessages.Use(player, equipment) + case _ => () + } + + case _ => + } + } + } + def handleUseLocker(locker: Locker, equipment: Option[Equipment], msg: UseItemMessage): Unit = { equipment match { case Some(item) => diff --git a/src/main/scala/net/psforever/objects/avatar/AvatarBotActor.scala b/src/main/scala/net/psforever/objects/avatar/AvatarBotActor.scala index 3fffb1a99..94bdebfb8 100644 --- a/src/main/scala/net/psforever/objects/avatar/AvatarBotActor.scala +++ b/src/main/scala/net/psforever/objects/avatar/AvatarBotActor.scala @@ -3,19 +3,24 @@ package net.psforever.objects.avatar import akka.actor.{Actor, ActorRef} import net.psforever.actors.zone.ShootingRangeTargetSpawner +import net.psforever.objects.{GlobalDefinitions, Tool} import net.psforever.objects.avatar.AvatarBot import net.psforever.objects.equipment._ import net.psforever.objects.serverobject.aura.{Aura, AuraEffectBehavior} +import net.psforever.objects.serverobject.CommonMessages import net.psforever.objects.serverobject.damage.Damageable.Target import net.psforever.objects.serverobject.damage.{AggravatedBehavior, Damageable, DamageableEntity} import net.psforever.objects.vital.resolution.ResolutionCalculations.Output import net.psforever.objects.zones._ import net.psforever.packet.game._ import net.psforever.types._ +import net.psforever.services.Service import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.objects.serverobject.environment.interaction.RespondsToZoneEnvironment +import net.psforever.objects.serverobject.repair.Repairable import net.psforever.objects.sourcing.PlayerSource +import net.psforever.objects.vital.{HealFromEquipment, RepairFromEquipment} import net.psforever.objects.vital.etc.SuicideReason import net.psforever.objects.vital.interaction.{DamageInteraction, DamageResult} @@ -83,6 +88,91 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef) case AvatarBot.Release() => release() + case CommonMessages.Use(user, Some(item: Tool)) + if item.Definition == GlobalDefinitions.medicalapplicator && bot.isAlive => + //heal + val originalHealth = bot.Health + val definition = bot.Definition + if ( + bot.MaxHealth > 0 && originalHealth < bot.MaxHealth && + user.Faction == bot.Faction && + item.Magazine > 0 && + Vector3.Distance(user.Position, bot.Position) < definition.RepairDistance + ) { + val zone = bot.Zone + val events = zone.AvatarEvents + val uname = user.Name + val guid = bot.GUID + if (!(bot.isMoving || user.isMoving)) { //only allow stationary heals + val newHealth = bot.Health = originalHealth + 10 + val magazine = item.Discharge() + events ! AvatarServiceMessage( + uname, + AvatarAction.SendResponse( + Service.defaultPlayerGUID, + InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine.toLong) + ) + ) + events ! AvatarServiceMessage(zone.id, AvatarAction.PlanetsideAttributeToAll(guid, 0, newHealth)) + bot.LogActivity( + HealFromEquipment( + PlayerSource(user), + GlobalDefinitions.medicalapplicator, + newHealth - originalHealth + ) + ) + } + //progress bar remains visible for all heal attempts + events ! AvatarServiceMessage( + uname, + AvatarAction.SendResponse( + Service.defaultPlayerGUID, + RepairMessage(guid, bot.Health * 100 / definition.MaxHealth) + ) + ) + } + + case CommonMessages.Use(user, Some(item: Tool)) if item.Definition == GlobalDefinitions.bank => + val originalArmor = bot.Armor + val definition = bot.Definition + if ( + bot.MaxArmor > 0 && originalArmor < bot.MaxArmor && + user.Faction == bot.Faction && + item.AmmoType == Ammo.armor_canister && item.Magazine > 0 && + Vector3.Distance(user.Position, bot.Position) < definition.RepairDistance + ) { + val zone = bot.Zone + val events = zone.AvatarEvents + val uname = user.Name + val guid = bot.GUID + if (!(bot.isMoving || user.isMoving)) { //only allow stationary repairs + val newArmor = bot.Armor = + originalArmor + Repairable.applyLevelModifier(user, item, RepairToolValue(item)).toInt + definition.RepairMod + val magazine = item.Discharge() + events ! AvatarServiceMessage( + uname, + AvatarAction.SendResponse( + Service.defaultPlayerGUID, + InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine.toLong) + ) + ) + events ! AvatarServiceMessage(zone.id, AvatarAction.PlanetsideAttributeToAll(guid, 4, bot.Armor)) + bot.LogActivity( + RepairFromEquipment( + PlayerSource(user), + GlobalDefinitions.bank, + newArmor - originalArmor + ) + ) + } + //progress bar remains visible for all repair attempts + events ! AvatarServiceMessage( + uname, + AvatarAction + .SendResponse(Service.defaultPlayerGUID, RepairMessage(guid, bot.Armor * 100 / bot.MaxArmor)) + ) + } + case _ => ; } @@ -404,6 +494,16 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef) case _ => ; } + def RepairToolValue(item: Tool): Float = { + item.AmmoSlot.Box.Definition.repairAmount + + (if (bot.ExoSuit != ExoSuitType.MAX) { + item.FireMode.Add.Damage0 + } + else { + item.FireMode.Add.Damage3 + }) + } + def UpdateAuraEffect(target: AuraEffectBehavior.Target) : Unit = { import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} val zone = target.Zone