C#:
using System;
using System.Collections.Generic;
using UnityEngine;
using Rust;
using System.Reflection;
using Oxide.Core.Plugins;
using Oxide.Core;
using System.Linq;
using System.Diagnostics;
using System.Text;
using System.Collections;
namespace Oxide.Plugins {
[Info("AttackPlanes", "Shady", "1.0.0", ResourceId = 0)]
class AttackPlanes : RustPlugin {
#region Fields
//static float rocketSpread = 2f;
//static int rocketAmount = 30;
//static float planeDistance = 10f; //distance before firing
//static float rocketInterval = 0.1f; //time between projectiles
[PluginReference]
Plugin ZoneManager;
static FieldInfo TimeToTake = typeof(CargoPlane).GetField("secondsToTake", (BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic));
static FieldInfo StartPos = typeof(CargoPlane).GetField("startPos", (BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic));
static FieldInfo EndPos = typeof(CargoPlane).GetField("endPos", (BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic));
static FieldInfo DropPos = typeof(CargoPlane).GetField("dropPosition", (BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic));
private static readonly int groundWorldConstLayer = LayerMask.GetMask("World", "Default", "Terrain", "Construction", "Deployable", "Prevent Building", "Deployed");
private static readonly int groundWorldLayer = LayerMask.GetMask("World", "Default", "Terrain");
private static readonly int worldLayer = LayerMask.GetMask("World", "Default");
private static readonly int constructionColl = LayerMask.GetMask(new string[] {
"Construction", "Deployable", "Prevent Building", "Deployed"
}
);
private static readonly int treeLayer = LayerMask.GetMask("Tree");
public enum StrikeType {
Cannon, Nuke, Rockets
}
;
public Dictionary<ulong, bool> toggleList = new Dictionary<ulong, bool>();
private List<AttackPlane> allPlanes = new List<AttackPlane>();
public static AttackPlanes apMain;
#endregion
public static Vector3 SpreadVector(Vector3 vec, float rocketSpread = 1.5f) {
return Quaternion.Euler(UnityEngine.Random.Range((float)(-rocketSpread * 0.2), rocketSpread * 0.2f), UnityEngine.Random.Range((float)(-rocketSpread * 0.2), rocketSpread * 0.2f), UnityEngine.Random.Range((float)(-rocketSpread * 0.2), rocketSpread * 0.2f)) * vec;
}
Vector3 SpreadVector2(Vector3 vec, float spread) {
return vec + UnityEngine.Random.insideUnitSphere * spread;
}
public static void QuickHurt(BaseCombatEntity entity, float dmg, Rust.DamageType type, BaseEntity attacker = null, bool useProtection = true, bool useKill = false) {
if (entity == null || entity.IsDestroyed || entity?.transform == null) return;
entity.Hurt(dmg, type, attacker, useProtection);
return;
if (entity is BasePlayer) {
entity.Hurt(dmg, type, attacker, useProtection);
return;
}
if (!useProtection && dmg >= (entity?.health ?? 0)) {
entity.Kill();
return;
}
var newInfo = new HitInfo(attacker, entity, type, dmg, entity.transform.position);
if (useProtection) entity.ScaleDamage(newInfo);
var hp = entity.health;
entity.health = hp - (newInfo?.damageTypes?.Total() ?? 0f);
if (!useKill) {
entity.lastDamage = type;
entity.lastAttacker = attacker;
}
if (entity.health <= 0.0) {
if (useKill) entity.Kill();
else entity.Die();
}
else entity.SendNetworkUpdate();
}
public static IEnumerator HurtEntities(List<BaseCombatEntity> entities, float dmg, Rust.DamageType type, BaseEntity attacker = null, bool useProtection = true) {
for(int i = 0; i < entities.Count; i++) {
var entity = entities[i];
if (entity != null) entity.Hurt(dmg, type, attacker, useProtection);
yield return CoroutineEx.waitForSeconds(0.005f);
}
}
public static IEnumerator HurtEntities(Dictionary<BaseCombatEntity, HitInfo> entities) {
var count = 0;
var entCount = entities.Count;
var countMax = (entities.Count >= 2500) ? 3 : 9;
//large bases take too long to nuke, but 3 will increase lag.should be a middle ground
var hurtMax = 10000L;
var hurtComp = 0L;
foreach(var kvp in entities) {
if (kvp.Value == null) continue;
var entity = kvp.Key;
var info = kvp.Value;
if (entity == null || entity.IsDestroyed || entity?.transform == null || info == null) continue;
count++;
hurtComp++;
if (hurtComp >= hurtMax) {
Interface.Oxide.LogWarning("break on HurtEntities, hurtComp >= hurtMax, total count was: " + entities.Count);
break;
//lag safety
}
var dmgType = info?.damageTypes?.GetMajorityDamageType() ?? DamageType.Generic;
var dmgTotal = info?.damageTypes?.Total() ?? 0f;
var attacker = info?.Initiator ?? null;
QuickHurt(entity, dmgTotal, dmgType, attacker, true, true);
if (count >= countMax || entCount < 5) {
count = 0;
yield return CoroutineEx.waitForSeconds(0.00215f);
}
}
}
public static void HurtEntities2(Dictionary<BaseCombatEntity, HitInfo> entities) {
if (entities == null || entities.Count < 1) return;
foreach (var kvp in entities) {
if (kvp.Value == null) continue;
var entity = kvp.Key;
var info = kvp.Value;
if (entity == null || entity.IsDestroyed || entity?.transform == null || info == null) continue;
var dmgType = info?.damageTypes?.GetMajorityDamageType() ?? DamageType.Generic;
var dmgTotal = info?.damageTypes?.Total() ?? 0f;
var attacker = info?.Initiator ?? null;
QuickHurt(entity, dmgTotal, dmgType, attacker, true, true);
}
}
#region Classes
class NukeMovement : MonoBehaviour {
public BaseEntity entity;
public Vector3 startPos = Vector3.zero;
private Vector3 _endPos = Vector3.zero;
public Vector3 endPos {
get {
return _endPos;
}
set {
_endPos = value;
journeyLength = Distance;
}
}
public float Distance {
get {
return Vector3.Distance(startPos, endPos);
}
}
private float startTime = 0f;
public float speed = 10f;
private float lerpTime = 0f;
private float currentLerpTime = 0f;
private float journeyLength;
void Awake() {
entity = GetComponent<BaseEntity>();
if (entity == null || entity.IsDestroyed) {
DoDestroy();
return;
}
startPos = entity.transform.position;
startTime = UnityEngine.Time.time;
}
public void DoDestroy() => GameObject.Destroy(this);
void Update() {
if (entity == null || entity?.transform == null) return;
if (startPos == Vector3.zero || endPos == Vector3.zero) return;
var fracJourney = ((Time.time - startTime) * speed) / journeyLength;
entity.transform.position = Vector3.Lerp(startPos, endPos, fracJourney);
entity.SendNetworkUpdateImmediate();
}
}
public class NukeSettings {
public float RadZoneRadiusMin = 85f;
public float RadZoneRadiusMax = 170f;
public float RadZoneLifeMin = 90f;
public float RadZoneLifeMax = 240f;
public float RadRadius = 400f;
public float RadDmgRadius = 230f;
public float TemperatureRadius = 400f;
public bool CreateFire = true;
public bool SphereEffect = true;
// public float DamageScalar = 1.0f;
public NukeSettings() {
}
}
private void ExplodeNuke(BaseEntity nukeEnt, BaseCombatEntity attacker = null, NukeSettings nukeSettings = null) {
if (nukeEnt == null) return;
var nukePos = nukeEnt?.transform?.position ?? Vector3.zero;
if (!nukeEnt.IsDestroyed) nukeEnt.Kill();
for (int i = 0; i < 7; i++) {
var rngPos = SpreadVector(nukePos, UnityEngine.Random.Range(0.8f, 2.5f));
if (i < 7) Effect.server.Run("assets/prefabs/npc/m2bradley/effects/maincannonattack.prefab", rngPos, Vector3.zero);
if (i < 5) Effect.server.Run("assets/bundled/prefabs/fx/explosions/explosion_01.prefab", rngPos, Vector3.zero);
if (i < 8) Effect.server.Run("assets/bundled/prefabs/fx/weapons/landmine/landmine_explosion.prefab", SpreadVector(rngPos, UnityEngine.Random.Range(3f, 9f)), Vector3.zero);
if (i < 3) Effect.server.Run("assets/bundled/prefabs/fx/gas_explosion_small.prefab", SpreadVector(rngPos, 1.5f), Vector3.zero);
if (i < 3) Effect.server.Run("assets/prefabs/npc/patrol helicopter/effects/rocket_fire.prefab", rngPos, Vector3.zero);
if (i < 1) Effect.server.Run("assets/prefabs/npc/patrol helicopter/effects/heli_explosion.prefab", SpreadVector(rngPos, 2f), Vector3.zero);
}
if (nukeSettings != null) {
if (nukeSettings.SphereEffect) {
var lerpRadius = UnityEngine.Random.Range(330, 570);
var lerpLife = UnityEngine.Random.Range(4f, 6f);
var lerpSpeed = UnityEngine.Random.Range(480, 680);
var startRadius = UnityEngine.Random.Range(50, 70);
for (int i = 0; i < 4; i++) {
var sphere = (SphereEntity)GameManager.server.CreateEntity("assets/prefabs/visualization/sphere.prefab", nukePos);
if (sphere == null) break;
sphere.currentRadius = startRadius;
sphere.lerpRadius = lerpRadius;
sphere.lerpSpeed = lerpSpeed;
sphere.Spawn();
InvokeHandler.Invoke(sphere, () => {
if (!sphere?.IsDestroyed ?? true) sphere.Kill();
}
, lerpLife);
}
}
}
PrintWarning("explode nuke, did effect & settings/sphere, now starting instance invoke");
InvokeHandler.Invoke(ServerMgr.Instance, () => {
PrintWarning("start nuke dmg invoke");
var dmgList = new List<DamageTypeEntry>();
var expDmg = new DamageTypeEntry();
expDmg.amount = 75f;
expDmg.type = DamageType.Explosion;
var radDmg = new DamageTypeEntry();
radDmg.amount = UnityEngine.Random.Range(6f, 12f);
radDmg.type = DamageType.Radiation;
dmgList.Add(expDmg);
DamageUtil.RadiusDamage(attacker, null, nukePos, 100f, 115f, dmgList, Rust.Layers.Mask.Player_Server, true);
dmgList.Remove(expDmg);
expDmg = new DamageTypeEntry();
expDmg.type = DamageType.Explosion;
expDmg.amount = UnityEngine.Random.Range(90f, 200f);
Interface.Oxide.LogWarning("exp dmg: " + expDmg.amount);
var nearConst = new List<BaseCombatEntity>();
Vis.Entities(nukePos, UnityEngine.Random.Range(230f, 275f), nearConst);
var nearTrees = new List<TreeEntity>();
Vis.Entities(nukePos, UnityEngine.Random.Range(280f, 350f), nearTrees, treeLayer);
nearConst.Distinct();
nearTrees.Distinct();
nearTrees = nearTrees.OrderBy(p => Vector3.Distance((p?.transform?.position ?? Vector3.zero), nukePos))?.ToList() ?? null;
nearConst = nearConst.OrderBy(p => Vector3.Distance((p?.transform?.position ?? Vector3.zero), nukePos))?.ToList() ?? null;
if (nearTrees != null && nearTrees.Count > 0) {
Interface.Oxide.LogWarning("Near trees!");
for (int i = 0; i < nearTrees.Count; i++) {
var tree = nearTrees[i];
if (tree == null) continue;
var treePos = tree?.transform?.position ?? Vector3.zero;
if (treePos == Vector3.zero) continue;
var newHit = new HitInfo();
newHit.PointStart = treePos;
newHit.PointEnd = SpreadVector2(treePos, UnityEngine.Random.Range(1f, 2f));
tree.OnKilled(newHit);
}
}
if (nearConst != null && nearConst.Count > 0) {
var stopWatch = new Stopwatch();
stopWatch.Start();
// List<Stopwatch> stopWatches = new List<Stopwatch>();
var hurts = new Dictionary<BaseCombatEntity, HitInfo>();
for (int i = 0; i < nearConst.Count; i++) {
var entity = nearConst[i];
if (entity == null || entity?.transform == null || entity.IsDestroyed || entity.OwnerID == 757) continue;
if (entity?.baseProtection == null || entity?.baseProtection?.amounts == null) continue;
var fullProtCount = 0;
for (int j = 0; j < entity.baseProtection.amounts.Length; j++) if (entity.baseProtection.amounts[j] >= 1.0f) fullProtCount++;
if (fullProtCount >= entity.baseProtection.amounts.Length) continue;
// var watch = new Stopwatch();
//watch.Start();
var entPos = entity?.transform?.position ?? Vector3.zero;
var dmg = UnityEngine.Random.Range(625f, 2200f);
var dist = Vector3.Distance(entPos, nukePos);
var distReduc = dist / UnityEngine.Random.Range(95f, 180f);
if (distReduc > 999f) distReduc = 999f;
else if (distReduc < 0.85f) distReduc = 0.85f;
// var distReduc = Mathf.Clamp(dist / UnityEngine.Random.Range(80f, 161f), 0.85f, 999f);
dmg = (dmg) / distReduc;
if (entity is BuildingBlock && !entity.IsVisible(nukePos)) dmg /= UnityEngine.Random.Range(1.15f, 1.36f);
if ((entity is DecorDeployable) && !entity.IsVisible(nukePos)) dmg /= UnityEngine.Random.Range(2f, 3f);
if ((entity is BasePlayer) && !entity.IsVisible(nukePos)) dmg /= UnityEngine.Random.Range(7.2f, 21f);
var inCave = IsInCave(entity);
if (inCave) dmg /= UnityEngine.Random.Range(7f, 15f);
var spreadCenter = SpreadVector2(entity.CenterPoint(), 1.1f);
if (nukeSettings != null && nukeSettings.CreateFire && !inCave) {
var fireRNG = UnityEngine.Random.Range(0, 100);
if ((fireRNG <= 1)) {
InvokeHandler.Invoke(ServerMgr.Instance, () => {
var fire = (FireBall)GameManager.server.CreateEntity("assets/bundled/prefabs/oilfireballsmall.prefab", spreadCenter);
if (fire == null) return;
fire.Spawn();
fire.CancelInvoke(fire.Extinguish);
var rngLife = UnityEngine.Random.Range(fire.lifeTimeMin, fire.lifeTimeMax);
fire.Invoke(() => {
if (fire != null && !fire.IsDestroyed) fire.Kill();
}
, rngLife);
if (attacker != null) {
fire.OwnerID = attacker.OwnerID;
fire.creatorEntity = attacker;
}
}
, UnityEngine.Random.Range(0.3f, 0.8f));
}
}
/*?
if (entity is BuildingBlock && (BasePlayer.activePlayerList?.Any(p => p != null && p.transform != null && Vector3.Distance(p.transform.position, spreadCenter) < 60) ?? false)) //check for near players to avoid unneeded effects
{
var block = (entity as BuildingBlock);
var gibFX = "assets/bundled/prefabs/fx/building/" + (block.grade == BuildingGrade.Enum.Twigs ? "thatch" : block.grade == BuildingGrade.Enum.Wood ? "wood" : block.grade == BuildingGrade.Enum.Stone ? "stone" : "metal_sheet") + "_gib.prefab";
Effect.server.Run(gibFX, spreadCenter, Vector3.zero);
}/*/
var info = new HitInfo(attacker, entity, DamageType.Explosion, dmg);
hurts[entity] = info;
// QuickHurt(entity, dmg, DamageType.Explosion, attacker);
// watch.Stop();
// stopWatches.Add(watch);
}
if (hurts != null && hurts.Count > 0) {
if (ServerMgr.Instance == null) {
PrintWarning("ServerMgr.Instance is null!!");
}
else {
ServerMgr.Instance.StartCoroutine(HurtEntities(hurts));
Interface.Oxide.LogWarning("Started Coroutine for HurtEntities");
}
// CommunityEntity.ServerInstance.StartCoroutine(HurtEntities(hurts));
}
else PrintWarning("No hurts!");
stopWatch.Stop();
Interface.Oxide.LogWarning("Entity loop of " + nearConst.Count + " took: " + stopWatch.ElapsedMilliseconds.ToString("0.000") + "ms");
var totalTime = stopWatch.ElapsedMilliseconds;
var watchSB = new StringBuilder();
/*/
if (stopWatches.Count > 0)
{
for (int i = 0; i < stopWatches.Count; i++)
{
var timeTaken = stopWatches[i].ElapsedMilliseconds;
totalTime += timeTaken;
watchSB.AppendLine("Stopwatch: " + i + " took: " + timeTaken.ToString("0.000") + "ms");
}
Interface.Oxide.LogWarning(watchSB.ToString().TrimEnd());
}/*/
Interface.Oxide.LogWarning("Total time: " + totalTime.ToString("0.000") + "ms");
}
if (nukeSettings != null && nukeSettings.RadDmgRadius > 0.0f) {
dmgList.Add(radDmg);
dmgList.Remove(expDmg);
var heatDmg = new Rust.DamageTypeEntry();
heatDmg.type = DamageType.Heat;
heatDmg.amount = UnityEngine.Random.Range(6f, 18f);
dmgList.Add(heatDmg);
DamageUtil.RadiusDamage(attacker, null, nukePos, nukeSettings.RadDmgRadius, nukeSettings.RadDmgRadius, dmgList, Rust.Layers.Mask.Player_Server, false);
}
}
, 0.1f);
if (nukeSettings != null && (nukeSettings.TemperatureRadius > 0.0f || nukeSettings.RadRadius > 0.0f)) {
InvokeHandler.Invoke(ServerMgr.Instance, () => {
var checkDistance = Math.Max(nukeSettings.TemperatureRadius, nukeSettings.RadRadius);
var nearPlayers = BasePlayer.activePlayerList?.Where(p => p != null && p?.transform != null && p?.metabolism != null && Vector3.Distance(p.transform.position, nukePos) <= checkDistance)?.ToList() ?? null;
if (nearPlayers != null && nearPlayers.Count > 0) {
for (int i = 0; i < nearPlayers.Count; i++) {
var player = nearPlayers[i];
var pDist = Vector3.Distance(player.transform.position, nukePos);
var inCave = IsInCave(player);
Interface.Oxide.LogWarning("do rad & temp for player: " + player.displayName);
var radMin = (inCave) ? 75f : 200f;
var radMax = (inCave) ? 200f : 800f;
var oldMin = player.metabolism.temperature.min;
if (pDist <= nukeSettings.RadRadius) {
player.metabolism.radiation_poison.value = Mathf.Clamp(player.metabolism.radiation_poison.value + UnityEngine.Random.Range(radMin, radMax), player.metabolism.radiation_poison.min, player.metabolism.radiation_poison.max);
player.metabolism.radiation_level.value = player.metabolism.radiation_poison.value;
}
if (pDist <= nukeSettings.TemperatureRadius) {
var tempMod = Mathf.Clamp(pDist / 64, 1f, 999f);
var tempMin = (inCave) ? 80f : 600f;
var tempMax = (inCave) ? 500f : 1200f;
player.metabolism.temperature.value = Mathf.Clamp(player.metabolism.temperature.value + (UnityEngine.Random.Range(tempMin, tempMax) / tempMod), player.metabolism.temperature.min, player.metabolism.temperature.max);
Interface.Oxide.LogWarning("temp value after nuke: " + player.metabolism.temperature.value);
// var oldMin = player.metabolism.temperature.min;
player.metabolism.temperature.min = player.metabolism.temperature.value / UnityEngine.Random.Range(1f, 1.25f);
}
player.metabolism.SendChangesToClient();
InvokeHandler.Invoke(ServerMgr.Instance, () => {
if (player?.metabolism != null) player.metabolism.temperature.min = oldMin;
}
, UnityEngine.Random.Range(10f, 30f));
}
}
}
, 0.75f);
}
if (nukeSettings != null && nukeSettings.RadZoneRadiusMin > 0.0f && nukeSettings.RadZoneRadiusMax > 0.0f && nukeSettings.RadZoneLifeMin > 0.0f && nukeSettings.RadZoneLifeMax > 0.0f) {
if (apMain.ZoneManager != null && apMain.ZoneManager.IsLoaded) {
var zoneRadiation = UnityEngine.Random.Range(80f, 220f);
string[] args = {
"radius", UnityEngine.Random.Range(nukeSettings.RadZoneRadiusMin, nukeSettings.RadZoneRadiusMax).ToString(), "radiation", zoneRadiation.ToString()
}
;
var nukeName = UnityEngine.Random.Range(0, 100000) + " NUKE";
var newZone = apMain?.ZoneManager?.Call<bool>("CreateOrUpdateZone", nukeName, args, nukePos) ?? false;
if (newZone) Interface.Oxide.LogWarning("Created new nuke rad zone");
else Interface.Oxide.LogWarning("Did not create new nuke rad zone");
InvokeHandler.Invoke(ServerMgr.Instance, () => {
var newRad = Math.Round(zoneRadiation / UnityEngine.Random.Range(1.26f, 1.9f), MidpointRounding.AwayFromZero);
Interface.Oxide.LogWarning("new rad: " + newRad + ", old: " + zoneRadiation);
string[] updArgs = {
"radiation", newRad.ToString()
}
;
var updZone = apMain?.ZoneManager?.Call<bool>("CreateOrUpdateZone", nukeName, updArgs, nukePos) ?? false;
if (updZone) Interface.Oxide.LogWarning("Upd zone!");
else Interface.Oxide.LogWarning("failed to upd zone");
}
, UnityEngine.Random.Range(45f, 70f));
InvokeHandler.Invoke(ServerMgr.Instance, () => {
if (apMain == null || apMain.ZoneManager == null || !apMain.ZoneManager.IsLoaded) {
Interface.Oxide.LogWarning("no apmain or zone manager, ap main: " + (apMain != null) + " zm: " + (apMain?.ZoneManager?.IsLoaded ?? false));
return;
}
var delZone = apMain?.ZoneManager?.Call<bool>("EraseZone", nukeName) ?? false;
if (delZone) Interface.Oxide.LogWarning("Deleted nuclear ground zero zone");
else Interface.Oxide.LogWarning("Did NOT delete nuclear ground zero zone");
}
, UnityEngine.Random.Range(nukeSettings.RadZoneLifeMin, nukeSettings.RadZoneLifeMax));
}
}
Interface.Oxide.LogWarning("NUKE GROUNED!");
return;
}
HashSet<BaseEntity> nukeRockets = new HashSet<BaseEntity>();
void LaunchICBM(Vector3 startPosition, Vector3 endPosition) {
var initEndPos = startPosition;
initEndPos.y += 3000;
var rocket = LaunchRocket(startPosition, initEndPos, Vector3.zero, 160, 0.05f, globalBroadcast : true);
if (rocket == null || rocket.IsDestroyed) return;
rocket.Invoke(() => {
rocket.SendMessage("InitializeVelocity", (endPosition - rocket.transform.position));
}
, 8f);
for(int i = 0; i < 9; i++) {
timer.Once(UnityEngine.Random.Range(0.03f, 0.1f), () => {
var newRocket = LaunchRocket(SpreadVector2(startPosition, UnityEngine.Random.Range(0.7f, 1.5f)), SpreadVector2(initEndPos, UnityEngine.Random.Range(0.7f, 1.3f)), Vector3.zero, 160, 0.05f, globalBroadcast : true);
var endRng = SpreadVector2(endPosition, UnityEngine.Random.Range(0.7f, 1.4f));
newRocket.Invoke(() => newRocket.SendMessage("InitializeVelocity", (endRng - newRocket.transform.position)), 8f);
}
);
}
nukeRockets.Add(rocket);
}
void OnEntityKill(BaseNetworkable entity) {
if (entity == null) return;
var rocket = entity as BaseEntity;
if (nukeRockets.Contains(rocket)) {
nukeRockets.Remove(rocket);
var ply = BasePlayer.FindByID(rocket.OwnerID) ?? BasePlayer.FindSleeping(rocket.OwnerID);
PrintWarning("Would explode now");
//var nukeSet = new NukeSettings();
// ExplodeNuke(rocket, ply, nukeSet);
}
}
private BaseEntity LaunchRocket(Vector3 startPos, Vector3 targetPos, Vector3 offset = default(Vector3), float speed = 80, float gravity = 0f, float radiusScalar = 0f, float dmgScalar = 0f, BaseEntity trackEntity = null, bool globalBroadcast = false, bool incen = false) {
var rocket = incen ? "ammo.rocket.fire" : "ammo.rocket.hv";
var launchPos = startPos;
ItemDefinition projectileItem = ItemManager.FindItemDefinition(rocket);
ItemModProjectile component = projectileItem.GetComponent<ItemModProjectile>();
if (offset != default(Vector3)) {
launchPos.x += offset.x;
launchPos.y += offset.y;
launchPos.z += offset.z;
}
BaseEntity entity = GameManager.server.CreateEntity(component.projectileObject.resourcePath, launchPos, new Quaternion(), true);
if (entity == null) return null;
entity.Invoke(() => {
if (entity == null || (entity?.IsDestroyed ?? true)) return;
entity.Kill();
}
, 40f);
TimedExplosive rocketExplosion = entity as TimedExplosive;
ServerProjectile rocketProjectile = entity.GetComponent<ServerProjectile>();
rocketProjectile.speed = speed;
rocketProjectile.gravityModifier = gravity;
rocketExplosion.timerAmountMin = 60;
rocketExplosion.timerAmountMax = 60;
if (radiusScalar < 0 || radiusScalar > 0) {
rocketExplosion.minExplosionRadius *= radiusScalar;
rocketExplosion.explosionRadius *= radiusScalar;
}
if (dmgScalar > 0 || dmgScalar < 0) rocketExplosion.damageTypes.ForEach(p => p.amount *= dmgScalar);
Vector3 newDirection = (targetPos - launchPos);
entity.SendMessage("InitializeVelocity", (newDirection));
if (globalBroadcast) entity.globalBroadcast = true;
entity.Spawn();
if (globalBroadcast) entity.globalBroadcast = true;
entity.SendNetworkUpdateImmediate(true);
if (trackEntity != null && !(trackEntity?.IsDestroyed ?? true)) {
Action trackInvoke = null;
trackInvoke = new Action(() => {
if ((entity?.IsDestroyed ?? true) || (trackEntity?.IsDestroyed ?? true)) {
InvokeHandler.CancelInvoke(entity, trackInvoke);
return;
}
entity.SendMessage("InitializeVelocity", (trackEntity.transform.position - entity.transform.position));
}
);
InvokeHandler.InvokeRepeating(entity, trackInvoke, 0.5f, 0.1f);
}
return entity;
}
public class AttackPlane : MonoBehaviour {
public CargoPlane Plane;
public Vector3 TargetPosition;
public int FiredRockets = 0;
public ulong OwnerID = 0;
public BasePlayer GetOwnerPlayer() {
return OwnerID == 0 ? null : BasePlayer.FindByID(OwnerID) ?? BasePlayer.FindSleeping(OwnerID) ?? null;
}
public StrikeType type = StrikeType.Cannon;
public NukeSettings nukeSettings = new NukeSettings();
public float spreadMin = 2.75f;
public float spreadMax = 5.8f;
public float fireDistance = 12f;
public int fireAmount = 24;
public float rocketInterval = 0.08f;
public float damageModifier = 1f;
public float rocketRadiusScalar = 1f;
public void SpawnPlane(CargoPlane plane, Vector3 position, float speed, bool isSquad = false, Vector3 offset = new Vector3()) {
if (plane == null) throw new ArgumentNullException();
enabled = true;
Plane = plane;
TargetPosition = position;
Plane.InitDropPosition(position);
Plane.Spawn();
if (isSquad) {
Vector3 SpawnPos = CalculateSpawnPos(offset);
StartPos.SetValue(Plane, SpawnPos);
EndPos.SetValue(Plane, SpawnPos - new Vector3(0, 0, TerrainMeta.Size.x * 1.1f));
Plane.transform.position = SpawnPos;
Plane.transform.rotation = new Quaternion(0, 180, 0, 0);
}
TimeToTake.SetValue(Plane, Vector3.Distance((Vector3)StartPos.GetValue(Plane), (Vector3)EndPos.GetValue(Plane)) / speed);
InvokeHandler.InvokeRepeating(this, CheckDistance, 0.5f, 0.1f);
}
private Vector3 CalculateSpawnPos(Vector3 offset) {
float mapSize = (TerrainMeta.Size.x / 2) + 150f;
Vector3 spawnPos = new Vector3();
spawnPos.x = TargetPosition.x + offset.x;
spawnPos.z = mapSize + offset.z;
spawnPos.y = 150 + offset.y;
return spawnPos;
}
private void CheckDistance() {
var currentPos = Plane.transform.position;
var dist = Vector3.Distance(currentPos, TargetPosition);
// Interface.Oxide.LogWarning("currentpos, targetposition distance: " + dist + ", curr pos.y + fire distance: " + (currentPos.y + fireDistance));
var altPos = currentPos;
altPos.y = TargetPosition.y;
var altDist = Vector3.Distance(altPos, TargetPosition);
// Interface.Oxide.LogWarning("Alt dist: " + altDist);
if (altDist <= fireDistance) {
Interface.Oxide.LogWarning("Fire dist");
FireRockets();
InvokeHandler.CancelInvoke(this, CheckDistance);
}
/*/
if (Vector3.Distance(currentPos, TargetPosition) < (currentPos.y + fireDistance))
{
FireRockets();
InvokeHandler.CancelInvoke(this, CheckDistance);
}/*/
}
private void FireRockets() {
if (InvokeHandler.IsInvoking(this, SpreadRockets)) InvokeHandler.CancelInvoke(this, SpreadRockets);
InvokeHandler.InvokeRepeating(this, SpreadRockets, 0.001f, rocketInterval);
}
private void SpreadRockets() {
if (FiredRockets >= fireAmount) {
InvokeHandler.CancelInvoke(this, SpreadRockets);
return;
}
FiredRockets++;
if (type == StrikeType.Cannon) LaunchCannon(TargetPosition);
if (type == StrikeType.Rockets) LaunchRocket(TargetPosition);
if (type == StrikeType.Nuke) {
Interface.Oxide.LogWarning("NUKE");
LaunchNuke(TargetPosition);
FiredRockets = fireAmount;
}
}
private void LaunchCannon(Vector3 targetPos) {
if (targetPos == Vector3.zero) return;
var launchPos = Plane?.transform?.position ?? Vector3.zero;
if (launchPos == Vector3.zero) return;
var modLaunch = SpreadVector(launchPos, UnityEngine.Random.Range(2.35f, 3.4f));
// Interface.Oxide.LogWarning("start launch: " + modLaunch);
// Interface.Oxide.LogWarning("aim cone: " + modLaunch);
Effect.server.Run("assets/prefabs/npc/m2bradley/effects/maincannonattack.prefab", modLaunch, Vector3.zero);
var modAdj = modLaunch;
modAdj.y -= UnityEngine.Random.Range(3f, 4f);
var shell = GameManager.server.CreateEntity("assets/prefabs/npc/m2bradley/maincannonshell.prefab", modAdj);
var newDir = (targetPos - modAdj);
newDir = SpreadVector(newDir, UnityEngine.Random.Range(spreadMin, spreadMax));
shell.SendMessage("InitializeVelocity", newDir);
shell.creatorEntity = GetOwnerPlayer();
shell.OwnerID = OwnerID;
shell.Spawn();
}
private void LaunchNuke(Vector3 targetPos) {
if (targetPos == Vector3.zero) return;
var launchPos = Plane?.transform?.position ?? Vector3.zero;
if (launchPos == Vector3.zero) return;
var modLaunch = SpreadVector(launchPos, UnityEngine.Random.Range(0.2f, 0.8f));
var nukePrefab = "assets/prefabs/deployable/water catcher/water_catcher_small.prefab";
// var nukePrefab = "assets/bundled/prefabs/static/hobobarrel_static.prefab";
var nukeEnt = GameManager.server.CreateEntity(nukePrefab, modLaunch, Quaternion.identity);
nukeEnt.OwnerID = 757;
Interface.Oxide.LogWarning("net limit before: " + nukeEnt.globalBroadcast);
nukeEnt.globalBroadcast = true;
nukeEnt.Spawn();
Interface.Oxide.LogWarning("nuke pre rot: " + nukeEnt.transform.rotation);
// nukeEnt.transform.rotation = new Quaternion(-0.5f, -0.5f, -0.5f, -0.5f);
// nukeEnt.transform.rotation = Quaternion.Euler(Plane?.transform?.eulerAngles ?? Vector3.zero);
Interface.Oxide.LogWarning("nuke after rot: " + nukeEnt.transform.rotation);
Interface.Oxide.LogWarning("do launch nuke, nukeent: " + nukeEnt.transform.position);
var startPos = nukeEnt?.transform?.position ?? Vector3.zero;
var endPos = Vector3.zero;
// RaycastHit rayInfo;
var rayPos = startPos;
rayPos.y += 300;
var hits = UnityEngine.Physics.RaycastAll(new Ray(rayPos, Vector3.down), modLaunch.y + 400f, groundWorldConstLayer);
var hitDistances = new Dictionary<Vector3, float>();
// var hitDistances = new List<float>();
if (hits == null || hits.Length < 1) Interface.Oxide.LogWarning("NO HITS!");
else {
for(int i = 0; i < hits.Length; i++) {
var hit = hits[i];
var hitEnt = hit.GetEntity();
if (hitEnt != null && hitEnt.ShortPrefabName == nukeEnt.ShortPrefabName) continue;
if (hit.point != Vector3.zero) {
var dist = Vector3.Distance(hit.point, startPos);
hitDistances[hit.point] = dist;
// hitDistances.Add(dist);
}
// endPos = hit.point;
}
}
if (hitDistances.Count < 1) {
Interface.Oxide.LogWarning("no hit dists!");
return;
}
var valMin = hitDistances.Values.Min();
endPos = hitDistances.Where(p => p.Value == valMin)?.FirstOrDefault().Key ?? Vector3.zero;
// endPos = hits?.Where(p => Vector3.Distance(p.point, startPos).ToString() == hitDistances.Min().ToString())?.FirstOrDefault().point ?? Vector3.zero;
/*/
if (UnityEngine.Physics.Raycast(new Ray(rayPos, Vector3.down), out rayInfo, modLaunch.y + 400f, groundWorldConstLayer))
{
endPos = rayInfo.point;
Interface.Oxide.LogWarning("ray hit: " + rayInfo.GetEntity()?.ShortPrefabName + ", " + rayInfo.collider?.sharedMaterial?.name);
}/*/
// if (UnityEngine.Physics.Raycast(new Ray(startPos, Vector3.down), out rayInfo, modLaunch.y + 300f, groundWorldLayer)) endPos = rayInfo.point;
if (endPos == Vector3.zero) {
nukeEnt.Kill();
Interface.Oxide.LogWarning("BAD ENDPOS");
return;
}
Interface.Oxide.LogWarning("end pos: " + endPos);
var nukeClass = nukeEnt.gameObject.AddComponent<NukeMovement>();
// var nukeClass = nukeEnt.GetComponent<NukeMovement>();
nukeClass.speed = UnityEngine.Random.Range(32f, 64f);
nukeClass.endPos = endPos;
//nukeEnt.GetComponent<NukeClass>().endPos = endPos;
var attacker = GetOwnerPlayer();
Action nukeAct = null;
nukeAct = new Action(() => {
if (nukeEnt == null || nukeEnt.IsDestroyed) {
InvokeHandler.CancelInvoke(nukeEnt, nukeAct);
return;
}
var nukePos = nukeEnt?.transform?.position ?? Vector3.zero;
if (Vector3.Distance(nukePos, endPos) <= UnityEngine.Random.Range(55f, 75f)) //explode a bit off the ground for more realism
{
InvokeHandler.CancelInvoke(nukeEnt, nukeAct);
apMain?.ExplodeNuke(nukeEnt, attacker, nukeSettings);
// Interface.Oxide.LogWarning("NUKE GROUNED!");
return;
}
}
);
InvokeHandler.InvokeRepeating(nukeEnt, nukeAct, 0.05f, 0.05f);
}
private void LaunchRocket(Vector3 targetPos) {
var launchPos = Plane.transform.position;
ItemDefinition projectileItem = ItemManager.FindItemDefinition("ammo.rocket.basic");
ItemModProjectile component = projectileItem.GetComponent<ItemModProjectile>();
BaseEntity entity = GameManager.server.CreateEntity(component.projectileObject.resourcePath, launchPos, new Quaternion(), true);
TimedExplosive rocketExplosion = entity.GetComponent<TimedExplosive>();
ServerProjectile rocketProjectile = entity.GetComponent<ServerProjectile>();
rocketProjectile.speed = 90;
rocketProjectile.gravityModifier = 0;
rocketExplosion.timerAmountMin = 60;
rocketExplosion.timerAmountMax = 60;
rocketExplosion.minExplosionRadius *= rocketRadiusScalar;
rocketExplosion.explosionRadius *= rocketRadiusScalar;
for (int i = 0; i < rocketExplosion.damageTypes.Count; i++) rocketExplosion.damageTypes[i].amount *= damageModifier;
Vector3 newDirection = (targetPos - launchPos);
entity.SendMessage("InitializeVelocity", (newDirection));
entity.Spawn();
if (this.OwnerID != 0) {
entity.creatorEntity = GetOwnerPlayer();
entity.OwnerID = this.OwnerID;
}
}
}
private CargoPlane CreatePlane() => (CargoPlane)GameManager.server.CreateEntity(cargoPlanePrefab, new Vector3(), new Quaternion(), true);
#endregion
#region Oxide Hooks
void Init() => apMain = this;
void Unload() {
DestroyAllPlanes();
}
void OnEntitySpawned(BaseEntity entity) {
if (entity != null && (entity is SupplyDrop)) CheckStrikeDrop(entity as SupplyDrop);
}
#endregion
#region Core Functions
static bool IsInCave(BaseEntity entity) {
if (entity == null || entity?.transform == null || entity.IsDestroyed) return false;
var targets = Physics.RaycastAll(new Ray(entity.transform.position, Vector3.up), 250, worldLayer);
if (targets == null || targets.Length < 1) return false;
for(int i = 0; i < targets.Length; i++) {
var hit = targets[i];
var collider = (hit.collider ?? null) as MeshCollider;
if (collider == null) continue;
if (collider.sharedMesh.name.StartsWith("cave_") || collider.sharedMesh.name.StartsWith("rock_")) return true;
}
return false;
}
static bool IsOnGround(BaseEntity entity) {
if (entity == null || (entity?.IsDestroyed ?? true)) return false;
var ray = new Ray((entity?.transform?.position ?? Vector3.zero), Vector3.down);
RaycastHit hit;
if (UnityEngine.Physics.SphereCast(ray, 1f, out hit, 0.75f, groundWorldConstLayer)) if (hit.GetEntity() != null || hit.GetCollider() != null) return true;
return false;
}
public const string cargoPlanePrefab = "assets/prefabs/npc/cargo plane/cargo_plane.prefab";
private void DestroyPlane(AttackPlane plane) {
if (plane == null) {
PrintWarning("destroyPlane call but plane is already null!");
return;
}
PrintWarning("destroyPlane called!!");
if (allPlanes.Contains(plane)) {
if (plane?.Plane != null && !plane.Plane.IsDestroyed) plane.Plane.Kill();
UnityEngine.Object.Destroy(plane);
}
if (allPlanes.Contains(plane)) allPlanes.Remove(plane);
}
private void DestroyAllPlanes() {
for (int i = 0; i < allPlanes.Count; i++) DestroyPlane(allPlanes[i]);
}
public bool CheckStrikeDrop(SupplyDrop drop) {
if (drop == null) return false;
bool istrue = false;
foreach (var plane in allPlanes) {
if (plane.Plane == null) continue;
float dropDistance = ((Vector3.Distance(plane.Plane.transform.position, drop.transform.position)));
if (dropDistance <= 130 && !(drop?.IsDestroyed ?? true)) drop.Kill();
istrue = true;
}
return istrue;
}
private void MassSet(Vector3 position, Vector3 offset, int speed = -1, float dmgScalar = 1f, float radiusScalar = 1f, ulong OwnerID = 0, StrikeType type = StrikeType.Cannon) {
if (speed == -1) speed = 100;
CargoPlane plane = CreatePlane();
if (plane == null || plane.IsDestroyed) {
PrintWarning("plane is null or destroyed on MassSet!!!!");
return;
}
var AttackPlane = plane.gameObject.AddComponent<AttackPlane>();
AttackPlane.type = type;
allPlanes.Add(AttackPlane);
AttackPlane.OwnerID = OwnerID;
AttackPlane.rocketRadiusScalar = radiusScalar;
AttackPlane.damageModifier = dmgScalar;
if (type == StrikeType.Rockets) AttackPlane.fireDistance = 32;
AttackPlane.SpawnPlane(plane, position, speed, true, offset);
var removePlane = ((Vector3.Distance((Vector3)StartPos.GetValue(plane), (Vector3)DropPos.GetValue(plane)) / speed) + 55);
Interface.Oxide.LogWarning("will destroy plane in: " + removePlane);
plane.Invoke(() => {
Prin
// ... [Code preview truncated due to length. Full source in attached file] ...