Files
Nathaniel Cosford 062dfab2cd Patched
2025-05-30 01:04:40 +09:30

828 lines
30 KiB
C#

using System.Collections.Generic;
public class EntityWraith : EntityFlying
{
public override void FireEvent(MinEventTypes _eventType, bool useInventory = true)
{
bool applyBlockDamageBuffs = false;
if (_eventType == MinEventTypes.onSelfDamagedOther)
{
//Log.Out("EntityAlivePatches-FireEvent WRAITH DAMAGED OTHER");
this.Buffs.AddBuff("FuriousRamsayWraithProtection");
this.Buffs.SetCustomVar("$FuriousRamsayAttacked", 0f);
}
else if (_eventType == MinEventTypes.onSelfRangedBurstShotStart)
{
//Log.Out("EntityAlivePatches-FireEvent WRAITH BURST SHOT OTHER");
this.Buffs.AddBuff("FuriousRamsayWraithProtection");
this.Buffs.SetCustomVar("$FuriousRamsayAttacked", 1f);
}
else if (_eventType == MinEventTypes.onSelfAttackedOther)
{
//Log.Out("EntityAlivePatches-FireEvent WRAITH ATTACKED OTHER");
this.Buffs.AddBuff("FuriousRamsayWraithProtection");
float attacks = this.Buffs.GetCustomVar("$FuriousRamsayAttacked") - 2f;
if (attacks < 0f)
{
attacks = 0f;
}
this.Buffs.SetCustomVar("$FuriousRamsayAttacked", attacks);
}
else if (_eventType == MinEventTypes.onSelfDamagedBlock)
{
//Log.Out("EntityAlivePatches-FireEvent WRAITH DAMAGED BLOCK");
applyBlockDamageBuffs = true;
}
else if (_eventType == MinEventTypes.onSelfDestroyedBlock)
{
//Log.Out("EntityAlivePatches-FireEvent WRAITH DESTROYED BLOCK");
applyBlockDamageBuffs = true;
}
else if (_eventType == MinEventTypes.onSelfPrimaryActionUpdate ||
_eventType == MinEventTypes.onSelfSecondaryActionUpdate
)
{
}
else
{
//Log.Out("EntityAlivePatches-FireEvent _eventType: " + _eventType);
}
if (applyBlockDamageBuffs)
{
//Log.Out("EntityAlivePatches-FireEvent ADD BLOCK BUFF");
this.Buffs.AddBuff("FuriousRamsayWraithProtectionBlocks");
}
if (_eventType == MinEventTypes.onOtherDamagedSelf)
{
float attacks = this.Buffs.GetCustomVar("$FuriousRamsayAttacked") + 1f;
this.Buffs.SetCustomVar("$FuriousRamsayAttacked", attacks);
if (attacks >= 4f)
{
this.Buffs.RemoveBuff("FuriousRamsayWraithProtection");
this.Buffs.RemoveBuff("FuriousRamsayWraithProtectionBlocks");
}
}
base.FireEvent(_eventType, useInventory);
}
public override string EntityName
{
get
{
return this.entityName;
}
}
public override void OnUpdateLive()
{
if (this.bDead)
{
if (this.lootContainer != null)
{
if (this.lootContainer.bTouched && this.lootContainer.IsEmpty())
{
this.MarkToUnload();
this.KillLootContainer();
}
}
}
base.OnUpdateLive();
}
public override void Awake()
{
base.Awake();
this.state = EntityWraith.State.WanderStart;
}
public override void Init(int _entityClass)
{
base.Init(_entityClass);
this.Init();
}
public override void InitFromPrefab(int _entityClass)
{
base.InitFromPrefab(_entityClass);
this.Init();
}
private void Init()
{
this.isRadiated = EntityClass.list[this.entityClass].Properties.Values.ContainsKey("Radiated");
this.battleFatigueSeconds = 30f + this.rand.RandomFloat * 60f;
}
public override void SetSleeper()
{
base.SetSleeper();
this.sorter = new EAISetNearestEntityAsTargetSorter(this);
base.setHomeArea(new Vector3i(this.position), (int)this.sleeperSightRange + 1);
this.battleFatigueSeconds = float.MaxValue;
}
public override void updateTasks()
{
if (GamePrefs.GetBool(EnumGamePrefs.DebugStopEnemiesMoving))
{
this.aiManager.UpdateDebugName();
return;
}
if (GameStats.GetInt(EnumGameStats.GameState) == 2)
{
return;
}
base.CheckDespawn();
base.GetEntitySenses().ClearIfExpired();
bool flag = this.Buffs.HasBuff("buffShocked");
if (flag)
{
this.SetState(EntityWraith.State.Stun);
}
else
{
EntityAlive revengeTarget = base.GetRevengeTarget();
if (revengeTarget)
{
this.battleDuration = 0f;
this.isBattleFatigued = false;
base.SetRevengeTarget((EntityAlive) null);
if (revengeTarget != this.attackTarget && (!this.attackTarget || this.rand.RandomFloat < 0.5f))
{
base.SetAttackTarget(revengeTarget, 1200);
}
}
if (this.attackTarget != this.currentTarget)
{
this.currentTarget = this.attackTarget;
if (this.currentTarget)
{
this.SetState(EntityWraith.State.Attack);
this.waypoint = this.position;
this.moveUpdateDelay = 0;
this.homeCheckDelay = 400;
}
else
{
this.SetState(EntityWraith.State.AttackStop);
}
}
}
float sqrMagnitude = (this.waypoint - this.position).sqrMagnitude;
this.stateTime += 0.05f;
int num2;
switch (this.state)
{
case EntityWraith.State.Attack:
this.battleDuration += 0.05f;
break;
case EntityWraith.State.AttackReposition:
if (sqrMagnitude < 2.25f || this.stateTime >= this.stateMaxTime)
{
this.SetState(EntityWraith.State.Attack);
this.motion *= -0.2f;
this.motion.y = 0f;
}
break;
case EntityWraith.State.AttackStop:
this.ClearTarget();
this.SetState(EntityWraith.State.WanderStart);
break;
case EntityWraith.State.Home:
if (sqrMagnitude < 4f || this.stateTime > 30f)
{
this.SetState(EntityWraith.State.WanderStart);
}
else
{
num2 = this.homeSeekDelay - 1;
this.homeSeekDelay = num2;
if (num2 <= 0)
{
this.homeSeekDelay = 40;
int minXZ = 10;
if (this.stateTime > 20f)
{
minXZ = -20;
}
int maximumHomeDistance = base.getMaximumHomeDistance();
Vector3 vector = RandomPositionGenerator.CalcTowards(this, minXZ, 30, maximumHomeDistance / 2, base.getHomePosition().position.ToVector3());
if (!vector.Equals(Vector3.zero))
{
this.waypoint = vector;
this.AdjustWaypoint();
}
}
}
break;
case EntityWraith.State.Stun:
if (flag)
{
this.motion = this.rand.RandomOnUnitSphere * -0.075f;
this.motion.y = this.motion.y + -0.060000002f;
this.ModelTransform.GetComponentInChildren<Animator>().enabled = false;
return;
}
this.ModelTransform.GetComponentInChildren<Animator>().enabled = true;
this.SetState(EntityWraith.State.WanderStart);
break;
case EntityWraith.State.WanderStart:
this.homeCheckDelay = 60;
this.SetState(EntityWraith.State.Wander);
this.isCircling = (!this.IsSleeper && this.rand.RandomFloat < 0.4f);
float num3 = this.position.y;
RaycastHit raycastHit;
if (Physics.Raycast(this.position - Origin.position, Vector3.down, out raycastHit, 999f, 65536))
{
float num4 = 10f + this.rand.RandomFloat * 20f;
if (this.IsSleeper)
{
num4 *= 0.4f;
}
num3 += -raycastHit.distance + num4;
}
else
{
this.isCircling = false;
}
bool flag2 = false;
EntityPlayer entityPlayer3 = null;
EntityPlayer closestPlayer = null;
float numTarget = 200 * 200;
float numTarget2 = float.MaxValue;
for (int i = this.world.Players.list.Count - 1; i >= 0; i--)
{
EntityPlayer entityPlayer = this.world.Players.list[i];
if (!entityPlayer.IsDead() && entityPlayer.Spawned)
{
////Log.Out("FOUND PLAYER: " + entityPlayer.EntityName);
float distanceSq = entityPlayer.GetDistanceSq(this.position);
if (distanceSq < numTarget2 && distanceSq <= numTarget)
{
numTarget2 = distanceSq;
closestPlayer = entityPlayer;
}
}
}
entityPlayer3 = closestPlayer;
if (this.isCircling)
{
this.wanderChangeDelay = 120;
Vector3 right = base.transform.right;
right.y = 0f;
this.circleReverseScale = 1f;
if (this.rand.RandomFloat < 0.5f)
{
this.circleReverseScale = -1f;
right.x = -right.x;
right.z = -right.z;
}
this.circleCenter = this.position + right * (3f + this.rand.RandomFloat * 7f);
this.circleCenter.y = num3;
if (flag2)
{
this.circleCenter.x = this.circleCenter.x * 0.6f + entityPlayer3.position.x * 0.4f;
this.circleCenter.z = this.circleCenter.z * 0.6f + entityPlayer3.position.z * 0.4f;
}
}
else
{
this.wanderChangeDelay = 400;
this.waypoint = this.position;
this.waypoint.x = this.waypoint.x + (this.rand.RandomFloat * 16f - 8f);
this.waypoint.y = num3;
this.waypoint.z = this.waypoint.z + (this.rand.RandomFloat * 16f - 8f);
if (flag2)
{
this.waypoint.x = this.waypoint.x * 0.6f + entityPlayer3.position.x * 0.4f;
this.waypoint.z = this.waypoint.z * 0.6f + entityPlayer3.position.z * 0.4f;
}
this.AdjustWaypoint();
}
break;
case EntityWraith.State.Wander:
if (this.isBattleFatigued)
{
this.battleDuration -= 0.05f;
if (this.battleDuration <= 0f)
{
this.isBattleFatigued = false;
}
}
num2 = this.wanderChangeDelay - 1;
this.wanderChangeDelay = num2;
if (num2 <= 0)
{
this.SetState(EntityWraith.State.WanderStart);
}
if (this.isCircling)
{
Vector3 vector2 = this.circleCenter - this.position;
float x = vector2.x;
vector2.x = -vector2.z * this.circleReverseScale;
vector2.z = x * this.circleReverseScale;
vector2.y = 0f;
this.waypoint = this.position + vector2;
}
else if (sqrMagnitude < 1f)
{
this.SetState(EntityWraith.State.WanderStart);
}
num2 = this.targetSwitchDelay - 1;
this.targetSwitchDelay = num2;
if (num2 <= 0)
{
this.targetSwitchDelay = 40;
if (this.IsSleeper || this.rand.RandomFloat >= 0.5f)
{
EntityPlayer entityPlayer4 = this.FindTarget();
if (entityPlayer4)
{
base.SetAttackTarget(entityPlayer4, 1200);
}
}
}
break;
}
if (this.state != EntityWraith.State.Home)
{
num2 = this.homeCheckDelay - 1;
this.homeCheckDelay = num2;
if (num2 <= 0)
{
this.homeCheckDelay = 60;
if (!base.isWithinHomeDistanceCurrentPosition())
{
this.SetState(EntityWraith.State.AttackStop);
}
}
}
num2 = this.moveUpdateDelay - 1;
this.moveUpdateDelay = num2;
if (num2 <= 0)
{
this.moveUpdateDelay = 5 + this.rand.RandomRange(5);
if (this.currentTarget && this.state == EntityWraith.State.Attack)
{
this.waypoint = this.currentTarget.getHeadPosition();
this.waypoint.y = this.waypoint.y + -0.1f;
if (this.currentTarget.AttachedToEntity)
{
this.waypoint += this.currentTarget.GetVelocityPerSecond() * 0.3f;
}
Vector3 a = this.waypoint - this.position;
a.y = 0f;
a.Normalize();
this.waypoint += a * -0.6f;
}
float num5;
if (!isCourseTraversable(this.waypoint, out num5))
{
this.waypoint.y = this.waypoint.y + 2f;
if (this.state == EntityWraith.State.Attack)
{
if (this.rand.RandomFloat < 0.1f)
{
this.StartAttackReposition();
}
}
else if (this.state != EntityWraith.State.Home && this.state != EntityWraith.State.AttackReposition)
{
this.SetState(EntityWraith.State.WanderStart);
}
}
}
Vector3 a2 = this.waypoint - this.position;
float magnitude = a2.magnitude;
Vector3 vector3 = a2 * (1f / magnitude);
this.glidingPercent = 0f;
if (vector3.y > 0.57f)
{
this.accel = 0.35f;
}
else if (vector3.y < -0.34f)
{
this.accel = 0.95f;
this.glidingPercent = 1f;
}
else
{
this.accel = 0.55f;
if (this.state == EntityWraith.State.Home || this.state == EntityWraith.State.Wander)
{
this.accel = 0.8f;
if (this.isCircling)
{
this.glidingPercent = 1f;
}
}
}
if (this.attackDelay > 0)
{
this.glidingPercent = 0f;
}
if (this.currentTarget && this.currentTarget.AttachedToEntity)
{
if (this.IsBloodMoon && this.accel > 0.5f)
{
this.accel = 2.5f;
}
this.accel *= this.moveSpeedAggro;
}
else
{
this.accel *= this.moveSpeed;
}
this.motion = this.motion * 0.9f + vector3 * (this.accel * 0.1f);
this.glidingCurrentPercent = Mathf.MoveTowards(this.glidingCurrentPercent, this.glidingPercent, 0.060000002f);
this.emodel.avatarController.UpdateFloat("Gliding", this.glidingCurrentPercent);
if (this.attackDelay > 0)
{
this.attackDelay--;
}
if (this.attack2Delay > 0)
{
this.attack2Delay--;
}
float num6 = Mathf.Atan2(this.motion.x * this.motionReverseScale, this.motion.z * this.motionReverseScale) * 57.29578f;
if (this.currentTarget)
{
num2 = this.targetSwitchDelay - 1;
this.targetSwitchDelay = num2;
if (num2 <= 0)
{
this.targetSwitchDelay = 60;
if (this.state != EntityWraith.State.AttackStop)
{
EntityPlayer entityPlayer5 = this.FindTarget();
EntityPlayer closestPlayer = null;
float numTarget = 200 * 200;
float numTarget2 = float.MaxValue;
for (int i = this.world.Players.list.Count - 1; i >= 0; i--)
{
EntityPlayer entityPlayer = this.world.Players.list[i];
if (!entityPlayer.IsDead() && entityPlayer.Spawned)
{
////Log.Out("FOUND PLAYER: " + entityPlayer.EntityName);
float distanceSq = entityPlayer.GetDistanceSq(this.position);
if (distanceSq < numTarget2 && distanceSq <= numTarget)
{
numTarget2 = distanceSq;
closestPlayer = entityPlayer;
}
}
}
entityPlayer5 = closestPlayer;
if (entityPlayer5 && entityPlayer5 != this.attackTarget)
{
base.SetAttackTarget(entityPlayer5, 400);
}
}
float num7 = this.currentTarget.AttachedToEntity ? 0.1f : 0.25f;
if (this.state != EntityWraith.State.AttackReposition && this.rand.RandomFloat < num7)
{
this.StartAttackReposition();
}
}
}
if (this.currentTarget)
{
Vector3 vector4 = this.currentTarget.getHeadPosition();
vector4 += this.currentTarget.GetVelocityPerSecond() * 0.2f;
Vector3 vector5 = vector4 - this.position;
float sqrMagnitude2 = vector5.sqrMagnitude;
if ((sqrMagnitude2 > 6400f && !this.IsBloodMoon) || this.currentTarget.IsDead())
{
this.SetState(EntityWraith.State.AttackStop);
}
else if (this.state != EntityWraith.State.AttackReposition)
{
if (sqrMagnitude2 < 4f)
{
num6 = Mathf.Atan2(vector5.x, vector5.z) * 57.29578f;
}
if (this.attackDelay <= 0 && !this.isAttack2On)
{
if (sqrMagnitude2 < 0.64000005f && this.position.y >= this.currentTarget.position.y && this.position.y < vector4.y + 0.1f)
{
this.AttackAndAdjust(false);
}
else if (this.checkBlockedDelay > 0)
{
this.checkBlockedDelay--;
}
else
{
this.checkBlockedDelay = 6;
Vector3 normalized = vector5.normalized;
Ray ray = new Ray(this.position + new Vector3(0f, 0.22f, 0f) - normalized * 0.13f, normalized);
if (Voxel.Raycast(this.world, ray, 0.83f, 1082195968, 128, 0.13f))
{
this.AttackAndAdjust(true);
}
}
}
bool flag3 = false;
ItemActionVomit.ItemActionDataVomit itemActionDataVomit = this.inventory.holdingItemData.actionData[1] as ItemActionVomit.ItemActionDataVomit;
if (itemActionDataVomit != null && this.attack2Delay <= 0 && sqrMagnitude2 >= 9f)
{
float range = ((ItemActionRanged)this.inventory.holdingItem.Actions[1]).GetRange(itemActionDataVomit);
if (sqrMagnitude2 < range * range && Utils.FastAbs(Mathf.DeltaAngle(num6, this.rotation.y)) < 20f && Utils.FastAbs(Vector3.SignedAngle(vector5, base.transform.forward, Vector3.right)) < 25f)
{
flag3 = true;
}
}
if (!this.isAttack2On && flag3)
{
this.isAttack2On = true;
itemActionDataVomit.muzzle = this.emodel.GetHeadTransform();
itemActionDataVomit.numWarningsPlayed = 999;
}
if (this.isAttack2On)
{
if (!flag3)
{
this.isAttack2On = false;
}
else
{
this.motion *= 0.7f;
this.SetLookPosition(vector4);
base.Use(false);
if (itemActionDataVomit.isDone)
{
this.isAttack2On = false;
}
}
if (!this.isAttack2On)
{
if (itemActionDataVomit.numVomits > 0)
{
this.StartAttackReposition();
}
base.Use(true);
this.attack2Delay = 60;
this.SetLookPosition(Vector3.zero);
}
}
}
}
float magnitude2 = this.motion.magnitude;
if (magnitude2 < 0.02f)
{
this.motion *= 1f / magnitude2 * 0.02f;
}
base.SeekYaw(num6, 0f, 20f);
this.aiManager.UpdateDebugName();
}
public override string MakeDebugNameInfo()
{
return string.Format("\n{0} {1}\nWaypoint {2}\nTarget {3}, AtkDelay {4}, BtlTime {5}\nSpeed {6}, Motion {7}, Accel {8}", new object[]
{
this.state.ToStringCached<EntityWraith.State>(),
this.stateTime.ToCultureInvariantString("0.00"),
this.waypoint.ToCultureInvariantString(),
this.currentTarget ? this.currentTarget.name : "",
this.attackDelay,
this.battleDuration.ToCultureInvariantString("0.00"),
this.motion.magnitude.ToCultureInvariantString("0.000"),
this.motion.ToCultureInvariantString("0.000"),
this.accel.ToCultureInvariantString("0.000")
});
}
private void SetState(EntityWraith.State newState)
{
this.state = newState;
this.stateTime = 0f;
this.motionReverseScale = 1f;
}
private void AdjustWaypoint()
{
int num = 255;
Vector3i pos = new Vector3i(this.waypoint);
while (!this.world.GetBlock(pos).isair && --num >= 0)
{
this.waypoint.y = this.waypoint.y + 1f;
pos.y++;
}
this.waypoint.y = Mathf.Min(this.waypoint.y, 250f);
}
private void StartAttackReposition()
{
this.SetState(EntityWraith.State.AttackReposition);
this.stateMaxTime = this.rand.RandomRange(0.8f, 5f);
this.attackCount = 0;
this.waypoint = this.position;
this.waypoint.x = this.waypoint.x + (this.rand.RandomFloat * 8f - 4f);
this.waypoint.y = this.waypoint.y + (this.rand.RandomFloat * 4f + 3f);
this.waypoint.z = this.waypoint.z + (this.rand.RandomFloat * 8f - 4f);
this.moveUpdateDelay = 0;
this.motion = -this.motion;
if (this.rand.RandomFloat < 0.5f)
{
this.motionReverseScale = -1f;
this.motion.y = 0.2f;
}
}
private void ClearTarget()
{
base.attackTarget = (EntityAlive) null;
base.SetRevengeTarget((EntityAlive) null);
this.currentTarget = null;
}
private EntityPlayer FindTarget()
{
EntityPlayer closestPlayer = null;
float numTarget = 200 * 200;
float numTarget2 = float.MaxValue;
for (int i = this.world.Players.list.Count - 1; i >= 0; i--)
{
EntityPlayer entityPlayer = this.world.Players.list[i];
if (!entityPlayer.IsDead() && entityPlayer.Spawned)
{
////Log.Out("FOUND PLAYER: " + entityPlayer.EntityName);
float distanceSq = entityPlayer.GetDistanceSq(this.position);
if (distanceSq < numTarget2 && distanceSq <= numTarget)
{
numTarget2 = distanceSq;
closestPlayer = entityPlayer;
}
}
}
return closestPlayer;
}
public override float GetEyeHeight()
{
return 0.3f;
}
public override Vector3 GetLookVector()
{
if (this.lookAtPosition.Equals(Vector3.zero))
{
return base.GetLookVector();
}
return this.lookAtPosition - this.getHeadPosition();
}
public override int DamageEntity(
DamageSource _damageSource,
int _strength,
bool _criticalHit,
float _impulseScale)
{
//Log.Out("EntityWraith-DamageEntity START, _strength: " + _strength);
if (!this.Buffs.HasBuff("FuriousRamsayWraithProtection"))
{
//Log.Out("EntityWraith-CanDamageEntity SHIELD IS UP");
return 0;
}
return base.DamageEntity(_damageSource, _strength, _criticalHit, _impulseScale);
}
/*public override bool CanDamageEntity(int _sourceEntityId)
{
//Log.Out("EntityWraith-CanDamageEntity START");
if (!this.Buffs.HasBuff("FuriousRamsayWraithProtection"))
{
//Log.Out("EntityWraith-CanDamageEntity SHIELD IS UP");
return false;
}
Entity entity = this.world.GetEntity(_sourceEntityId);
return !entity || entity.entityClass != this.entityClass;
}*/
private void AttackAndAdjust(bool isBlock)
{
if (base.Attack(false))
{
base.Attack(true);
this.attackDelay = 18;
this.isCircling = false;
if (this.currentTarget.AttachedToEntity)
{
this.motion *= 0.7f;
}
else
{
this.motion *= 0.6f;
}
int num = this.attackCount + 1;
this.attackCount = num;
if (num >= 5 || this.rand.RandomFloat < 0.25f)
{
this.StartAttackReposition();
}
}
}
private const float cFlyingMinimumSpeed = 0.02f;
private const float cTargetDistanceClose = 0.8f;
private const float cTargetDistanceMax = 80f;
private const float cTargetAttackOffsetY = -0.1f;
private const float cVomitMinRange = 3f;
private const int cAttackDelay = 18;
private const int cCollisionMask = 1082195968;
private const float cBattleFatigueMin = 30f;
private const float cBattleFatigueMax = 90f;
private const float cBattleFatigueCooldownMin = 60f;
private const float cBattleFatigueCooldownMax = 180f;
private bool isRadiated;
private int moveUpdateDelay;
private float motionReverseScale = 1f;
private Vector3 waypoint;
private bool isCircling;
private Vector3 circleCenter;
private float circleReverseScale;
private float glidingCurrentPercent;
private float glidingPercent;
private float accel;
private EntityAlive currentTarget;
private int targetSwitchDelay;
private int homeCheckDelay;
private int homeSeekDelay;
private int wanderChangeDelay;
private int checkBlockedDelay;
private float battleDuration;
private float battleFatigueSeconds;
private bool isBattleFatigued;
private int attackDelay;
private int attackCount;
private int attack2Delay;
private bool isAttack2On;
private EAISetNearestEntityAsTargetSorter sorter;
private static List<Entity> list = new List<Entity>();
private EntityWraith.State state;
private float stateTime;
private float stateMaxTime;
protected bool isCourseTraversable(Vector3 _pos, out float _distance)
{
float num = _pos.x - this.position.x;
float num2 = _pos.y - this.position.y;
float num3 = _pos.z - this.position.z;
_distance = Mathf.Sqrt(num * num + num2 * num2 + num3 * num3);
if (_distance < 1.5f)
{
return true;
}
num /= _distance;
num2 /= _distance;
num3 /= _distance;
Bounds boundingBox = this.boundingBox;
this.collBB.Clear();
int num4 = 1;
while ((float)num4 < _distance - 1f)
{
boundingBox.center += new Vector3(num, num2, num3);
this.world.GetCollidingBounds(this, boundingBox, this.collBB);
if (this.collBB.Count > 0)
{
return false;
}
num4++;
}
return true;
}
private List<Bounds> collBB = new List<Bounds>();
private enum State
{
Attack,
AttackReposition,
AttackStop,
Home,
Stun,
WanderStart,
Wander
}
}