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().enabled = false; return; } this.ModelTransform.GetComponentInChildren().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(), 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 list = new List(); 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 collBB = new List(); private enum State { Attack, AttackReposition, AttackStop, Home, Stun, WanderStart, Wander } }