C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using Rust.Ai.HTN.Scientist;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("GameZombieDefence", "stoneharry", "0.0.1")]
class GameZombieDefence : RustPlugin
{
private const string _GameName = "Zombie Defence";
private const string _ConfigFileName = "ZombieDefenceConfig";
private const string _ScarecrowPrefab = "assets/prefabs/npc/scarecrow/scarecrow.prefab";
private const string _MurdererPrefab = "assets/prefabs/npc/murderer/murderer.prefab";
private const string _ScientistPrefab = "assets/prefabs/npc/scientist/scientist.prefab";
private const string _TankPrefab = "assets/prefabs/npc/m2bradley/bradleyapc.prefab";
[PluginReference]
Plugin ScoreBoard;
[PluginReference]
Plugin GameDefenceCui;
[PluginReference]
Plugin Kits;
[PluginReference]
Plugin GrapeGameManager;
private GameConfig _Config = null;
private Timer _GameUpdater = null;
private System.Random _Random = new System.Random();
private const float _ScoreboardUpdateRate = 3f;
private const float _TimeAndObjectiveUpdateRate = 0.9f;
private const float _ItemDespawnTime = 60 * 5;
private Timer _ScoreboardTicker;
private Timer _TimeAndObjectiveTicker;
private RunningGameData _GameData;
private enum GAME_STATE
{
WAITING_FOR_PLAYERS,
COUNTDOWN_WAVE,
RUNNING_WAVE,
TANK_BOSS_1,
PLAYERS_WIN,
ALL_PLAYERS_DEAD
}
#region DebugCommands
[ChatCommand("add")]
void AddCommand(BasePlayer player, string command, string[] args)
{
if (player.IsAdmin)
{
player.ChatMessage("Adding item");
player.GiveItem(ItemManager.CreateByName(args[0], 1, ulong.Parse(args[1])));
}
}
[ChatCommand("wave")]
void WaveCommand(BasePlayer player, string command, string[] args)
{
if (player.IsAdmin)
{
bool worked = _GameData.DebugState(int.Parse(args[0]));
player.ChatMessage($"Setting wave to { args[0] } { (worked ? "worked" : "failed") }");
}
}
[ChatCommand("delete")]
void deletesphere(BasePlayer player, string command, string[] args)
{
if (!player.IsAdmin)
return;
if (args.Length < 1)
{
RaycastHit hit;
BaseEntity sphere = null;
if (Physics.Raycast(player.eyes.HeadRay(), out hit, 20f))
sphere = hit.transform.GetComponentInParent<BaseEntity>();
if (sphere != null)
{
player.SendConsoleCommand("chat.add", 0, "worked " + sphere, 1f);
sphere.Kill();
}
else
{
player.SendConsoleCommand("chat.add", 0, "targeting: " + hit.GetEntity() + "\n" + hit.GetCollider() + "\n" + hit.GetRigidbody(), 1f);
}
return;
}
}
#endregion
#region GamePublicAPI_ForGameManager
bool AddPlayer(BasePlayer player)
{
if (FindPlayerByUserId(player.userID) != null)
{
Puts($"Failed to add player [{player.displayName}] to [{_GameName}], already in game");
return false;
}
Puts($"Adding player [{player.displayName}] to game [{_GameName}]");
_GameData.Players.Add(new GamePlayer(player));
InitialiseGamePlayer(player);
Puts($"New player count: {_GameData.Players.Count}");
return true;
}
bool RemovePlayer(BasePlayer player)
{
var toRemove = FindPlayerByUserId(player.userID);
if (toRemove != null)
{
Puts($"Removing player [{player.displayName}] from game [{_GameName}]");
toRemove.SendHome();
bool removed = _GameData.Players.Remove(toRemove);
CuiHelper.DestroyUi(player, ScoreboardPrefix + _GameName);
GameDefenceCui?.Call("DestroyGUIExternal", player);
return removed;
}
return false;
}
void Unload()
{
// Loop on players without having a lock on the Players list so it can be modified
while (_GameData.Players.Count > 0)
{
GrapeGameManager?.Call("PlayerRemovedFromGameHook", _GameData.Players[0].Entity);
RemovePlayer(_GameData.Players[0].Entity);
}
_GameData.NPCPlayers.ForEach((entity) => entity.Kill());
_GameData.NPCPlayers.Clear();
}
#endregion
#region Hooks
void OnPluginLoaded(Plugin name)
{
if (!name.Name.Equals("GameZombieDefence"))
return;
LoadConfigFile();
WriteConfig();
_GameData = new RunningGameData(new WaveConfiguration(), _Config);
_GameUpdater?.Destroy();
_GameUpdater = timer.Every(1f, () => GameUpdate());
_ScoreboardTicker?.Destroy();
_ScoreboardTicker = timer.Every(_ScoreboardUpdateRate, () => UpdateScoreboard());
_TimeAndObjectiveTicker?.Destroy();
_TimeAndObjectiveTicker = timer.Every(_TimeAndObjectiveUpdateRate, () => UpdateTimeAndObjective());
}
bool? OnPlayerDie(BasePlayer player, HitInfo info)
{
var gamePlayer = FindPlayerByUserId(player.userID);
if (gamePlayer != null)
{
// Only count a death if not already wounded
if (!player.IsWounded())
{
gamePlayer.AddDeath();
}
player.StartWounded();
player.ProlongWounding(60 * 10);
return true;
}
return null;
}
object OnPlayerRespawn(BasePlayer player)
{
var gamePlayer = FindPlayerByUserId(player.userID);
if (gamePlayer != null)
{
InitialiseGamePlayer(player);
return new BasePlayer.SpawnPoint()
{
pos = _Config.GetSpawnPosition(),
rot = new Quaternion(0, 0, 0, 1)
};
}
return null;
}
private void OnEntitySpawned(BaseEntity spawned)
{
HandleNpcLootChange(spawned);
}
void OnEntityDeath(BaseCombatEntity entity, HitInfo info)
{
if (entity != null && (entity is NPCPlayer || entity is HTNPlayer) && info.Initiator != null && info.Initiator is BasePlayer)
{
var player = info.Initiator.ToPlayer();
var gamePlayer = FindPlayerByUserId(player.userID);
if (gamePlayer != null)
{
gamePlayer.AddKill();
}
var data = entity.GetComponent<ZombieData>();
if (data != null && data.MinScrap > 0 && data.MaxScrap > 0)
{
var item = ItemManager.CreateByName("scrap", UnityEngine.Random.Range(data.MinScrap, data.MaxScrap));
if (item != null)
{
var velocity = entity.GetComponent<Rigidbody>()?.velocity;
item.Drop(entity.transform.position + new Vector3(0, 0.25f, 0), velocity ?? Vector3.zero);
timer.Once(_ItemDespawnTime, () => item?.RemoveFromWorld());
}
}
}
}
object OnNpcPlayerTarget(NPCPlayerApex npcPlayer, BaseEntity entity)
{
if (npcPlayer == null || entity == null)
return null;
return CanZombieTarget(entity);
}
object CanBradleyApcTarget(BradleyAPC apc, BaseEntity entity)
{
if (entity == null || apc == null)
return null;
return CanZombieTarget(entity);
}
object CanZombieTarget(BaseEntity entity)
{
var isNpc = (entity is HTNPlayer) || (entity is NPCPlayer) || (entity is Scientist);
if (isNpc)
return true;
if (entity is BasePlayer)
{
if (entity.ToPlayer().IsWounded())
return true;
}
return null;
}
bool? OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
{
// Reflect friendly damage
if (entity is BasePlayer && info.Initiator != null && info.Initiator is BasePlayer)
{
var attacked = (BasePlayer)entity;
var initiator = (BasePlayer)info.Initiator;
if (attacked.userID == initiator.userID)
{
return null;
}
var attackedGamePlayer = FindPlayerByUserId(attacked.userID);
var initiatorGamePlayer = FindPlayerByUserId(initiator.userID);
if (attackedGamePlayer != null && initiatorGamePlayer != null)
{
initiator.Hurt(info);
}
}
{
// Override scientists damge and accuracy to players
var initiator = info?.Initiator;
if (initiator != null && initiator is Scientist && entity is BasePlayer)
{
var data = initiator.GetComponent<ZombieData>();
if (data != null)
{
int rand = UnityEngine.Random.Range(1, 100);
float distance = Vector3.Distance(info.Initiator.transform.position, entity.transform.position);
var newAccuracy = data.Accuracy;
var newDamage = data.Damage;
if (distance > 100f)
{
newAccuracy = data.Accuracy / (distance / 100f);
newDamage = data.Damage / (distance / 100f);
}
//Puts("New damage & new accuracy: " + newDamage + ", " + newAccuracy + ", RAND: " + rand);
if (((int)newAccuracy) < rand)
return true;
info.damageTypes.ScaleAll(newDamage);
}
}
}
{
// Handle tank boss
if (entity is BradleyAPC && info.Initiator != null && info.Initiator.ToPlayer() != null && _GameData.NPCPlayers.Contains(entity))
{
//info.Initiator.ToPlayer().ChatMessage("Damage dealt to tank before: " + info.damageTypes.Total());
info.damageTypes.ScaleAll(info.damageTypes.IsMeleeType() ? 10f : 1000f);
//info.Initiator.ToPlayer().ChatMessage("Damage dealt to tank after : " + info.damageTypes.Total());
if (info.damageTypes.Total() >= entity.health)
{
var position = entity.transform.position;
// Handle tank death
var gibs = entity.GetComponent<TankController>().OnDeath();
// Clear fireballs and then gibs after timers
timer.Once(30f, () =>
{
var fires = new List<FireBall>();
Vis.Entities(position, 20f, fires);
fires.ForEach((fire) => fire.Kill());
});
timer.Once(60f, () => gibs.ForEach((gib) => gib.Kill()));
return true;
}
}
}
return null;
}
void OnPlayerDropActiveItem(BasePlayer player, Item item)
{
timer.Once(_ItemDespawnTime, () => item?.RemoveFromWorld());
}
#endregion
#region GameLogic
private void HandleNpcLootChange(BaseEntity spawned)
{
if (spawned == null)
{
return;
}
if (spawned is NPCPlayerCorpse)
{
var corpse = spawned as NPCPlayerCorpse;
corpse.ResetRemovalTime(30f);
NextTick(() =>
{
if (corpse == null || corpse.containers == null)
return;
List<Item> toDestroy = new List<Item>();
foreach (var item in corpse.containers[0].itemList)
toDestroy.Add(item);
foreach (var item in toDestroy)
item?.RemoveFromContainer();
corpse.containers[0].Clear();
corpse.containers[1].Clear();
corpse.containers[2].Clear();
});
}
}
private GamePlayer FindPlayerByUserId(ulong userId)
{
return _GameData.Players.Find((player) => player.Entity.userID == userId);
}
private void InitialiseGamePlayer(BasePlayer player)
{
NextTick(() =>
{
player.Teleport(_Config.GetSpawnPosition());
player.inventory.Strip();
player.StopWounded();
player.metabolism.Reset();
player.metabolism.calories.SetValue(player.metabolism.calories.max);
player.metabolism.hydration.SetValue(player.metabolism.hydration.max);
player.ChangeHealth(player.MaxHealth());
player.inventory.Strip();
plugins.Find("Kits")?.Call("GiveKit", player, _Config.StartingKitName);
});
}
private bool DestroyEmptyGame()
{
if (_GameData.Players.Count == 0)
{
_GameData.Reset();
return true;
}
return false;
}
private void GameUpdate()
{
// Remove any murderers from list that are dead or destroyed
_GameData.NPCPlayers.RemoveAll((murderer) =>
murderer == null ||
murderer.IsDestroyed ||
(murderer is NPCPlayer && ((NPCPlayer)murderer).IsDead()) ||
(murderer is HTNPlayer && ((HTNPlayer)murderer).IsDead()));
if (DestroyEmptyGame())
{
return;
}
switch (_GameData.State)
{
case GAME_STATE.WAITING_FOR_PLAYERS:
HandleWaitingForPlayers();
break;
case GAME_STATE.COUNTDOWN_WAVE:
HandleCountdownWave();
break;
case GAME_STATE.RUNNING_WAVE:
HandleRunningWave();
break;
case GAME_STATE.ALL_PLAYERS_DEAD:
HandleAllPlayersDead();
break;
case GAME_STATE.PLAYERS_WIN:
HandlePlayersWin();
break;
default:
Puts("ERROR: Unknown state: " + _GameData.State);
break;
}
}
private void HandleWaitingForPlayers()
{
if (_GameData.Players.Count >= _Config.RequiredPlayercount)
{
_GameData.State = GAME_STATE.COUNTDOWN_WAVE;
}
}
private void HandleCountdownWave()
{
if (_GameData.Waiting)
{
var wave = _GameData.WaveSpawnList();
var diff = DateTime.Now - _GameData.TimeWaitingFrom;
if (diff.TotalSeconds >= wave.SecondsUntilNextWave)
{
_GameData.State = GAME_STATE.RUNNING_WAVE;
_GameData.Waiting = false;
}
return;
}
_GameData.Waiting = true;
_GameData.TimeWaitingFrom = DateTime.Now;
}
private void HandleAllPlayersDead()
{
if (_GameData.Waiting)
{
var diff = DateTime.Now - _GameData.TimeWaitingFrom;
if (diff.TotalSeconds >= 10D)
{
while (_GameData.Players.Count > 0)
{
GrapeGameManager?.Call("PlayerRemovedFromGameHook", _GameData.Players[0].Entity);
RemovePlayer(_GameData.Players[0].Entity);
}
_GameData.Reset();
}
return;
}
_GameData.Waiting = true;
_GameData.TimeWaitingFrom = DateTime.Now;
}
private void HandlePlayersWin()
{
if (_GameData.Waiting)
{
var diff = DateTime.Now - _GameData.TimeWaitingFrom;
if (diff.TotalSeconds >= 10D)
{
while (_GameData.Players.Count > 0)
{
GrapeGameManager?.Call("PlayerRemovedFromGameHook", _GameData.Players[0].Entity);
RemovePlayer(_GameData.Players[0].Entity);
}
_GameData.Reset();
}
return;
}
_GameData.Waiting = true;
_GameData.TimeWaitingFrom = DateTime.Now;
}
#region RunningWaveAndSpawningLogic
private void HandleRunningWave()
{
if (_GameData.Waiting)
{
SpawnRemainingWaveToMaxCount();
if (_GameData.NPCPlayers.Count == 0)
{
_GameData.RewardWave();
_GameData.State = GAME_STATE.COUNTDOWN_WAVE;
_GameData.IncrementWave();
_GameData.Waiting = false;
_GameData.Players.ForEach((player) => player.ResetStats());
}
// If all players are wounded end the game
else if (_GameData.Players.Find((player) => player.Entity != null && !player.Entity.IsWounded()) == null)
{
_GameData.State = GAME_STATE.ALL_PLAYERS_DEAD;
_GameData.Waiting = false;
}
return;
}
_GameData.Waiting = true;
SpawnWaveToMaxCount();
}
private void SpawnWaveToMaxCount()
{
var wave = _GameData.WaveSpawnList();
var numPlayers = _GameData.Players.Count;
var maxSpawn = wave.MaxSpawnAmount;
var currentCount = _GameData.NPCPlayers.Count;
var spawnLaterData = new List<SpawnLaterData>();
foreach (var spawn in wave.Spawns)
{
var numberToSpawn = numPlayers * spawn.Amount;
for (int i = 0; i < numberToSpawn; ++i)
{
var location = spawn.SpawnLocations[UnityEngine.Random.Range(0, spawn.SpawnLocations.Count)];
// Handle special waves
if (spawn.State != GAME_STATE.RUNNING_WAVE)
{
if (HandleCustomWaveState(spawn, location))
continue;
}
// If we have hit the maximum amount that can be spawned at a single time, save the data for later
if (++currentCount >= maxSpawn)
{
spawnLaterData.Add(new SpawnLaterData
{
Location = location,
Prefab = spawn.Prefab,
Health = spawn.Health,
DisplayName = spawn.DisplayName,
MinScrap = spawn.MinScrap,
MaxScrap = spawn.MaxScrap,
Kit = spawn.Kit,
Damage = spawn.Damage,
Accuracy = spawn.Accuracy
});
}
else
{
SpawnZombie(spawn.Prefab, spawn.Health, location,
spawn.DisplayName, spawn.MinScrap, spawn.MaxScrap,
spawn.Kit, spawn.Damage, spawn.Accuracy);
}
}
}
_GameData.SpawnLaterData = spawnLaterData;
}
private bool HandleCustomWaveState(WaveConfiguration.WaveSpawn spawn, Vector3 location)
{
if (spawn.State == GAME_STATE.TANK_BOSS_1)
{
/*_GameData.Players.ForEach((player) =>
{
if (player.Entity == null)
return;
player.Entity.GiveItem(ItemManager.CreateByName("rocket.launcher", 1, 853494512));
player.Entity.GiveItem(ItemManager.CreateByName("ammo.rocket.basic", 4));
player.Entity.ChatMessage("You have been given a rocket launcher!");
});*/
SpawnTankBoss(spawn, location);
return true;
}
return false;
}
private void SpawnRemainingWaveToMaxCount()
{
var maxSpawn = _GameData.WaveSpawnList().MaxSpawnAmount;
var currentCount = _GameData.NPCPlayers.Count;
// Loop without having a handle on the data
while (_GameData.SpawnLaterData.Count > 0)
{
if (currentCount++ >= maxSpawn)
{
break;
}
var data = _GameData.SpawnLaterData[0];
SpawnZombie(data.Prefab, data.Health, data.Location,
data.DisplayName, data.MinScrap, data.MaxScrap,
data.Kit, data.Damage, data.Accuracy);
_GameData.SpawnLaterData.RemoveAt(0);
}
}
private class SpawnLaterData
{
public Vector3 Location;
public string Prefab;
public float Health;
public string DisplayName;
public int MinScrap;
public int MaxScrap;
public string Kit;
public float Damage;
public float Accuracy;
}
#endregion
private void SpawnZombie(string prefab, float health, Vector3 spawnLocation, string displayName = "Zombie",
int minScrap = 0, int maxScrap = 0, string kit = null, float damage = 0.25f, float accuracy = 1f)
{
Puts("Spawning: " + prefab);
var entity = GameManager.server.CreateEntity(prefab, spawnLocation, Quaternion.identity, false);
if (entity != null)
{
entity.enableSaving = false;
entity.gameObject.AwakeFromInstantiate();
entity.Spawn();
if (entity is BasePlayer)
{
var plr = (BasePlayer)entity;
plr.displayName = displayName;
var data = plr.gameObject.AddComponent<ZombieData>();
data.MinScrap = minScrap;
data.MaxScrap = maxScrap;
var npcAgex = entity.GetComponent<NPCPlayerApex>();
if (npcAgex)
{
npcAgex.Stats.AggressionRange = 200f;
npcAgex.Stats.VisionRange = 200f;
npcAgex.ChangeHealth(health);
npcAgex.startHealth = health;
npcAgex._maxHealth = health;
npcAgex.Stats.Hostility = 1f;
// Disable radio
npcAgex.RadioEffect = new GameObjectRef();
// Move to random players position constantly
if (plr is Scientist)
{
data.Damage = damage;
data.Accuracy = accuracy;
}
}
if (kit != null)
{
plr.inventory.Strip();
Kits?.Call("GiveKit", entity, kit);
}
if (entity is NPCPlayer || entity is NPCMurderer)
{
Timer _npcTimer = null;
_npcTimer = timer.Every(5f, () =>
{
if (plr == null || plr.IsDead())
{
_npcTimer.Destroy();
return;
}
var randomPlayer = _GameData.Players.Count == 0 ? null :
_GameData.Players[UnityEngine.Random.Range(0, _GameData.Players.Count)];
NPCPlayer scientist = entity as NPCPlayer;
NPCMurderer murderer = entity as NPCMurderer;
if (randomPlayer != null && scientist != null && scientist.NavAgent.isOnNavMesh)
{
scientist.NavAgent.SetDestination(randomPlayer.Entity.transform.position);
}
else if (randomPlayer != null && murderer != null && murderer.NavAgent.isOnNavMesh)
{
murderer.NavAgent.SetDestination(randomPlayer.Entity.transform.position);
}
});
}
}
else if (entity is HTNPlayer)
{
var plr = (HTNPlayer)entity;
plr.AiDomain.Movement = Rust.Ai.HTN.HTNDomain.MovementRule.FreeMove;
plr.AiDomain.MovementRadius = 300f;
plr.health = health;
plr._maxHealth = health;
plr.startHealth = health;
plr.displayName = displayName;
plr.AiDefinition.Engagement.AggroRange = 200f;
plr.AiDefinition.Sensory.VisionRange = 200f;
if (kit != null)
{
plr.inventory.Strip();
Kits?.Call("GiveKit", entity, kit);
}
}
_GameData.NPCPlayers.Add(entity);
}
}
public HashSet<ulong> GetUserIds()
{
var userIds = new HashSet<ulong>();
foreach (var player in _GameData.Players)
{
userIds.Add(player.UserID);
}
return userIds;
}
#endregion
#region TankBoss
private void SpawnTankBoss(WaveConfiguration.WaveSpawn spawn, Vector3 location)
{
Puts("Spawning: " + spawn.Prefab);
var entity = GameManager.server.CreateEntity(spawn.Prefab, location, Quaternion.identity, false);
if (entity != null)
{
entity.enableSaving = false;
entity.gameObject.AwakeFromInstantiate();
entity.Spawn();
if (entity is BradleyAPC)
{
var tank = entity as BradleyAPC;
var health = spawn.Health * _GameData.Players.Count;
tank.InitializeHealth(health, health);
var controller = tank.gameObject.AddComponent<TankController>();
controller.MinScrapPerBox = spawn.MinScrap;
controller.MaxScrapPerBox = spawn.MaxScrap;
controller.ScrapScaling = _GameData.Players.Count;
}
_GameData.NPCPlayers.Add(entity);
}
}
private class TankController : MonoBehaviour
{
private BradleyAPC entity;
private TankWaypointController waypointController;
private float MainGunMinDistance = 7f;
private int MainGunShots = 1;
private int GattlingGunShots = 8;
private float MainGunCooldown = 3f;
private float GattlingCooldown = 5f;
private float gattlingFireRate = 0.06667f;
private float mainGunFireRate = 0.25f;
private int numMainGunFired;
private int numGattlingFired;
private float nextGattlingFireTime;
private float nextMainGunFireTime;
public int MinScrapPerBox = 12;
public int MaxScrapPerBox = 24;
public float ScrapScaling = 1f;
public int NumLootBoxes = 10;
private float lastLateUpdate;
private Vector3 desiredTopTurretAimVector = Vector3.forward;
private Vector3 desiredAimVector = Vector3.forward;
private float currentSpeedZoneLimit;
private BaseCombatEntity mainGunTarget;
private void Awake()
{
entity = GetComponent<BradleyAPC>();
// Disable normal tank AI
entity.enabled = false;
//entity.CancelInvoke(entity.UpdateTargetList);
//entity.CancelInvoke(entity.UpdateTargetVisibilities);
waypointController = new TankWaypointController();
}
public void FixedUpdate()
{
DoSimpleAI();
DoPhysicsMove();
DoWeapons();
entity.SendNetworkUpdate(BasePlayer.NetworkQueue.Update);
}
public void LateUpdate()
{
float single = Time.time - lastLateUpdate;
lastLateUpdate = Time.time;
if (!entity.isServer)
{
entity.turretAimVector = Vector3.Lerp(entity.turretAimVector, desiredAimVector, Time.deltaTime * 10f);
}
else
{
float single1 = 2.09439516f;
entity.turretAimVector = Vector3.RotateTowards(entity.turretAimVector, desiredAimVector, single1 * single, 0f);
}
entity.AimWeaponAt(entity.mainTurret, entity.coaxPitch, entity.turretAimVector, -90f, 90f, 360f, null);
entity.AimWeaponAt(entity.mainTurret, entity.CannonPitch, entity.turretAimVector, -90f, 7f, 360f, null);
entity.topTurretAimVector = Vector3.Lerp(entity.topTurretAimVector, desiredTopTurretAimVector, Time.deltaTime * 5f);
entity.AimWeaponAt(entity.topTurretYaw, entity.topTurretPitch, entity.topTurretAimVector, -360f, 360f, 360f, entity.mainTurret);
}
public void DoSimpleAI()
{
if (entity.isClient)
{
return;
}
entity.SetFlag(BaseEntity.Flags.Reserved5, TOD_Sky.Instance.IsNight, false, true);
if (entity.targetList.Count > 0)
{
if (!entity.targetList[0].IsValid() || !entity.targetList[0].IsVisible())
{
mainGunTarget = null;
}
else
{
mainGunTarget = entity.targetList[0].entity as BaseCombatEntity;
}
entity.UpdateMovement_Hunt();
}
var destination = waypointController.UpdateAndGetDestination(entity);
entity.SetDestination(destination);
float single = Vector3.Distance(entity.transform.position, entity.destination);
float single1 = Vector3.Distance(entity.transform.position, mainGunTarget != null ? mainGunTarget.transform.position : destination);
if (single > entity.stoppingDist)
{
Vector3 vector3 = BradleyAPC.Direction2D(entity.destination, entity.transform.position);
float single2 = Vector3.Dot(vector3, entity.transform.right);
float single3 = Vector3.Dot(vector3, entity.transform.right);
float single4 = Vector3.Dot(vector3, -entity.transform.right);
if (Vector3.Dot(vector3, -entity.transform.forward) <= single2)
{
entity.turning = Mathf.Clamp(single2 * 3f, -1f, 1f);
}
else if (single3 < single4)
{
entity.turning = -1f;
}
else
{
entity.turning = 1f;
}
float single5 = 1f - Mathf.InverseLerp(0f, 0.3f, Mathf.Abs(entity.turning));
float single6 = Mathf.InverseLerp(0.1f, 0.4f, Vector3.Dot(entity.transform.forward, Vector3.up));
entity.throttle = (0.1f + Mathf.InverseLerp(0f, 20f, single1) * 1f) * single5 + single6;
}
DoWeaponAiming();
}
public void DoWeaponAiming()
{
Vector3 aimPoint;
Vector3 vector3;
Vector3 vector31;
var target = entity.targetList.Count > 0 ? entity.targetList[0].entity as BaseCombatEntity : null;
if (target != null)
{
aimPoint = entity.GetAimPoint(target) - entity.mainTurretEyePos.transform.position;
vector3 = aimPoint.normalized;
}
else
{
vector3 = desiredAimVector;
}
desiredAimVector = vector3;
BaseEntity item = null;
if (entity.targetList.Count > 0)
{
if (entity.targetList.Count > 1 && entity.targetList[1].IsValid() && entity.targetList[1].IsVisible())
{
item = entity.targetList[1].entity;
}
else if (entity.targetList[0].IsValid() && entity.targetList[0].IsVisible())
{
item = entity.targetList[0].entity;
}
}
if (item != null)
{
aimPoint = entity.GetAimPoint(item) - entity.topTurretEyePos.transform.position;
vector31 = aimPoint.normalized;
}
else
{
vector31 = transform.forward;
}
desiredTopTurretAimVector = vector31;
entity.SendNetworkUpdate(BasePlayer.NetworkQueue.Update);
}
public void DoPhysicsMove()
{
if (entity.isClient)
{
return;
}
Vector3 vector3 = entity.myRigidBody.velocity;
entity.throttle = Mathf.Clamp(entity.throttle, -1f, 1f);
entity.leftThrottle = entity.throttle;
entity.rightThrottle = entity.throttle;
if (entity.turning > 0f)
{
entity.rightThrottle = -entity.turning;
entity.leftThrottle = entity.turning;
}
else if (entity.turning < 0f)
{
entity.leftThrottle = entity.turning;
entity.rightThrottle = entity.turning * -1f;
}
float single = Vector3.Distance(entity.transform.position, entity.GetFinalDestination());
float single1 = Vector3.Distance(entity.transform.position, entity.GetCurrentPathDestination());
float single2 = 15f;
if (single1 < 20f)
{
float single3 = Vector3.Dot(entity.PathDirection(entity.currentPathIndex), entity.PathDirection(entity.currentPathIndex + 1));
float single4 = Mathf.InverseLerp(2f, 10f, single1);
float single5 = Mathf.InverseLerp(0.5f, 0.8f, single3);
single2 = 15f - 14f * ((1f - single5) * (1f - single4));
}
if (entity.patrolPath != null)
{
float single6 = single2;
foreach (PathSpeedZone speedZone in entity.patrolPath.speedZones)
{
if (!speedZone.WorldSpaceBounds().Contains(entity.transform.position))
{
continue;
}
single6 = Mathf.Min(single6, speedZone.GetMaxSpeed());
}
currentSpeedZoneLimit = Mathf.Lerp(currentSpeedZoneLimit, single6, Time.deltaTime);
single2 = Mathf.Min(single2, currentSpeedZoneLimit);
}
if (entity.PathComplete())
{
single2 = 0f;
}
//if (Global.developer > 1)
//{
// Debug.Log(string.Concat(new object[] { "velocity:", vector3.magnitude, "max : ", single2 }));
//}
entity.brake = vector3.magnitude >= single2;
entity.ApplyBrakes((entity.brake ? 1f : 0f));
float single7 = entity.throttle;
entity.leftThrottle = Mathf.Clamp(entity.leftThrottle + single7, -1f, 1f);
entity.rightThrottle = Mathf.Clamp(entity.rightThrottle + single7, -1f, 1f);
float single8 = Mathf.InverseLerp(2f, 1f, vector3.magnitude * Mathf.Abs(Vector3.Dot(vector3.normalized, entity.transform.forward)));
float single9 = Mathf.Lerp(entity.moveForceMax, entity.turnForce, single8);
float single10 = Mathf.InverseLerp(5f, 1.5f, vector3.magnitude * Mathf.Abs(Vector3.Dot(vector3.normalized, entity.transform.forward)));
entity.ScaleSidewaysFriction(1f - single10);
entity.SetMotorTorque(entity.leftThrottle, false, single9);
entity.SetMotorTorque(entity.rightThrottle, true, single9);
entity.impactDamager.damageEnabled = entity.myRigidBody.velocity.magnitude > 2f;
}
public void DoWeapons()
{
// Find target
BaseCombatEntity target = null;
foreach (var possibleEntity in entity.targetList)
{
var possibleTarget = possibleEntity.entity.ToPlayer();
// Skip wounded players
if (possibleTarget != null && possibleTarget.IsWounded())
{
continue;
}
target = possibleTarget;
break;
}
// If no players try to target a npc
if (target == null && entity.targetList.Count > 0)
{
target = entity.targetList[0].entity as BaseCombatEntity;
}
if (target == null)
{
return;
}
// Fire all weapons
if (Vector3.Dot(entity.turretAimVector, (entity.GetAimPoint(target) - entity.mainTurretEyePos.transform.position).normalized) >= 0.99f)
{
bool flag = entity.VisibilityTest(target);
float single = Vector3.Distance(target.transform.position, entity.transform.position);
if (Time.time > nextGattlingFireTime & flag && single <= 40f)
{
numGattlingFired++;
entity.FireGun(entity.GetAimPoint(target), 3f, true);
nextGattlingFireTime = Time.time + gattlingFireRate;
if (numGattlingFired >= GattlingGunShots)
{
nextGattlingFireTime = Time.time + GattlingCooldown;
numGattlingFired = 0;
}
}
if (single >= MainGunMinDistance & flag)
{
FireGunTest();
}
}
}
public void FireGunTest()
{
if (Time.time < nextMainGunFireTime)
{
return;
}
nextMainGunFireTime = Time.time + mainGunFireRate;
numMainGunFired++;
if (numMainGunFired >= MainGunShots)
{
nextMainGunFireTime = Time.time + MainGunCooldown;
numMainGunFired = 0;
}
Vector3 modifiedAimConeDirection = AimConeUtil.GetModifiedAimConeDirection(2f, entity.CannonMuzzle.rotation * Vector3.forward, true);
Vector3 cannonPitch = (entity.CannonPitch.transform.rotation * Vector3.back) + (entity.transform.up * -1f);
Vector3 vector3 = cannonPitch.normalized;
entity.myRigidBody.AddForceAtPosition(vector3 * entity.recoilScale, entity.CannonPitch.transform.position, ForceMode.Impulse);
Effect.server.Run(entity.mainCannonMuzzleFlash.resourcePath, entity, StringPool.Get(entity.CannonMuzzle.gameObject.name), Vector3.zero, Vector3.zero, null, false);
BaseEntity baseEntity = GameManager.server.CreateEntity(entity.mainCannonProjectile.resourcePath, entity.CannonMuzzle.transform.position, Quaternion.LookRotation(modifiedAimConeDirection), true);
if (baseEntity == null)
{
return;
}
ServerProjectile component = baseEntity.GetComponent<ServerProjectile>();
if (component)
{
component.InitializeVelocity(modifiedAimConeDirection * component.speed);
}
baseEntity.Spawn();
}
public List<ServerGib> OnDeath()
{
int minScrap = (int)(MinScrapPerBox * ScrapScaling);
int maxScrap = (int)(MaxScrapPerBox * ScrapScaling);
// Spawn loot boxes
for (int i = 0; i < NumLootBoxes; i++)
{
Vector3 onSphere = UnityEngine.Random.onUnitSphere;
BaseEntity lootCrate = GameManager.server.CreateEntity(entity.crateToDrop.resourcePath,
(entity.transform.position + new Vector3(0f, 1.5f, 0f)) + (onSphere * UnityEngine.Random.Range(2f, 3f)),
Quaternion.LookRotation(onSphere), true);
lootCrate.Spawn();
LootContainer lootContainer = lootCrate as LootContainer;
if (lootContainer)
{
lootContainer.inventory.itemList.Clear();
Item newItem = ItemManager.CreateByName("scrap", UnityEngine.Random.Range(minScrap, maxScrap));
newItem.MoveToContainer(lootContainer.inventory);
lootContainer.Invoke(new Action(lootContainer.RemoveMe), 120f);
}
Collider collider = lootCrate.GetComponent<Collider>();
Rigidbody rigidbody = lootCrate.gameObject.AddComponent<Rigidbody>();
rigidbody.useGravity = true;
rigidbody.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
rigidbody.mass = 2f;
rigidbody.interpolation = RigidbodyInterpolation.Interpolate;
rigidbody.velocity = Vector3.zero + (onSphere * UnityEngine.Random.Range(1f, 3f));
rigidbody.angularVelocity = Vector3Ex.Range(-1.75f, 1.75f);
rigidbody.drag = 0.5f * (rigidbody.mass / 5f);
rigidbody.angularDrag = 0.2f * (rigidbody.mass / 5f);
// fire on loot boxes
/*FireBall fireBall = GameManager.server.CreateEntity(entity.fireBall.resourcePath, lootCrate.transform.position, new Quaternion(), true) as FireBall;
if (fireBall)
{
fireBall.transform.position = lootCrate.transform.position;
fireBall.Spawn();
fireBall.GetComponent<Rigidbody>().isKinematic = true;
fireBall.GetComponent<Collider>().enabled = false;
fireBall.transform.parent = lootCrate.transform;
}
lootCrate.SendMessage("SetLockingEnt", fireBall.gameObject, SendMessageOptions.DontRequireReceiver);*/
}
// Spawn death effects (fire, body, debris) then destroy entity
Effect.server.Run(entity.explosionEffect.resourcePath, entity.transform.position, Vector3.up, null, true);
List<ServerGib> serverGibs = ServerGib.CreateGibs(entity.servergibs.resourcePath, entity.gameObject, entity.servergibs.Get().GetComponent<ServerGib>()._gibSource, Vector3.zero, 3f);
for (int i = 0; i < 12 - entity.maxCratesToSpawn; i++)
{
BaseEntity fireBall = GameManager.server.CreateEntity(entity.fireBall.resourcePath, entity.transform.position, entity.transform.rotation, true);
if (fireBall)
{
Vector3 onSphere = UnityEngine.Random.onUnitSphere;
fireBall.transform.position = (entity.transform.position + new Vector3(0f, 1.5f, 0f)) + (onSphere * UnityEngine.Random.Range(-4f, 4f));
Collider collider = fireBall.GetComponent<Collider>();
fireBall.Spawn();
fireBall.SetVelocity(Vector3.zero + (onSphere * UnityEngine.Random.Range(3, 10)));
foreach (ServerGib serverGib in serverGibs)
Physics.IgnoreCollision(collider, serverGib.GetCollider(), true);
}
}
if (entity != null && !entity.IsDestroyed)
entity.Kill(BaseNetworkable.DestroyMode.Gib);
return serverGibs;
}
}
#endregion
#region TankWaypointController
private class TankWaypointController
{
private int WaypointIndex;
private Waypoint[] Waypoints = new Waypoint[]
{
// 0 Start at the top gate, head towards first truck
new Waypoint()
{
Destination = new Vector3(316.077f, 0.9093992f, -473.2338f)
},
// 1 Navigate around the truck
new Waypoint()
{
Destination = new Vector3(323.5825f, 1
// ... [Code preview truncated due to length. Full source in attached file] ...