mirror of
https://github.com/sp-tarkov/modules.git
synced 2025-02-13 02:10:45 -05:00
BTR Cover Fire service and roadkill trigger implemented (!62)
Todo: * Taxi service * Refinement of BTR turret aim/shooting * BTR should switch targets if it has no line of sight to current target * Blacklist player from entering BTR after antagonising it * Perhaps make blacklist persist for 3 raids (apparently on Live?) * Code refactor because it currently looks like doodoo Co-authored-by: Nympfonic <arys.steam@gmail.com> Reviewed-on: SPT-AKI/Modules#62 Co-authored-by: Arys <arys@noreply.dev.sp-tarkov.com> Co-committed-by: Arys <arys@noreply.dev.sp-tarkov.com>
This commit is contained in:
parent
a0f2bb9261
commit
e771501cd5
@ -11,13 +11,15 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using Random = UnityEngine.Random;
|
||||||
|
using BotEventHandler = GClass595;
|
||||||
|
|
||||||
namespace Aki.Debugging.BTR
|
namespace Aki.Debugging.BTR
|
||||||
{
|
{
|
||||||
public class BTRManager : MonoBehaviour
|
public class BTRManager : MonoBehaviour
|
||||||
{
|
{
|
||||||
private GameWorld gameWorld;
|
private GameWorld gameWorld;
|
||||||
private BotsController botsController;
|
private BotEventHandler botEventHandler;
|
||||||
|
|
||||||
private BotBTRService btrBotService;
|
private BotBTRService btrBotService;
|
||||||
private BTRControllerClass btrController;
|
private BTRControllerClass btrController;
|
||||||
@ -30,23 +32,22 @@ namespace Aki.Debugging.BTR
|
|||||||
private EPlayerBtrState previousPlayerBtrState;
|
private EPlayerBtrState previousPlayerBtrState;
|
||||||
private BTRSide lastInteractedBtrSide;
|
private BTRSide lastInteractedBtrSide;
|
||||||
public BTRSide LastInteractedBtrSide => lastInteractedBtrSide;
|
public BTRSide LastInteractedBtrSide => lastInteractedBtrSide;
|
||||||
|
|
||||||
|
private Coroutine _coverFireTimerCoroutine;
|
||||||
private BTRTurretServer btrTurretServer;
|
private BTRTurretServer btrTurretServer;
|
||||||
private Transform btrTurretDefaultTargetTransform;
|
private Transform btrTurretDefaultTargetTransform;
|
||||||
private Coroutine _shootingTargetCoroutine;
|
private Coroutine _shootingTargetCoroutine;
|
||||||
|
private IPlayer currentTarget = null;
|
||||||
private bool isShooting = false;
|
private bool isShooting = false;
|
||||||
private BulletClass btrMachineGunAmmo;
|
private BulletClass btrMachineGunAmmo;
|
||||||
private Item btrMachineGunWeapon;
|
private Item btrMachineGunWeapon;
|
||||||
|
|
||||||
private MethodInfo _updateTaxiPriceMethod;
|
private MethodInfo _updateTaxiPriceMethod;
|
||||||
|
|
||||||
private Dictionary<ETraderServiceType, Dictionary<string, bool>> ServicePurchasedDict { get; set; }
|
|
||||||
|
|
||||||
BTRManager()
|
BTRManager()
|
||||||
{
|
{
|
||||||
Type btrControllerType = typeof(BTRControllerClass);
|
Type btrControllerType = typeof(BTRControllerClass);
|
||||||
_updateTaxiPriceMethod = AccessTools.GetDeclaredMethods(btrControllerType).Single(IsUpdateTaxiPriceMethod);
|
_updateTaxiPriceMethod = AccessTools.GetDeclaredMethods(btrControllerType).Single(IsUpdateTaxiPriceMethod);
|
||||||
ServicePurchasedDict = new Dictionary<ETraderServiceType, Dictionary<string, bool>>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find `BTRControllerClass.method_9(PathDestination currentDestinationPoint, bool lastRoutePoint)`
|
// Find `BTRControllerClass.method_9(PathDestination currentDestinationPoint, bool lastRoutePoint)`
|
||||||
@ -55,32 +56,6 @@ namespace Aki.Debugging.BTR
|
|||||||
return (method.GetParameters().Length == 2 && method.GetParameters()[0].ParameterType == typeof(PathDestination));
|
return (method.GetParameters().Length == 2 && method.GetParameters()[0].ParameterType == typeof(PathDestination));
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsServicePurchased(ETraderServiceType serviceType, string traderId)
|
|
||||||
{
|
|
||||||
if (ServicePurchasedDict.TryGetValue(serviceType, out var traderDict))
|
|
||||||
{
|
|
||||||
if (traderDict.TryGetValue(traderId, out var result))
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetServicePurchased(ETraderServiceType serviceType, string traderId)
|
|
||||||
{
|
|
||||||
if (ServicePurchasedDict.TryGetValue(serviceType, out var traderDict))
|
|
||||||
{
|
|
||||||
traderDict[traderId] = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ServicePurchasedDict[serviceType] = new Dictionary<string, bool>();
|
|
||||||
ServicePurchasedDict[serviceType][traderId] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Start()
|
private void Start()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -90,6 +65,7 @@ namespace Aki.Debugging.BTR
|
|||||||
if (gameWorld == null)
|
if (gameWorld == null)
|
||||||
{
|
{
|
||||||
Destroy(this);
|
Destroy(this);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gameWorld.BtrController == null)
|
if (gameWorld.BtrController == null)
|
||||||
@ -121,65 +97,48 @@ namespace Aki.Debugging.BTR
|
|||||||
{
|
{
|
||||||
btrBotShooter = btrController.BotShooterBtr;
|
btrBotShooter = btrController.BotShooterBtr;
|
||||||
btrBotService.Reset(); // Player will be added to Neutrals list and removed from Enemies list
|
btrBotService.Reset(); // Player will be added to Neutrals list and removed from Enemies list
|
||||||
|
TraderServicesManager.Instance.OnTraderServicePurchased += TraderServicePurchased;
|
||||||
btrBotShooterInitialized = true;
|
btrBotShooterInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (btrController.BotShooterBtr == null) return;
|
if (btrController.BotShooterBtr == null) return;
|
||||||
|
|
||||||
if (IsAimingAtTarget() && !isShooting)
|
if (HasTarget() && IsAimingAtTarget() && !isShooting)
|
||||||
{
|
{
|
||||||
_shootingTargetCoroutine = StaticManager.BeginCoroutine(ShootTarget());
|
_shootingTargetCoroutine = StaticManager.BeginCoroutine(ShootTarget());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HandleBtrDoorState(EPlayerBtrState playerBtrState)
|
|
||||||
{
|
|
||||||
if (previousPlayerBtrState == EPlayerBtrState.Approach && playerBtrState == EPlayerBtrState.GoIn
|
|
||||||
|| previousPlayerBtrState == EPlayerBtrState.Inside && playerBtrState == EPlayerBtrState.GoOut)
|
|
||||||
{
|
|
||||||
// Open Door
|
|
||||||
UpdateBTRSideDoorState(1);
|
|
||||||
}
|
|
||||||
else if (previousPlayerBtrState == EPlayerBtrState.GoIn && playerBtrState == EPlayerBtrState.Inside
|
|
||||||
|| previousPlayerBtrState == EPlayerBtrState.GoOut && playerBtrState == EPlayerBtrState.Outside)
|
|
||||||
{
|
|
||||||
// Close Door
|
|
||||||
UpdateBTRSideDoorState(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
previousPlayerBtrState = playerBtrState;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Please tell me there's a better way than this xd
|
// Please tell me there's a better way than this xd
|
||||||
public void OnPlayerInteractDoor(PlayerInteractPacket interactPacket)
|
public void OnPlayerInteractDoor(PlayerInteractPacket interactPacket)
|
||||||
{
|
{
|
||||||
var playerGoIn = interactPacket.InteractionType == EInteractionType.GoIn;
|
btrServerSide.LeftSlot0State = 0;
|
||||||
var playerGoOut = interactPacket.InteractionType == EInteractionType.GoOut;
|
btrServerSide.LeftSlot1State = 0;
|
||||||
|
btrServerSide.RightSlot0State = 0;
|
||||||
|
btrServerSide.RightSlot1State = 0;
|
||||||
|
|
||||||
if (interactPacket.SideId == 0)
|
bool playerGoIn = interactPacket.InteractionType == EInteractionType.GoIn;
|
||||||
|
|
||||||
|
if (interactPacket.SideId == 0 && playerGoIn)
|
||||||
{
|
{
|
||||||
if (interactPacket.SlotId == 0)
|
if (interactPacket.SlotId == 0)
|
||||||
{
|
{
|
||||||
if (playerGoIn) btrServerSide.LeftSlot0State = 1;
|
btrServerSide.LeftSlot0State = 1;
|
||||||
else if (playerGoOut) btrServerSide.LeftSlot0State = 0;
|
|
||||||
}
|
}
|
||||||
else if (interactPacket.SlotId == 1)
|
else if (interactPacket.SlotId == 1)
|
||||||
{
|
{
|
||||||
if (playerGoIn) btrServerSide.LeftSlot1State = 1;
|
btrServerSide.LeftSlot1State = 1;
|
||||||
else if (playerGoOut) btrServerSide.LeftSlot1State = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (interactPacket.SideId == 1)
|
else if (interactPacket.SideId == 1 && playerGoIn)
|
||||||
{
|
{
|
||||||
if (interactPacket.SlotId == 0)
|
if (interactPacket.SlotId == 0)
|
||||||
{
|
{
|
||||||
if (playerGoIn) btrServerSide.RightSlot0State = 1;
|
btrServerSide.RightSlot0State = 1;
|
||||||
else if (playerGoOut) btrServerSide.RightSlot0State = 0;
|
|
||||||
}
|
}
|
||||||
else if (interactPacket.SlotId == 1)
|
else if (interactPacket.SlotId == 1)
|
||||||
{
|
{
|
||||||
if (playerGoIn) btrServerSide.RightSlot1State = 1;
|
btrServerSide.RightSlot1State = 1;
|
||||||
else if (playerGoOut) btrServerSide.RightSlot1State = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -187,19 +146,20 @@ namespace Aki.Debugging.BTR
|
|||||||
private void InitBTR()
|
private void InitBTR()
|
||||||
{
|
{
|
||||||
// Initial setup
|
// Initial setup
|
||||||
botsController = Singleton<IBotGame>.Instance.BotsController;
|
botEventHandler = Singleton<BotEventHandler>.Instance;
|
||||||
|
var botsController = Singleton<IBotGame>.Instance.BotsController;
|
||||||
btrBotService = botsController.BotTradersServices.BTRServices;
|
btrBotService = botsController.BotTradersServices.BTRServices;
|
||||||
var btrControllerType = btrController.GetType();
|
btrController.method_3(); // spawns server-side BTR game object
|
||||||
AccessTools.Method(btrControllerType, "method_3").Invoke(btrController, null); // spawns server-side BTR game object
|
|
||||||
botsController.BotSpawner.SpawnBotBTR(); // spawns the scav bot which controls the BTR's turret
|
botsController.BotSpawner.SpawnBotBTR(); // spawns the scav bot which controls the BTR's turret
|
||||||
|
|
||||||
// Initial BTR configuration
|
// Initial BTR configuration
|
||||||
btrServerSide = btrController.BtrVehicle;
|
btrServerSide = btrController.BtrVehicle;
|
||||||
|
btrServerSide.transform.Find("KillBox").gameObject.AddComponent<BTRRoadKillTrigger>();
|
||||||
btrServerSide.moveSpeed = 20f;
|
btrServerSide.moveSpeed = 20f;
|
||||||
var btrMapConfig = btrController.MapPathsConfiguration;
|
var btrMapConfig = btrController.MapPathsConfiguration;
|
||||||
btrServerSide.CurrentPathConfig = btrMapConfig.PathsConfiguration.pathsConfigurations.RandomElement();
|
btrServerSide.CurrentPathConfig = btrMapConfig.PathsConfiguration.pathsConfigurations.RandomElement();
|
||||||
btrServerSide.Initialization(btrMapConfig);
|
btrServerSide.Initialization(btrMapConfig);
|
||||||
AccessTools.Method(btrControllerType, "method_14").Invoke(btrController, null); // creates and assigns the BTR a fake stash
|
btrController.method_14(); // creates and assigns the BTR a fake stash
|
||||||
|
|
||||||
DisableServerSideRenderers();
|
DisableServerSideRenderers();
|
||||||
|
|
||||||
@ -233,6 +193,47 @@ namespace Aki.Debugging.BTR
|
|||||||
_updateTaxiPriceMethod.Invoke(btrController, new object[] { destinationPoint, isFinal });
|
_updateTaxiPriceMethod.Invoke(btrController, new object[] { destinationPoint, isFinal });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void TraderServicePurchased(ETraderServiceType serviceType)
|
||||||
|
{
|
||||||
|
switch (serviceType)
|
||||||
|
{
|
||||||
|
case ETraderServiceType.BtrBotCover:
|
||||||
|
List<Player> passengers = gameWorld.AllAlivePlayersList.Where(x => x.BtrState == EPlayerBtrState.Inside).ToList();
|
||||||
|
botEventHandler.ApplyTraderServiceBtrSupport(passengers);
|
||||||
|
StartCoverFireTimer(90f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartCoverFireTimer(float time)
|
||||||
|
{
|
||||||
|
_coverFireTimerCoroutine = StaticManager.BeginCoroutine(CoverFireTimer(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator CoverFireTimer(float time)
|
||||||
|
{
|
||||||
|
yield return new WaitForSecondsRealtime(time);
|
||||||
|
botEventHandler.StopTraderServiceBtrSupport();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleBtrDoorState(EPlayerBtrState playerBtrState)
|
||||||
|
{
|
||||||
|
if (previousPlayerBtrState == EPlayerBtrState.Approach && playerBtrState == EPlayerBtrState.GoIn
|
||||||
|
|| previousPlayerBtrState == EPlayerBtrState.Inside && playerBtrState == EPlayerBtrState.GoOut)
|
||||||
|
{
|
||||||
|
// Open Door
|
||||||
|
UpdateBTRSideDoorState(1);
|
||||||
|
}
|
||||||
|
else if (previousPlayerBtrState == EPlayerBtrState.GoIn && playerBtrState == EPlayerBtrState.Inside
|
||||||
|
|| previousPlayerBtrState == EPlayerBtrState.GoOut && playerBtrState == EPlayerBtrState.Outside)
|
||||||
|
{
|
||||||
|
// Close Door
|
||||||
|
UpdateBTRSideDoorState(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
previousPlayerBtrState = playerBtrState;
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateBTRSideDoorState(byte state)
|
private void UpdateBTRSideDoorState(byte state)
|
||||||
{
|
{
|
||||||
var player = gameWorld.MainPlayer;
|
var player = gameWorld.MainPlayer;
|
||||||
@ -243,13 +244,17 @@ namespace Aki.Debugging.BTR
|
|||||||
if (player.BtrInteractionSide != null && btrSides[i] == player.BtrInteractionSide
|
if (player.BtrInteractionSide != null && btrSides[i] == player.BtrInteractionSide
|
||||||
|| lastInteractedBtrSide != null && btrSides[i] == lastInteractedBtrSide)
|
|| lastInteractedBtrSide != null && btrSides[i] == lastInteractedBtrSide)
|
||||||
{
|
{
|
||||||
if (i == 0) btrServerSide.LeftSideState = state;
|
switch (i)
|
||||||
else if (i == 1) btrServerSide.RightSideState = state;
|
|
||||||
|
|
||||||
if (lastInteractedBtrSide != player.BtrInteractionSide)
|
|
||||||
{
|
{
|
||||||
lastInteractedBtrSide = player.BtrInteractionSide;
|
case 0:
|
||||||
|
btrServerSide.LeftSideState = state;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
btrServerSide.RightSideState = state;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lastInteractedBtrSide = player.BtrInteractionSide;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -292,50 +297,64 @@ namespace Aki.Debugging.BTR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsAimingAtTarget()
|
private bool HasTarget()
|
||||||
{
|
{
|
||||||
var turretInDefaultRotation = btrTurretServer.targetTransform == btrTurretDefaultTargetTransform
|
|
||||||
&& btrTurretServer.targetPosition == btrTurretServer.defaultAimingPosition;
|
|
||||||
|
|
||||||
var enemies = btrBotShooter.BotsGroup.Enemies;
|
var enemies = btrBotShooter.BotsGroup.Enemies;
|
||||||
if (enemies.Any())
|
if (enemies.Any())
|
||||||
{
|
{
|
||||||
IPlayer currentTarget = enemies.First().Key;
|
currentTarget = enemies.First().Key;
|
||||||
Transform currentTargetTransform = currentTarget.Transform.Original;
|
|
||||||
Vector3 currentTargetPosition = currentTargetTransform.position;
|
|
||||||
var currentTargetInfo = btrBotShooter.EnemiesController.EnemyInfos[currentTarget];
|
|
||||||
|
|
||||||
if (!currentTarget.HealthController.IsAlive)
|
if (!currentTarget.HealthController.IsAlive)
|
||||||
{
|
{
|
||||||
enemies.Remove(currentTarget);
|
enemies.Remove(currentTarget);
|
||||||
|
currentTarget = null;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsAimingAtTarget()
|
||||||
|
{
|
||||||
|
bool turretInDefaultRotation = btrTurretServer.targetTransform == btrTurretDefaultTargetTransform
|
||||||
|
&& btrTurretServer.targetPosition == btrTurretServer.defaultAimingPosition;
|
||||||
|
|
||||||
|
if (currentTarget != null)
|
||||||
|
{
|
||||||
|
Transform currentTargetTransform = currentTarget.Transform.Original;
|
||||||
|
EnemyInfo currentTargetInfo = btrBotShooter.EnemiesController.EnemyInfos[currentTarget];
|
||||||
|
|
||||||
if (currentTargetInfo.IsVisible)
|
if (currentTargetInfo.IsVisible)
|
||||||
{
|
{
|
||||||
|
Vector3 currentTargetPosition = currentTargetTransform.position;
|
||||||
if (btrTurretServer.CheckPositionInAimingZone(currentTargetPosition))
|
if (btrTurretServer.CheckPositionInAimingZone(currentTargetPosition))
|
||||||
{
|
{
|
||||||
btrTurretServer.EnableAimingObject(currentTargetTransform);
|
// If turret machine gun aim is close enough to target and has line of sight
|
||||||
}
|
if (btrTurretServer.targetTransform == currentTargetTransform && btrBotShooter.BotBtrData.CanShoot())
|
||||||
// If turret machine gun aim is close enough to target and has line of sight
|
{
|
||||||
if (btrBotShooter.BotBtrData.CanShoot())
|
return true;
|
||||||
{
|
}
|
||||||
return true;
|
|
||||||
|
if (btrTurretServer.targetTransform != currentTargetTransform)
|
||||||
|
{
|
||||||
|
btrTurretServer.EnableAimingObject(currentTargetTransform);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!currentTargetInfo.IsVisible)
|
// Turret will hold the angle where target was last seen for 3 seconds before resetting its rotation
|
||||||
|
else if (btrTurretServer.targetPosition != currentTargetInfo.EnemyLastPosition && btrTurretServer.targetTransform != null)
|
||||||
{
|
{
|
||||||
// Turret will hold the angle where target was last seen for 3 seconds before resetting its rotation
|
btrTurretServer.EnableAimingPosition(currentTargetInfo.EnemyLastPosition);
|
||||||
if (btrTurretServer.targetPosition != currentTargetInfo.EnemyLastPosition && btrTurretServer.targetTransform != null)
|
}
|
||||||
{
|
else if (currentTargetInfo.TimeLastSeen >= 3f && !turretInDefaultRotation)
|
||||||
btrTurretServer.EnableAimingPosition(currentTargetInfo.EnemyLastPosition);
|
{
|
||||||
}
|
currentTarget = null;
|
||||||
else if (currentTargetInfo.TimeLastSeen >= 3f && !turretInDefaultRotation)
|
btrTurretServer.DisableAiming();
|
||||||
{
|
|
||||||
btrTurretServer.DisableAiming();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!enemies.Any() && !turretInDefaultRotation)
|
else if (!turretInDefaultRotation)
|
||||||
{
|
{
|
||||||
btrTurretServer.DisableAiming();
|
btrTurretServer.DisableAiming();
|
||||||
}
|
}
|
||||||
@ -351,16 +370,22 @@ namespace Aki.Debugging.BTR
|
|||||||
isShooting = true;
|
isShooting = true;
|
||||||
|
|
||||||
Transform machineGunMuzzle = btrTurretServer.machineGunLaunchPoint;
|
Transform machineGunMuzzle = btrTurretServer.machineGunLaunchPoint;
|
||||||
Player btrBotPlayer = btrBotShooter.GetPlayer;
|
|
||||||
|
|
||||||
gameWorld.SharedBallisticsCalculator.Shoot(btrMachineGunAmmo, machineGunMuzzle.position, machineGunMuzzle.forward, btrBotPlayer.ProfileId, btrMachineGunWeapon, 1f, 0);
|
|
||||||
|
|
||||||
Player.FirearmController firearmController = btrBotShooter.GetComponent<Player.FirearmController>();
|
Player.FirearmController firearmController = btrBotShooter.GetComponent<Player.FirearmController>();
|
||||||
WeaponPrefab weaponPrefab = (WeaponPrefab)AccessTools.Field(firearmController.GetType(), "weaponPrefab_0").GetValue(firearmController);
|
WeaponPrefab weaponPrefab = (WeaponPrefab)AccessTools.Field(firearmController.GetType(), "weaponPrefab_0").GetValue(firearmController);
|
||||||
WeaponSoundPlayer weaponSoundPlayer = weaponPrefab.GetComponent<WeaponSoundPlayer>();
|
WeaponSoundPlayer weaponSoundPlayer = weaponPrefab.GetComponent<WeaponSoundPlayer>();
|
||||||
AccessTools.Method(firearmController.GetType(), "method_54").Invoke(firearmController, new object[] { weaponSoundPlayer, btrMachineGunAmmo, machineGunMuzzle.position, machineGunMuzzle.forward, false });
|
|
||||||
|
|
||||||
yield return new WaitForSecondsRealtime(0.092308f); // 650 RPM
|
int burstCount = Random.Range(5, 8);
|
||||||
|
while (burstCount > 0)
|
||||||
|
{
|
||||||
|
gameWorld.SharedBallisticsCalculator.Shoot(btrMachineGunAmmo, machineGunMuzzle.position, machineGunMuzzle.forward, btrBotShooter.ProfileId, btrMachineGunWeapon, 1f, 0);
|
||||||
|
firearmController.method_54(weaponSoundPlayer, btrMachineGunAmmo, machineGunMuzzle.position, machineGunMuzzle.forward, false);
|
||||||
|
burstCount--;
|
||||||
|
yield return new WaitForSecondsRealtime(0.092308f); // 650 RPM
|
||||||
|
}
|
||||||
|
|
||||||
|
float waitTime = Random.Range(0.8f, 1.7f); // 0.8 - 1.7 second pause between bursts
|
||||||
|
yield return new WaitForSecondsRealtime(waitTime);
|
||||||
|
|
||||||
isShooting = false;
|
isShooting = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,7 +410,13 @@ namespace Aki.Debugging.BTR
|
|||||||
gameWorld.MainPlayer.OnBtrStateChanged -= HandleBtrDoorState;
|
gameWorld.MainPlayer.OnBtrStateChanged -= HandleBtrDoorState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (TraderServicesManager.Instance != null)
|
||||||
|
{
|
||||||
|
TraderServicesManager.Instance.OnTraderServicePurchased -= TraderServicePurchased;
|
||||||
|
}
|
||||||
|
|
||||||
StaticManager.KillCoroutine(ref _shootingTargetCoroutine);
|
StaticManager.KillCoroutine(ref _shootingTargetCoroutine);
|
||||||
|
StaticManager.KillCoroutine(ref _coverFireTimerCoroutine);
|
||||||
Destroy(this);
|
Destroy(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
38
project/Aki.Debugging/BTR/BTRRoadKillTrigger.cs
Normal file
38
project/Aki.Debugging/BTR/BTRRoadKillTrigger.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
using EFT;
|
||||||
|
using EFT.Interactive;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Aki.Debugging.BTR
|
||||||
|
{
|
||||||
|
public class BTRRoadKillTrigger : DamageTrigger
|
||||||
|
{
|
||||||
|
public override bool IsStatic => false;
|
||||||
|
|
||||||
|
public override void AddPenalty(GInterface94 player)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PlaySound()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ProceedDamage(GInterface94 player, BodyPartCollider bodyPart)
|
||||||
|
{
|
||||||
|
bodyPart.ApplyInstantKill(new DamageInfo()
|
||||||
|
{
|
||||||
|
Damage = 9999f,
|
||||||
|
Direction = Vector3.zero,
|
||||||
|
HitCollider = bodyPart.Collider,
|
||||||
|
HitNormal = Vector3.zero,
|
||||||
|
HitPoint = Vector3.zero,
|
||||||
|
DamageType = EDamageType.Btr,
|
||||||
|
HittedBallisticCollider = bodyPart,
|
||||||
|
Player = null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void RemovePenalty(GInterface94 player)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -25,10 +25,9 @@ namespace Aki.Debugging.BTR.Patches
|
|||||||
}
|
}
|
||||||
|
|
||||||
[PatchPostfix]
|
[PatchPostfix]
|
||||||
public static void PatchPostfix(object __instance, int btrBotId, ref bool __result)
|
public static void PatchPostfix(BTRTurretView __instance, int btrBotId, ref bool __result)
|
||||||
{
|
{
|
||||||
var gameWorld = Singleton<GameWorld>.Instance;
|
var gameWorld = Singleton<GameWorld>.Instance;
|
||||||
var btrTurretView = (BTRTurretView)__instance;
|
|
||||||
|
|
||||||
foreach (var playerKeyValue in gameWorld.allAlivePlayersByID)
|
foreach (var playerKeyValue in gameWorld.allAlivePlayersByID)
|
||||||
{
|
{
|
||||||
@ -49,10 +48,7 @@ namespace Aki.Debugging.BTR.Patches
|
|||||||
foreach (var text in currentWeaponPrefab.RemoveChildrenOf)
|
foreach (var text in currentWeaponPrefab.RemoveChildrenOf)
|
||||||
{
|
{
|
||||||
var transform = currentWeaponPrefab.transform.FindTransform(text);
|
var transform = currentWeaponPrefab.transform.FindTransform(text);
|
||||||
if (transform != null)
|
transform?.gameObject.SetActive(false);
|
||||||
{
|
|
||||||
transform.gameObject.SetActive(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (var renderer in currentWeaponPrefab.GetComponentsInChildren<Renderer>())
|
foreach (var renderer in currentWeaponPrefab.GetComponentsInChildren<Renderer>())
|
||||||
@ -68,8 +64,8 @@ namespace Aki.Debugging.BTR.Patches
|
|||||||
}
|
}
|
||||||
|
|
||||||
var tuple = new ValueTuple<ObservedPlayerView, bool>(new ObservedPlayerView(), true);
|
var tuple = new ValueTuple<ObservedPlayerView, bool>(new ObservedPlayerView(), true);
|
||||||
var btrTurretViewTupleField = AccessTools.Field(btrTurretView.GetType(), "valueTuple_0");
|
var btrTurretViewTupleField = AccessTools.Field(__instance.GetType(), "valueTuple_0");
|
||||||
btrTurretViewTupleField.SetValue(btrTurretView, tuple);
|
btrTurretViewTupleField.SetValue(__instance, tuple);
|
||||||
|
|
||||||
__result = true;
|
__result = true;
|
||||||
return;
|
return;
|
||||||
|
@ -4,30 +4,31 @@ using EFT;
|
|||||||
using EFT.Vehicle;
|
using EFT.Vehicle;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using BotEventHandler = GClass595;
|
||||||
|
|
||||||
namespace Aki.Debugging.BTR.Patches
|
namespace Aki.Debugging.BTR.Patches
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Patches an empty method in <see cref="BTRView"/> to handle updating the BTR bot's Neutrals and Enemies lists in response to taking damage.
|
/// Patches an empty method in <see cref="BTRView"/> to handle updating the BTR bot's Neutrals and Enemies lists in response to taking damage.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class BTRReceiveDamageInfoPatch : ModulePatch
|
internal class BTRReceiveDamageInfoPatch : ModulePatch
|
||||||
{
|
{
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
{
|
{
|
||||||
return AccessTools.Method(typeof(BTRView), "method_1");
|
return AccessTools.Method(typeof(BTRView), nameof(BTRView.method_1));
|
||||||
}
|
}
|
||||||
|
|
||||||
[PatchPrefix]
|
[PatchPrefix]
|
||||||
public static void PatchPrefix(DamageInfo damageInfo)
|
private static void PatchPrefix(DamageInfo damageInfo)
|
||||||
{
|
{
|
||||||
var globalEvents = Singleton<GClass595>.Instance;
|
var botEventHandler = Singleton<BotEventHandler>.Instance;
|
||||||
if (globalEvents == null)
|
if (botEventHandler == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var shotBy = (Player)damageInfo.Player.iPlayer;
|
var shotBy = (Player)damageInfo.Player.iPlayer;
|
||||||
globalEvents.InterruptTraderServiceBtrSupportByBetrayer(shotBy);
|
botEventHandler.InterruptTraderServiceBtrSupportByBetrayer(shotBy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,6 @@ namespace Aki.Debugging.BTR.Utils
|
|||||||
public static readonly string BTRMachineGunWeaponTplId = "657857faeff4c850222dff1b"; // BTR PKTM machine gun
|
public static readonly string BTRMachineGunWeaponTplId = "657857faeff4c850222dff1b"; // BTR PKTM machine gun
|
||||||
public static readonly string BTRMachineGunAmmoTplId = "5e023d34e8a400319a28ed44"; // 7.62x54mmR BT
|
public static readonly string BTRMachineGunAmmoTplId = "5e023d34e8a400319a28ed44"; // 7.62x54mmR BT
|
||||||
|
|
||||||
private static FieldInfo _traderAvailableServicesField = AccessTools.Field(typeof(Profile.TraderInfo), "_availableServices");
|
|
||||||
|
|
||||||
static BTRUtil()
|
static BTRUtil()
|
||||||
{
|
{
|
||||||
// Sanity checks for compile time failure in the event the GClass changes
|
// Sanity checks for compile time failure in the event the GClass changes
|
||||||
|
@ -3,6 +3,7 @@ using Comfort.Common;
|
|||||||
using EFT;
|
using EFT;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@ -13,6 +14,8 @@ namespace Aki.SinglePlayer.Utils.TraderServices
|
|||||||
{
|
{
|
||||||
public class TraderServicesManager
|
public class TraderServicesManager
|
||||||
{
|
{
|
||||||
|
public event Action<ETraderServiceType> OnTraderServicePurchased; // Subscribe to this event to trigger trader service logic
|
||||||
|
|
||||||
private static TraderServicesManager _instance;
|
private static TraderServicesManager _instance;
|
||||||
|
|
||||||
public static TraderServicesManager Instance
|
public static TraderServicesManager Instance
|
||||||
@ -146,6 +149,7 @@ namespace Aki.SinglePlayer.Utils.TraderServices
|
|||||||
_servicePurchased[serviceType] = new Dictionary<string, bool>();
|
_servicePurchased[serviceType] = new Dictionary<string, bool>();
|
||||||
_servicePurchased[serviceType][traderId] = true;
|
_servicePurchased[serviceType][traderId] = true;
|
||||||
}
|
}
|
||||||
|
OnTraderServicePurchased.Invoke(serviceType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsServicePurchased(ETraderServiceType serviceType, string traderId)
|
public bool IsServicePurchased(ETraderServiceType serviceType, string traderId)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user