namespace Supercell.Laser.Logic.Battle.Structures { using System.Diagnostics.CodeAnalysis; using System.Net.Http.Headers; using System.Reflection.Metadata.Ecma335; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Security.Cryptography; using System.Xml.Linq; using Supercell.Laser.Logic.Battle.Component; using Supercell.Laser.Logic.Battle.Level; using Supercell.Laser.Logic.Battle.Objects; using Supercell.Laser.Logic.Battle.Structures; using Supercell.Laser.Logic.Data; using Supercell.Laser.Logic.Data.Helper; using Supercell.Laser.Logic.Util; using Supercell.Laser.Titan.DataStream; using Supercell.Laser.Titan.Debug; using Supercell.Laser.Titan.Math; public class Accessory { public AccessoryData AccessoryData; public int Uses; public int CoolDown; public int State; public string Type => AccessoryData.Type; public int ActivationDelay; public int X; public int Y; public int StartUsingTick; public int Angle; public bool IsActive; public int TicksActive; public int RewindX; public int RewindY; public int RewindHP; public int TrailX; public int TrailY; private int VisionTick; public Accessory(AccessoryData accessoryData) { X = 0; Y = 0; State = 0; ActivationDelay = 0; StartUsingTick = 0; CoolDown = 0; Uses = 3; Angle = 0; IsActive = false; TicksActive = 0; AccessoryData = accessoryData; } public void UpdateAccessory(Character character) { State = CheckCurrentAccessoryAvailability(character); CoolDown = LogicMath.Max(0, CoolDown - 1); if (IsActive) { if (ActivationDelay < 1) { if (TicksActive >= AccessoryData.ActiveTicks && AccessoryData.Type != "ulti_change") { IsActive = false; CoolDown = AccessoryData.Cooldown; } else { TickAccessory(character); TicksActive++; } } else { ActivationDelay--; if (ActivationDelay == 0) ActivateAccessory(character); } } if (character.m_isBot == 2 || (character.GetPlayer()?.IsAdmin ?? false)) { if (character.GetPlayer()?.IsAdmin ?? false) CoolDown = 0; Uses = 3; State = 0; } } public void TickAccessory(Character character) { switch (Type) { case "spin_shoot": character.SetForcedAngle(LogicMath.NormalizeAngle360(character.MoveAngle + 90)); if (TicksActive % AccessoryData.CustomValue1 == 0) { ProjectileData v17 = DataTables.GetProjectileByName(AccessoryData.CustomObject); if (v17?.Name == character.m_skills[0].SkillData.Projectile) { if (character.GetPlayer()?.SkinConfData?.MainAttackProjectile != null) v17 = DataTables.GetProjectileByName(character.GetPlayer()?.SkinConfData?.MainAttackProjectile); } if (v17 != null) { StartUsingTick = character.TicksGone; int v25 = (TicksActive / AccessoryData.CustomValue1) * AccessoryData.CustomValue2; int v27 = AccessoryData.CustomValue4 + AccessoryData.CustomValue5 * (TicksActive / AccessoryData.CustomValue1); TileMap v29 = character.GetBattle().GetTileMap(); int v33 = 1;//todo:Play Field Mirrored for player int v34 = LogicMath.GetRotatedX(v27, 0, v25) * v33; int v35 = LogicMath.GetRotatedY(v27, 0, v25) * v33; int v36 = character.GetX() + v34; int v37 = character.GetY() + v35; int v38 = LogicMath.Clamp(v36, 1, v29.LogicWidth - 2); int v39 = LogicMath.Clamp(v37, 1, v29.LogicHeight - 2); int v40 = 300 * v34 / v27 + character.GetX(); int v43 = 300 * v35 / v27 + character.GetY(); Projectile v46 = Projectile.ShootProjectile(v40, v43, character, character, v17, v38, v39, AccessoryData.CustomValue3, AccessoryData.CustomValue6, 0, false, 0, character.GetBattle(), 0, 4); if (character.GetCardValueForPassive("pushback_self", 1) >= 0) v46.AreaEffectCantPushback = true; v46.RunEarlyTicks(); } } break; case "vision": if (VisionTick + AccessoryData.ActiveTicks >= character.GetBattle().GetTicksGone()) { foreach (Character _character in character.GetBattle().GetGameObjectManager().GetCharacters()) { if (_character != null && _character.IsAlive()) { _character.YellowEye = true; _character.IncrementFadeCounter(); } } } else { foreach (Character _character in character.GetBattle().GetGameObjectManager().GetCharacters()) { if (_character != null && _character.IsAlive()) _character.YellowEye = false; } } break; case "repeat_shot": if (TicksActive % AccessoryData.CustomValue1 != 0) return; int v79, v80, v83, v85, v87; if (AccessoryData.SubType != 1) { if (AccessoryData.SubType != 2) return; v79 = 0; v80 = 0; Projectile v103 = Projectile.ShootProjectile( character.GetX(), character.GetY(), character, character, DataTables.GetProjectileByName(AccessoryData.CustomObject), v79, v80, AccessoryData.CustomValue2, 0, 0, false, 0, character.GetBattle(), 0, 4); v103.RunEarlyTicks(); return; } if (AccessoryData.TargetFriends) { return; } else { Character v61 = GetClosestEnemyForAccessory(character); if (v61 != null) { v79 = v61.GetX(); v80 = v61.GetY(); if (!AccessoryData.TargetIndirect) { v83 = v79 - character.GetX(); v85 = v80 - character.GetY(); v87 = LogicMath.Sqrt(v85 * v85 + v83 * v83); v79 = v83 * AccessoryData.Range * 300 / v87 + character.GetX(); v80 = v85 * AccessoryData.Range * 300 / v87 + character.GetY(); } Angle = LogicMath.GetAngle(v61.GetX() - character.GetX(), v61.GetY() - character.GetY()); //LABEL_85: Projectile v103 = Projectile.ShootProjectile( character.GetX(), character.GetY(), character, character, DataTables.GetProjectileByName(AccessoryData.CustomObject), v79, v80, AccessoryData.CustomValue2, 0, 0, false, 0, character.GetBattle(), 0, 4); v103.RunEarlyTicks(); } if(AccessoryData.SubType == 3) { //Item v91 = new Item(DataTables.GetItemByName("SilencerHuggerMine")); //v91.SetPosition(character.GetX(), character.GetY(), 0); //character.GetGameObjectManager().AddGameObject(v91); Projectile v103 = Projectile.ShootProjectile( -1, -1, character, character, DataTables.GetProjectileByName(AccessoryData.CustomObject), character.GetX(), character.GetY(), AccessoryData.CustomValue2, 0, 0, false, 0, character.GetBattle(), 0, 4); v103.RunEarlyTicks(); } } break; case "rewind": State = 0; CoolDown = AccessoryData.Cooldown; if (TicksActive == AccessoryData.ActiveTicks - 1) { AreaEffectData v12 = DataTables.GetAreaEffectByName(AccessoryData.CustomObject); character.TriggerBlink(RewindX, RewindY, v12, v12, 0, 0); character.m_hitpoints = RewindHP; foreach (GameObject gameObject in character.GetGameObjectManager().GetGameObjects()) { if (gameObject.GetObjectType() != 2) continue; AreaEffect areaEffect = (AreaEffect)gameObject; if (areaEffect.AreaEffectData.Name != AccessoryData.AreaEffect || areaEffect.GetIndex() != character.GetIndex()) continue; character.GetGameObjectManager().RemoveGameObject(areaEffect); } } break; case "trail": if (GamePlayUtil.GetDistanceSquaredBetween(character.GetX(), character.GetY(), TrailX, TrailY) <= AccessoryData.CustomValue1 * AccessoryData.CustomValue1) { break; } character.TriggerAreaEffect(DataTables.GetAreaEffectByName(AccessoryData.CustomObject), character.GetX(), character.GetY(), 0, 4); TrailX = character.GetX(); TrailY = character.GetY(); StartUsingTick = character.TicksGone; break; case "repeat_area": if (TicksActive % AccessoryData.CustomValue1 == 0) { AreaEffectData v7 = DataTables.GetAreaEffectByName(AccessoryData.AreaEffect); if (v7 != null) { character.TriggerAreaEffect(v7, character.GetX(), character.GetY(), 0, 4); StartUsingTick = character.TicksGone; } } break; } } public int GetActivationAngle(Character character) { if (X == 0 && Y == 0) return character.MoveAngle; return LogicMath.GetAngle(X, Y); } public void ActivateAccessory(Character character) { RewindHP = 0; switch (Type) { case "respawn_environment": RespawnEnvironmentArea(character.GetX(), character.GetY(), character.GetBattle().GetTileMap()); break; case "vision": VisionTick = character.GetBattle().GetTicksGone(); break; case "jump": character.TriggerPushback(character.GetX() - LogicMath.GetRotatedX(1000, 0, GetActivationAngle(character)), character.GetY() - LogicMath.GetRotatedY(1000, 0, GetActivationAngle(character)), AccessoryData.CustomValue1, true, 0, true, true, false, true, true, false, false, 0); break; case "dash": int Angle = GetActivationAngle(character); int Dis = AccessoryData.CustomValue1; character.TriggerCharge(character.GetX() + LogicMath.GetRotatedX(Dis, 0, Angle), character.GetY() + LogicMath.GetRotatedY(Dis, 0, Angle), AccessoryData.CustomValue2, 5, AccessoryData.CustomValue4, AccessoryData.CustomValue3, false); break; case "teleport_to_pet": Character character1 = character.GetActivePet(false); if (character1 == null) break; AreaEffectData v14 = DataTables.GetAreaEffectByName(AccessoryData.CustomObject); character.TriggerBlink(character1.GetX(), character1.GetY(), v14, v14, 0, 0); break; case "cc_immunity": break; case "heal": if (AccessoryData.SubType == 1) character.Heal(character.GetIndex(), AccessoryData.CustomValue1 == 0 ? (character.m_maxHitpoints - character.m_hitpoints) : AccessoryData.CustomValue1, true, null); else if (AccessoryData.SubType == 2) character.AddExtraHealthRegen(AccessoryData.CustomValue1, AccessoryData.ActiveTicks, character.GetIndex()); break; case "spawn": switch (AccessoryData.SubType) { case 1: Character v136 = Character.SummonMinion( DataTables.GetCharacterByName(AccessoryData.CustomObject), character.GetX(), character.GetY() + 150, 0, 1, 1, 0, 0, character.GetBattle(), character.GetIndex() % 16, character.GetIndex() / 16, character.GetGlobalID(), true, false, 0, false, 0 ); break; case 4: Character v137 = GetClosestEnemyForAccessory(character); if (v137 != null) { AreaEffect v141 = GameObjectFactory.CreateGameObjectByData(DataTables.GetAreaEffectByName(AccessoryData.CustomObject)); v141.SetPosition(v137.GetX(), v137.GetY(), 0); v141.SetIndex(character.GetIndex()); v141.SetSource(character, 4); v141.SetDamage(AccessoryData.CustomValue1); v141.NormalDMG = 0; character.GetGameObjectManager().AddGameObject(v141); v141.Trigger(); } break; case 5: for (int i = 0; i < AccessoryData.CustomValue1; i++) { int x = character.GetX() + LogicMath.GetRotatedX(AccessoryData.CustomValue2, 0, i * AccessoryData.CustomValue3 - AccessoryData.CustomValue3 / 4); int y = character.GetY() + LogicMath.GetRotatedY(AccessoryData.CustomValue2, 0, i * AccessoryData.CustomValue3 - AccessoryData.CustomValue3 / 4); Character.SummonMinion( DataTables.GetCharacterByName(AccessoryData.CustomObject), x, y, 0, 1, AccessoryData.CustomValue1, 0, 0, character.GetBattle(), character.GetIndex() % 16, character.GetIndex() / 16, character.GetGlobalID(), true, false, 0, false, 0 ); } break; } break; case "throw_opponent": Character v60 = GetClosestEnemyForAccessory(character); if (v60 != null) { int v63 = v60.GetX() - character.GetX(); int v65 = v60.GetY() - character.GetY(); if (v65 == 0 && v63 == 0) ; character.SetForcedAngle(LogicMath.GetAngle(v63, v65)); v60.TriggerPushback(v60.GetX() + v63, v60.GetY() + v65, AccessoryData.CustomValue1, true, 0, true, false, false, true, false, false, false, 0); } break; case "consume_bush": Tile tile = GetClosestBush(character.GetX(), character.GetY(), character.GetBattle().GetTileMap()); if (tile == null) break; tile.Destruct(); character.Heal(character.GetIndex(), 900, true, null); break; case "promote_minion": break; case "reload": character.GetSkill("Attack").AddCharge(character, AccessoryData.CustomValue1); break; case "kill_projectile": Projectile v11 = character.GetControlledProjectile(); if (v11 != null) { AreaEffectData v141 = DataTables.GetAreaEffectByName(AccessoryData.CustomObject); character.TriggerBlink(v11.GetX(), v11.GetY(), v141, v141, 0, 0); v11.TargetReached(5); } break; case "teleport_forward": break; case "poison_trigger": foreach (GameObject gameObject in character.GetGameObjectManager().GetGameObjects()) { if (gameObject.GetObjectType() != 0) continue; Character v100 = (Character)gameObject; if (v100.IsAlive() && v100.GetIndex() / 16 != character.GetIndex() / 16) { if (v100.Poisons.Count >= 1) { foreach (Poison poison in v100.Poisons) { if (poison.SourceIndex == character.GetIndex() % 16) { v100.GiveSpeedSlowerBuff(-AccessoryData.CustomValue1, AccessoryData.CustomValue2); break; } } } } } break; case "reload_speed": character.GiveReloadBuff(AccessoryData.CustomValue1); break; case "rewind": RewindX = character.GetX(); RewindY = character.GetY(); RewindHP = character.m_hitpoints; break; case "shield_pet": Character v105 = character.GetActivePet(false); if (v105 != null) { v105.AddShield(AccessoryData.ActiveTicks, AccessoryData.CustomValue1); } break; case "following_area": AreaEffectData v110 = DataTables.GetAreaEffectByName(AccessoryData.CustomObject); if (v110 != null) { character.AddAreaEffect(0, 0, v110, 4, false); } break; case "reposition_wall": TileMap v112 = character.GetBattle().GetTileMap(); if (v112.NewTiles.Count >= 1) { foreach (Tile tile1 in v112.NewTiles) { if (tile1.PlacerIndex == character.GetIndex()) { tile1.Destruct(); } } } character.GetPlayer()?.ChargeUlti(4000, false, true); break; case "consumable_shield": character.AddConsumableShield(AccessoryData.CustomValue1, AccessoryData.CustomValue2); break; case "movement_speed": character.GiveSpeedFasterBuff(AccessoryData.CustomValue1 * character.CharacterData.Speed / 100, AccessoryData.CustomValue2 * 20, false); character.GiveReloadBuff(AccessoryData.CustomValue2 * 20); break; /*case "random_ulti": string skill = null; SkillData skillData = character.m_skills[1].SkillData; switch (character.GetBattle().GetRandomInt(0, 4)) { case 0: skill = skillData.SecondarySkill; break; case 1: skill = skillData.SecondarySkill2; break; case 2: skill = skillData.SecondarySkill3; break; case 3: skill = skillData.SecondarySkill4; break; } character.m_skills[1] = new Skill(DataTables.Get(DataType.Skill).GetData(skill).GetGlobalId(), true, character); break;*/ case "random_buff": switch (character.GetBattle().GetRandomInt(0, 4)) { case 0: character.GiveDamageBuff(AccessoryData.CustomValue2, AccessoryData.CustomValue1); break; case 1: character.AddExtraHealthRegen(AccessoryData.CustomValue3, AccessoryData.CustomValue1, character.GetIndex()); break; case 2: character.GiveSpeedFasterBuff(AccessoryData.CustomValue4, AccessoryData.CustomValue1, true); break; case 3: character.GiveReloadBuff(AccessoryData.CustomValue1); break; } break; case "explode_souls": if (AccessoryData.SubType == 0) { Character c = character.GetClosestVisibleEnemy(); if (c == null) break; foreach (GameObject gameObject in character.GetGameObjectManager().GetGameObjects()) { if (gameObject.GetIndex() == character.GetIndex() && gameObject.GetObjectType() == 3) { Projectile.ShootProjectile(gameObject.GetX(), gameObject.GetY(), character, gameObject, DataTables.GetProjectileByName("SoulCollectorProjectile"), c.GetX(), c.GetY(), 1410, 0, 0, false, 0, character.GetBattle(), 0, 4).RunEarlyTicks(); character.GetGameObjectManager().RemoveGameObject(gameObject); } } } break; } //if ((Type - 1) <= 0x15) // __asm { ADD PC, R2, R1 } if (Type != "repeat_area") { AreaEffectData v150 = DataTables.GetAreaEffectByName(AccessoryData.AreaEffect); if (v150 != null) { character.TriggerAreaEffect(v150, character.GetX(), character.GetY(), 0, 4); } } AreaEffectData v155 = DataTables.GetAreaEffectByName(AccessoryData.PetAreaEffect); if (v155 != null) { Character v157 = character.GetActivePet(false); if (v157 != null) { v157.TriggerAreaEffect(v155, v157.GetX(), v157.GetY(), 0, 4); } } if (AccessoryData.ShieldPercent >= 1) { character.AddShield(AccessoryData.ShieldTicks, AccessoryData.ShieldPercent); } if (AccessoryData.SpeedBoost >= 1) { character.GiveSpeedFasterBuff(AccessoryData.SpeedBoost, AccessoryData.SpeedBoostTicks, false); } //if (sub_3197D4(a1->AccessoryData)) // sub_2CF254(*a2->Skill); if (AccessoryData.ActiveTicks < 1 && AccessoryData.Type != "ulti_change") { IsActive = false; CoolDown = AccessoryData.Cooldown; } else { TicksActive = 0; TickAccessory(character); ++TicksActive; } //result = sub_445958(a1->AccessoryData); //if (result) //{ // result = ZNK20LogicCharacterServer12getActivePetEb(a2, 0); // if (result) // return ZN20LogicCharacterServer11causeDamageEiiiPS_biiPK9LogicDatabbbbb( // result, // -1, // &stru_18698.r_info + 3, // 0, // 0, // 0, // 0, // 0, // 0, // 1, // 0, // 1, // 0, // 0); //} //return result; if ((character.GetPlayer()?.IsAdmin ?? false)) { CoolDown = 0; State = 0; } } public Character GetClosestEnemyForAccessory(Character character) { Character e = character.GetClosestEnemy(); if (e == null || e.GetPosition().GetDistance(character.GetPosition()) > AccessoryData.Range * 300) return null; return e; } public static Tile GetClosestBush(int a2, int a3, TileMap a4) { int X = a2 / 300; int Y = a3 / 300; TileMap tileMap = a4; //if (!CharacterData.IsTrain()) // v81 = v110 - 100; int XMin = LogicMath.Clamp(X - 1, 0, tileMap.Width - 1); int YMin = LogicMath.Clamp(Y - 1, 0, tileMap.Height - 1); int XMax = LogicMath.Clamp(X + 1, 0, tileMap.Width - 1); int YMax = LogicMath.Clamp(Y + 1, 0, tileMap.Height - 1); int v14 = 999999999; Tile result = null; for (int i = XMin; i <= XMax; i++) { for (int j = YMin; j <= YMax; j++) { Tile tile = tileMap.GetTile(i, j, true); if (tile == null || !tile.Data.HidesHero || tile.IsDestructed()) continue; if (GamePlayUtil.GetDistanceSquaredBetween(tile.X + 150, tile.Y + 150, X * 300 + 150, Y * 300 + 150) < v14) { result = tile; v14 = GamePlayUtil.GetDistanceSquaredBetween(tile.X + 150, tile.Y + 150, X * 300 + 150, Y * 300 + 150); } } } return result; } public static Tile GetClosestTile(int a2, int a3, TileMap a4) { int X = a2 / 300; int Y = a3 / 300; TileMap tileMap = a4; //if (!CharacterData.IsTrain()) // v81 = v110 - 100; int XMin = LogicMath.Clamp(X - 1, 0, tileMap.Width - 1); int YMin = LogicMath.Clamp(Y - 1, 0, tileMap.Height - 1); int XMax = LogicMath.Clamp(X + 1, 0, tileMap.Width - 1); int YMax = LogicMath.Clamp(Y + 1, 0, tileMap.Height - 1); int v14 = 999999999; Tile result = null; for (int i = XMin; i <= XMax; i++) { for (int j = YMin; j <= YMax; j++) { Tile tile = tileMap.GetTile(i, j, true); if (tile == null || tile.IsDestructed() || !tile.BlocksVision()) continue; if (GamePlayUtil.GetDistanceSquaredBetween(tile.X + 150, tile.Y + 150, X * 300 + 150, Y * 300 + 150) < v14) { result = tile; v14 = GamePlayUtil.GetDistanceSquaredBetween(tile.X + 150, tile.Y + 150, X * 300 + 150, Y * 300 + 150); } } } return result; } public static void RespawnEnvironmentArea(int x, int y, TileMap tileMap) { int tileX = x / 300; int tileY = y / 300; int minX = LogicMath.Clamp(tileX - 1, 0, tileMap.Width - 1); int maxX = LogicMath.Clamp(tileX + 1, 0, tileMap.Width - 1); int minY = LogicMath.Clamp(tileY - 1, 0, tileMap.Height - 1); int maxY = LogicMath.Clamp(tileY + 1, 0, tileMap.Height - 1); for (int i = minX; i <= maxX; i++) { for (int j = minY; j <= maxY; j++) { if ((i == tileX || j == tileY) && Math.Abs(i - tileX) + Math.Abs(j - tileY) <= 1) { Tile tile = tileMap.GetTile(i, j, true); if (tile != null && tile.IsDestructed()) { tile.Construct(); } } } } } public static Tile GetClosestTileToRespawn(int a2, int a3, TileMap a4) { int X = a2 / 300; int Y = a3 / 300; TileMap tileMap = a4; //if (!CharacterData.IsTrain()) // v81 = v110 - 100; int XMin = LogicMath.Clamp(X - 1, 0, tileMap.Width - 1); int YMin = LogicMath.Clamp(Y - 1, 0, tileMap.Height - 1); int XMax = LogicMath.Clamp(X + 1, 0, tileMap.Width - 1); int YMax = LogicMath.Clamp(Y + 1, 0, tileMap.Height - 1); int v14 = 999999999; Tile result = null; for (int i = XMin; i <= XMax; i++) { for (int j = YMin; j <= YMax; j++) { Tile tile = tileMap.GetTile(i, j, true); if (tile == null || !tile.IsDestructed()) continue; if (GamePlayUtil.GetDistanceSquaredBetween(tile.X + 150, tile.Y + 150, X * 300 + 150, Y * 300 + 150) < v14) { result = tile; v14 = GamePlayUtil.GetDistanceSquaredBetween(tile.X + 150, tile.Y + 150, X * 300 + 150, Y * 300 + 150); } } } return result; } public int CheckCurrentAccessoryAvailability(Character character) { int result; // x0 int v5; // w22 Character v6; // x0 int v7; // x21 int v8; // w22 int v9; // w23 int v10; // w24 int v11; // w0 int v12; // w22 int v13; // w0 int v14; // w8 int v15; // x0 int v16; // x20 int v17; // w21 int v18; // x0 Skill v19; // x0 Projectile v20; // x0 int v21; // x0 int v22; // x0 int v23; // x20 int v24; // x22 char v25; // w23 int v26; // x21 int v27; // x8 int v28; // x10 bool v29; // w11 int v30; // x0 int v31; // x0 int v32; // x22 //_QWORD* v33; // x20 int v34; // x24 char v35; // w23 char v36; // w25 int v37; // x21 int v38; // w8 bool v39; // zf int v40; // w8 SkillData v41; // x0 SkillData v42; // x19 int active; // w20 int v44; // w20 int v45; // x0 int v46; // x0 int v47; // x8 int v48; // x9 int v49; // x10 int v50; // x11 if (character.GetZ() > 0 || character.IsChargeActive()) return 5; if (character == null || !character.IsAlive()) return 3; if (IsActive) return 1; if (Uses < 1) return 4; if (CoolDown > 0) return 5; //if (*(character + 776)) // return 6; if (character.IsPlayerControlRemoved() && (!character.IsCharging || AccessoryData.UsableDuringCharge == 0) && (Type != "cc_immunity" || character.IsCharging)) { return 2; } if (AccessoryData.RequirePetDistance >= 1) { v6 = character.GetActivePet(Type == "promote_minion"); if (v6 == null) return 7; //if (v5 == 14 && *(v6 + 764) > 0) // return 11; v12 = GamePlayUtil.GetDistanceSquaredBetween(character.GetX(), character.GetY(), v6.GetX(), v6.GetY()); v13 = AccessoryData.RequirePetDistance; if (v12 > 300 * v13 * 300 * v13) return 8; if (v6.GetZ() > 100) return 2; } if (AccessoryData.ConsumesAmmo && character.GetWeaponSkill().Charge < 1000) return 9; if (AccessoryData.RequireEnemyInRange && GetClosestEnemyForAccessory(character) == null) { return 8; } if (AccessoryData.UsableDuringCharge == 2 && !character.IsCharging) return 14; if (AccessoryData.SkipTypeCondition) return 0; switch (Type) { case "heal": if (character.m_hitpoints != character.m_maxHitpoints) return 0; return 10; case "reload": v19 = character.GetSkill("Attack"); if (!v19.HasFullCharge()) { goto LABEL_48; } return 12; case "consume_bush": if (GetClosestBush(character.GetX(), character.GetY(), character.GetBattle().GetTileMap()) != null) return 0; return 8; default: LABEL_48: switch (Type) { case "movement_speed": if (AccessoryData.SubType == 1) { if (character.CharacterData.UniqueProperty == 7) return 7; } return 0; case "dash": if (AccessoryData.SubType == 1) { if (character.CharacterData.UniqueProperty != 7) return 7; } return 0; case "kill_projectile": v20 = character.GetControlledProjectile(); if (v20 != null && v20.State == 0) return 0; return 7; case "teleport_forward": case "turret_barrage": case "pet_attack_speed": case "reload_speed": case "rewind": case "shield_pet": case "following_area": return 0; case "poison_trigger": foreach (GameObject gameObject in character.GetGameObjectManager().GetGameObjects()) { if (gameObject.GetObjectType() != 0) continue; Character v100 = (Character)gameObject; if (v100.IsAlive() && v100.GetIndex() / 16 != character.GetIndex() / 16) { if (v100.Poisons.Count >= 1) { foreach (Poison poison in v100.Poisons) { if (poison.SourceIndex == character.GetIndex() % 16) { return 0; } } } } } return 7; case "mine_trigger": //v30 = sub_710988(character); //v31 = sub_48868C(v30); //v32 = *(v31 + 12); //if (v32 < 1) // return 7; //v33 = v31; //v34 = 0; //v35 = 0; //v36 = 0; //do //{ // v37 = *(*v33 + 8 * v34); // v38 = *(sub_2FCB54(v37) + 84); // v39 = v38 == 25 || v38 == 6; // if (v39 && *(v37 + 60) == *(character + 60)) // { // v40 = *(v37 + 76); // v36 |= v40 > 0; // v35 |= v40 < 1; // } // ++v34; //} //while (v32 != v34); //if (v36 & 1 | ((v35 & 1) == 0)) // return 7; //return 0; return 7; case "next_attack_change": v41 = character.GetCurrentActiveOrCastingSkill(); if (v41 == null) return 0; v42 = v41; active = v41.ActiveTime; if (active < (2 * v42.MsBetweenAttacks)) return 0; return 2; case "reposition_wall": TileMap v112 = character.GetBattle().GetTileMap(); if (v112.NewTiles.Count >= 1) { foreach (Tile tile in v112.NewTiles) { if (tile.PlacerIndex == character.GetIndex()) { return 0; } } } return 7; default: if (Type != "spawn" || AccessoryData.SubType != 3 || false) return 0; return 13; } //while (1) //{ // v50 = *(v48 + 8 * v49); // if (v50) // { // if (*(v50 + 72) == v44) // break; // } // if (++v49 >= v47) // return result; //} return 0; } } public void TriggeredAgain(Character character) { if (Type == "rewind") { TicksActive = AccessoryData.ActiveTicks - 1; } } public void TriggerAccessory(Character character, int X, int Y) { if (IsActive && Type == "rewind") { TriggeredAgain(character); return; } State = CheckCurrentAccessoryAvailability(character); //v8 = ZNK20LogicCharacterServer22getCurrentCastingSkillEv(a2); //if (v8) // result = *(v8 + 120) == 2; //else // result = 0; bool result = false; if (character != null) { if (State == 0 || (character.GetPlayer()?.IsAdmin ?? false)) { result |= CoolDown > 0; if (!result || (character.GetPlayer()?.IsAdmin ?? false)) { // 来真的了 if (AccessoryData.InterruptsAction) character.InterruptAllSkills(); if (AccessoryData.StopMovement) character.StopMovement(); IsActive = true; this.X = X; this.Y = Y; //a1->field_44 = 0; StartUsingTick = character.TicksGone; int v13 = AccessoryData.ActivationDelay; if (v13 <= 0) { ActivateAccessory(character); } else { ActivationDelay = v13; //if (ZNK18LogicAccessoryData18getStopPetForDelayEv(v14)) //{ // v15 = ZNK20LogicCharacterServer12getActivePetEb(a2, 0); // if (v15) // { // v16 = v15; // v17 = *(v15 + 301); // v18 = v17 == 0; // if (!v17) // v18 = *(v16 + 300) == 0; // if (v18) // { // ZN20LogicCharacterServer12stopMovementEv(v16); // *(v16 + 360) = 0; // } // } //} } character.BlockHealthRegen(); Uses--; } } } } public void EndAccessoryActivation() { if (IsActive) { IsActive = false; CoolDown = AccessoryData.Cooldown; } } public void Interrupt(bool a2, Character a3) { bool result; // r0 result = false; if (Type == "next_attack_change" || Type == "ulti_change") result = a3.m_hitpoints > 0; if (!result) { result = IsActive; if (IsActive) { if (!a2) { IsActive = false; CoolDown = AccessoryData.Cooldown; } } } } /* public void Encode(BitStream stream, bool IsOwn) //это пиздец { stream.WritePositiveIntMax7(Uses); if (IsOwn) // BitStream::ReadBoolean(a2); { stream.WritePositiveVIntMax65535(CoolDown); stream.WritePositiveVIntMax255OftenZero(State); } else { stream.WriteBoolean(State == 1); } if (State == 1) { stream.WritePositiveInt(StartUsingTick, 14); stream.WritePositiveInt(Angle, 9); } }*/ public void Encode(BitStream bitStream, bool isOwn) { bitStream.WritePositiveIntMax7(Uses); if (isOwn) { bitStream.WritePositiveVIntMax255OftenZero(CoolDown); if (bitStream.WritePositiveVIntMax255OftenZero(State) != 1) return; bitStream.WritePositiveIntMax16383(StartUsingTick); bitStream.WritePositiveIntMax511(Angle); } else { if (!bitStream.WriteBoolean(IsActive && AccessoryData.Type == "next_attack_change")) return; bitStream.WritePositiveIntMax16383(0); bitStream.WritePositiveIntMax511(0); } } } } /* using Supercell.Laser.Logic.Battle.Component; using Supercell.Laser.Logic.Battle.Level; using Supercell.Laser.Logic.Battle.Objects; using Supercell.Laser.Logic.Data; using Supercell.Laser.Logic.Data.Helper; using Supercell.Laser.Logic.Util; using Supercell.Laser.Titan.DataStream; using Supercell.Laser.Titan.Math; namespace Supercell.Laser.Logic.Battle.Structures { public class Accessory { public AccessoryData AccessoryData; public int Uses; public int CoolDown; public string Type => AccessoryData.Type; public int State; public int ActivationDelay; public int X, Y; public int StartUsingTick; public int Angle; public bool IsActive; public int TicksActive; public int RewindX, RewindY, RewindHP; public int TrailX, TrailY; private int VisionTick; public Accessory(AccessoryData data) { AccessoryData = data; Uses = data.ChargeCount; CoolDown = 0; State = 0; ActivationDelay = 0; X = Y = 0; StartUsingTick = 0; Angle = 0; IsActive = false; TicksActive = 0; } public void UpdateAccessory(Character character) { State = CheckCurrentAccessoryAvailability(character); CoolDown = LogicMath.Max(0, CoolDown - 1); if (IsActive) { if (ActivationDelay > 0) { ActivationDelay--; if (ActivationDelay == 0) ActivateAccessory(character); } else { if (TicksActive >= AccessoryData.ActiveTicks && AccessoryData.Type != "ulti_change") { IsActive = false; CoolDown = AccessoryData.Cooldown; } else { TickAccessory(character); TicksActive++; } } } if (character.m_isBot == 2 || (character.GetPlayer()?.IsAdmin ?? false)) { if (character.GetPlayer()?.IsAdmin ?? false) CoolDown = 0; Uses = AccessoryData.ChargeCount; State = 0; } } public void TickAccessory(Character character) { var data = AccessoryData; switch (data.Type) { case "spin_shoot": if (TicksActive % data.CustomValue1 == 0) { ProjectileData proj = DataTables.GetProjectileByName(data.CustomObject); if (proj != null) { int angleOffset = (TicksActive / data.CustomValue1) * data.CustomValue2; int radius = data.CustomValue4 + data.CustomValue5 * (TicksActive / data.CustomValue1); TileMap map = character.GetBattle().GetTileMap(); int mirror = 1; int dx = LogicMath.GetRotatedX(radius, 0, angleOffset) * mirror; int dy = LogicMath.GetRotatedY(radius, 0, angleOffset) * mirror; int targetX = LogicMath.Clamp(character.GetX() + dx, 1, map.LogicWidth - 2); int targetY = LogicMath.Clamp(character.GetY() + dy, 1, map.LogicHeight - 2); Projectile.ShootProjectile( character.GetX() + dx * 300 / radius, character.GetY() + dy * 300 / radius, character, character, proj, targetX, targetY, data.CustomValue3, data.CustomValue6, 0, false, 0, character.GetBattle(), 0, 4 ).RunEarlyTicks(); } } break; case "vision": if (VisionTick + data.ActiveTicks >= character.GetBattle().GetTicksGone()) { foreach (var enemy in character.GetBattle().GetGameObjectManager().GetCharacters()) if (enemy != null && enemy.IsAlive()) { enemy.YellowEye = true; enemy.IncrementFadeCounter(); } } else { foreach (var enemy in character.GetBattle().GetGameObjectManager().GetCharacters()) if (enemy != null && enemy.IsAlive()) enemy.YellowEye = false; } break; case "repeat_shot": if (TicksActive % data.CustomValue1 != 0) return; if (data.SubType == 2 || data.SubType == 3) { ProjectileData proj = DataTables.GetProjectileByName(data.CustomObject); if (proj != null) Projectile.ShootProjectile(character.GetX(), character.GetY(), character, character, proj, character.GetX(), character.GetY(), data.CustomValue2, 0, 0, false, 0, character.GetBattle(), 0, 4).RunEarlyTicks(); } else { Character enemy = GetClosestEnemyForAccessory(character); if (enemy != null) { int tx = enemy.GetX(), ty = enemy.GetY(); if (!data.TargetIndirect) { int dx = tx - character.GetX(); int dy = ty - character.GetY(); int dist = LogicMath.Sqrt(dx * dx + dy * dy); tx = character.GetX() + dx * data.Range * 300 / dist; ty = character.GetY() + dy * data.Range * 300 / dist; } Angle = LogicMath.GetAngle(tx - character.GetX(), ty - character.GetY()); ProjectileData proj = DataTables.GetProjectileByName(data.CustomObject); if (proj != null) Projectile.ShootProjectile(character.GetX(), character.GetY(), character, character, proj, tx, ty, data.CustomValue2, 0, 0, false, 0, character.GetBattle(), 0, 4).RunEarlyTicks(); } } break; case "rewind": if (TicksActive == data.ActiveTicks - 1) { AreaEffectData blinkArea = DataTables.GetAreaEffectByName(data.CustomObject); if (blinkArea != null) character.TriggerBlink(RewindX, RewindY, blinkArea, blinkArea, 0, 0); character.m_hitpoints = RewindHP; foreach (var go in character.GetGameObjectManager().GetGameObjects()) { if (go.GetObjectType() == 2 && ((AreaEffect)go).AreaEffectData.Name == data.AreaEffect && go.GetIndex() == character.GetIndex()) character.GetGameObjectManager().RemoveGameObject(go); } } break; case "trail": if (GamePlayUtil.GetDistanceSquaredBetween(character.GetX(), character.GetY(), TrailX, TrailY) <= data.CustomValue1 * data.CustomValue1) break; character.TriggerAreaEffect(DataTables.GetAreaEffectByName(data.CustomObject), character.GetX(), character.GetY(), 0, 4); TrailX = character.GetX(); TrailY = character.GetY(); break; case "repeat_area": if (TicksActive % data.CustomValue1 == 0 && !string.IsNullOrEmpty(data.AreaEffect)) { AreaEffectData area = DataTables.GetAreaEffectByName(data.AreaEffect); if (area != null) character.TriggerAreaEffect(area, character.GetX(), character.GetY(), 0, 4); } break; case "gadget_tick_explosion": // для ClusterBombDude_Explosion if (TicksActive % data.CustomValue2 == 0) { AreaEffectData area = DataTables.GetAreaEffectByName(data.AreaEffect); if (area != null) character.TriggerAreaEffect(area, character.GetX(), character.GetY(), 0, 4); } break; default: break; } // Pet area loop if (!string.IsNullOrEmpty(data.LoopingEffectPet) && data.LoopingEffectPet == "gadget_on_loop") { Character pet = character.GetActivePet(false); if (pet != null && TicksActive % data.ActiveTicks == 0) { AreaEffectData petArea = DataTables.GetAreaEffectByName(data.PetAreaEffect); if (petArea != null) pet.TriggerAreaEffect(petArea, pet.GetX(), pet.GetY(), 0, 4); } } // Looping effect on self (e.g. Tick's explosion) if (!string.IsNullOrEmpty(data.LoopingEffect) && data.LoopingEffect == "gadget_tick_explosion") { if (TicksActive % data.CustomValue2 == 0) { AreaEffectData area = DataTables.GetAreaEffectByName(data.AreaEffect); if (area != null) character.TriggerAreaEffect(area, character.GetX(), character.GetY(), 0, 4); } } } public int GetActivationAngle(Character character) { if (X == 0 && Y == 0) return character.MoveAngle; return LogicMath.GetAngle(X, Y); } public void ActivateAccessory(Character character) { var data = AccessoryData; switch (data.Type) { case "jump": int angle = GetActivationAngle(character); character.TriggerPushback( character.GetX() - LogicMath.GetRotatedX(1000, 0, angle), character.GetY() - LogicMath.GetRotatedY(1000, 0, angle), data.CustomValue1, true, 0, true, true, false, true, true, false, false, 0); break; case "dash": { int ang = GetActivationAngle(character); int dist = data.CustomValue1; character.TriggerCharge( character.GetX() + LogicMath.GetRotatedX(dist, 0, ang), character.GetY() + LogicMath.GetRotatedY(dist, 0, ang), data.CustomValue2, 5, data.CustomValue4, data.CustomValue3, false); } break; case "teleport_to_pet": { Character pet = character.GetActivePet(false); if (pet != null) { AreaEffectData tpArea = DataTables.GetAreaEffectByName(data.CustomObject); if (tpArea != null) character.TriggerBlink(pet.GetX(), pet.GetY(), tpArea, tpArea, 0, 0); } } break; case "cc_immunity": break; case "heal": if (data.SubType == 1) { int amount = data.CustomValue1 > 0 ? data.CustomValue1 : character.m_maxHitpoints - character.m_hitpoints; character.Heal(character.GetIndex(), amount, true, null); } else if (data.SubType == 2) { character.AddExtraHealthRegen(data.CustomValue1, data.ActiveTicks, character.GetIndex()); } break; case "spawn": switch (data.SubType) { case 1: case 2: case 3: Character.SummonMinion( DataTables.GetCharacterByName(data.CustomObject), character.GetX(), character.GetY() + 150, 0, 1, 1, 0, 0, character.GetBattle(), character.GetIndex() % 16, character.GetIndex() / 16, character.GetGlobalID(), true, false, 0, false, 0); break; case 4: { Character enemy = GetClosestEnemyForAccessory(character); if (enemy != null) { AreaEffect v141 = GameObjectFactory.CreateGameObjectByData( DataTables.GetAreaEffectByName(data.CustomObject)) as AreaEffect; if (v141 != null) { v141.SetPosition(enemy.GetX(), enemy.GetY(), 0); v141.SetIndex(character.GetIndex()); v141.SetSource(character, 4); v141.SetDamage(data.CustomValue1); v141.NormalDMG = 0; character.GetGameObjectManager().AddGameObject(v141); v141.Trigger(); } } } break; case 5: { int count = data.CustomValue1; int radius = data.CustomValue2; int angleStep = data.CustomValue3; for (int i = 0; i < count; i++) { int ang = i * angleStep - angleStep / 4; int x = character.GetX() + LogicMath.GetRotatedX(radius, 0, ang); int y = character.GetY() + LogicMath.GetRotatedY(radius, 0, ang); Character.SummonMinion( DataTables.GetCharacterByName(data.CustomObject), x, y, 0, 1, count, 0, 0, character.GetBattle(), character.GetIndex() % 16, character.GetIndex() / 16, character.GetGlobalID(), true, false, 0, false, 0); } } break; } break; case "throw_opponent": { Character enemy = GetClosestEnemyForAccessory(character); if (enemy != null) { int dx = enemy.GetX() - character.GetX(); int dy = enemy.GetY() - character.GetY(); character.SetForcedAngle(LogicMath.GetAngle(dx, dy)); enemy.TriggerPushback(enemy.GetX() + dx, enemy.GetY() + dy, data.CustomValue1, true, 0, true, false, false, true, false, false, false, 0); } } break; case "consume_bush": { Tile bush = GetClosestBush(character.GetX(), character.GetY(), character.GetBattle().GetTileMap()); if (bush != null) { bush.Destruct(); character.Heal(character.GetIndex(), data.CustomValue1, true, null); } } break; case "promote_minion": // TODO: find porter and promote break; case "reload": character.GetSkill("Attack").AddCharge(character, data.CustomValue1); break; case "kill_projectile": { Projectile proj = character.GetControlledProjectile(); if (proj != null) { AreaEffectData tpArea = DataTables.GetAreaEffectByName(data.CustomObject); if (tpArea != null) character.TriggerBlink(proj.GetX(), proj.GetY(), tpArea, tpArea, 0, 0); proj.TargetReached(5); } } break; case "teleport_forward": { int ang = character.MoveAngle; int dist = data.CustomValue1; AreaEffectData tpArea = DataTables.GetAreaEffectByName(data.CustomObject); if (tpArea != null) character.TriggerBlink( character.GetX() + LogicMath.GetRotatedX(dist, 0, ang), character.GetY() + LogicMath.GetRotatedY(dist, 0, ang), tpArea, tpArea, 0, 0); } break; case "poison_trigger": { foreach (var go in character.GetGameObjectManager().GetGameObjects()) { if (go.GetObjectType() != 0) continue; Character c = (Character)go; if (c.IsAlive() && c.GetIndex() / 16 != character.GetIndex() / 16) { foreach (var poison in c.Poisons) if (poison.SourceIndex == character.GetIndex() % 16) { c.GiveSpeedSlowerBuff(-data.CustomValue1, data.CustomValue2); break; } } } } break; case "reload_speed": character.GiveReloadBuff(data.CustomValue1); break; case "shield_pet": { Character pet = character.GetActivePet(false); if (pet != null) pet.AddShield(data.ActiveTicks, data.CustomValue1); } break; case "following_area": { AreaEffectData area = DataTables.GetAreaEffectByName(data.CustomObject); if (area != null) character.AddAreaEffect(0, 0, area, 4, false); } break; case "reposition_wall": { TileMap map = character.GetBattle().GetTileMap(); foreach (var tile in map.NewTiles) if (tile.PlacerIndex == character.GetIndex()) tile.Destruct(); character.GetPlayer()?.ChargeUlti(4000, false, true); } break; case "consumable_shield": character.AddConsumableShield(data.CustomValue1, data.CustomValue2); break; case "auto_super_load_boost": // TODO: нужен метод GiveSuperChargeBoost break; case "turret_barrage": { Character turret = character.GetActivePet(false); if (turret != null) { for (int i = 0; i < data.CustomValue1; i++) turret.GetSkill("Attack")?.AddCharge(turret, 1000); } } break; case "pet_attack_speed": { Character pet = character.GetActivePet(false); if (pet != null) pet.GiveReloadBuff(data.CustomValue1); } break; case "next_attack_change": // TODO: изменить следующий снаряд/характеристики атаки break; case "mine_trigger": // TODO: найти и активировать все мины персонажа break; case "bush_slow": // TODO: нанести урон и замедлить врагов в кустах break; case "trigger_ulti_area": // TODO: активировать ульту Лу (IceDude) break; case "return_damage": // TODO: установить флаг отражения урона break; case "ulti_change": // TODO: сменить супер на альтернативный break; case "rewind": RewindX = character.GetX(); RewindY = character.GetY(); RewindHP = character.m_hitpoints; break; case "vision": VisionTick = character.GetBattle().GetTicksGone(); break; default: // Для гаджетов без типа, использующих AreaEffect (включая IceDude_Freeze) break; } // Уничтожение питомца, если указано if (data.DestroyPet) { Character pet = character.GetActivePet(false); if (pet != null) pet.CauseDamage(null, 99999, 99999, false, null, false); } // Применение AreaEffect (кроме repeat_area, он сам себя вызывает) if (!string.IsNullOrEmpty(data.AreaEffect) && data.Type != "repeat_area") { AreaEffectData area = DataTables.GetAreaEffectByName(data.AreaEffect); if (area != null) character.TriggerAreaEffect(area, character.GetX(), character.GetY(), 0, 4); } // Применение PetAreaEffect if (!string.IsNullOrEmpty(data.PetAreaEffect)) { Character pet = character.GetActivePet(false); if (pet != null) { AreaEffectData petArea = DataTables.GetAreaEffectByName(data.PetAreaEffect); if (petArea != null) pet.TriggerAreaEffect(petArea, pet.GetX(), pet.GetY(), 0, 4); } } // Щит и ускорение if (data.ShieldPercent >= 1) character.AddShield(data.ShieldTicks, data.ShieldPercent); if (data.SpeedBoost >= 1) character.GiveSpeedFasterBuff(data.SpeedBoost, data.SpeedBoostTicks, false); if (data.ActiveTicks < 1 && data.Type != "ulti_change") { IsActive = false; CoolDown = data.Cooldown; } else { TicksActive = 0; TickAccessory(character); TicksActive++; } if (character.GetPlayer()?.IsAdmin ?? false) { CoolDown = 0; State = 0; } } public Character GetClosestEnemyForAccessory(Character character) { Character enemy = character.GetClosestEnemy(); if (enemy != null && enemy.GetPosition().GetDistance(character.GetPosition()) <= AccessoryData.Range * 300) return enemy; return null; } public static Tile GetClosestBush(int x, int y, TileMap tileMap) { int tileX = x / 300, tileY = y / 300; int minX = LogicMath.Clamp(tileX - 1, 0, tileMap.Width - 1); int maxX = LogicMath.Clamp(tileX + 1, 0, tileMap.Width - 1); int minY = LogicMath.Clamp(tileY - 1, 0, tileMap.Height - 1); int maxY = LogicMath.Clamp(tileY + 1, 0, tileMap.Height - 1); int bestDist = int.MaxValue; Tile best = null; for (int i = minX; i <= maxX; i++) { for (int j = minY; j <= maxY; j++) { Tile t = tileMap.GetTile(i, j, true); if (t == null || !t.Data.HidesHero || t.IsDestructed()) continue; int dist = GamePlayUtil.GetDistanceSquaredBetween(t.X + 150, t.Y + 150, x + 150, y + 150); if (dist < bestDist) { bestDist = dist; best = t; } } } return best; } public static Tile GetClosestTile(int x, int y, TileMap tileMap) { int tileX = x / 300, tileY = y / 300; int minX = LogicMath.Clamp(tileX - 1, 0, tileMap.Width - 1); int maxX = LogicMath.Clamp(tileX + 1, 0, tileMap.Width - 1); int minY = LogicMath.Clamp(tileY - 1, 0, tileMap.Height - 1); int maxY = LogicMath.Clamp(tileY + 1, 0, tileMap.Height - 1); int bestDist = int.MaxValue; Tile best = null; for (int i = minX; i <= maxX; i++) { for (int j = minY; j <= maxY; j++) { Tile t = tileMap.GetTile(i, j, true); if (t == null || t.IsDestructed() || !t.BlocksVision()) continue; int dist = GamePlayUtil.GetDistanceSquaredBetween(t.X + 150, t.Y + 150, x + 150, y + 150); if (dist < bestDist) { bestDist = dist; best = t; } } } return best; } public int CheckCurrentAccessoryAvailability(Character character) { if (character.GetZ() > 0 || character.IsChargeActive()) return 5; if (character == null || !character.IsAlive()) return 3; if (IsActive) return 1; if (Uses < 1) return 4; if (CoolDown > 0) return 5; if (character.IsPlayerControlRemoved() && (!character.IsCharging || AccessoryData.UsableDuringCharge == 0) && (AccessoryData.Type != "cc_immunity" || character.IsCharging)) return 2; if (AccessoryData.RequirePetDistance >= 1) { Character pet = character.GetActivePet(AccessoryData.Type == "promote_minion"); if (pet == null) return 7; if (GamePlayUtil.GetDistanceSquaredBetween(character.GetX(), character.GetY(), pet.GetX(), pet.GetY()) > 300 * AccessoryData.RequirePetDistance * 300 * AccessoryData.RequirePetDistance) return 8; if (pet.GetZ() > 100) return 2; } if (AccessoryData.ConsumesAmmo && character.GetWeaponSkill().Charge < 1000) return 9; if (AccessoryData.RequireEnemyInRange && GetClosestEnemyForAccessory(character) == null) return 8; if (AccessoryData.UsableDuringCharge == 2 && !character.IsCharging) return 14; if (AccessoryData.SkipTypeCondition) return 0; switch (AccessoryData.Type) { case "heal": if (character.m_hitpoints != character.m_maxHitpoints) return 0; return 10; case "reload": if (!character.GetSkill("Attack").HasFullCharge()) return 0; return 12; case "consume_bush": if (GetClosestBush(character.GetX(), character.GetY(), character.GetBattle().GetTileMap()) != null) return 0; return 8; case "kill_projectile": { Projectile p = character.GetControlledProjectile(); if (p != null && p.State == 0) return 0; return 7; } case "next_attack_change": return 0; case "reposition_wall": foreach (var tile in character.GetBattle().GetTileMap().NewTiles) if (tile.PlacerIndex == character.GetIndex()) return 0; return 7; case "poison_trigger": foreach (var go in character.GetGameObjectManager().GetGameObjects()) { if (go.GetObjectType() != 0) continue; Character c = (Character)go; if (c.IsAlive() && c.GetIndex() / 16 != character.GetIndex() / 16) { foreach (var poison in c.Poisons) if (poison.SourceIndex == character.GetIndex() % 16) return 0; } } return 7; case "mine_trigger": case "trigger_ulti_area": case "ulti_change": default: return 0; } } public void TriggeredAgain(Character character) { if (AccessoryData.Type == "rewind") TicksActive = AccessoryData.ActiveTicks - 1; } public void TriggerAccessory(Character character, int x, int y) { if (IsActive && AccessoryData.Type == "rewind") { TriggeredAgain(character); return; } State = CheckCurrentAccessoryAvailability(character); if (State == 0 || (character.GetPlayer()?.IsAdmin ?? false)) { if (AccessoryData.InterruptsAction) character.InterruptAllSkills(); if (AccessoryData.StopMovement) character.StopMovement(); IsActive = true; X = x; Y = y; StartUsingTick = character.TicksGone; ActivationDelay = AccessoryData.ActivationDelay; if (ActivationDelay <= 0) ActivateAccessory(character); character.BlockHealthRegen(); Uses--; } } public void EndAccessoryActivation() { if (IsActive) { IsActive = false; CoolDown = AccessoryData.Cooldown; } } public void Interrupt(bool forceEnd, Character character) { if (AccessoryData.Type == "next_attack_change" || AccessoryData.Type == "ulti_change") { if (character.m_hitpoints > 0) return; } if (IsActive && !forceEnd) return; IsActive = false; CoolDown = AccessoryData.Cooldown; } public void Encode(BitStream bitStream, bool isOwn) { bitStream.WritePositiveIntMax7(Uses); if (isOwn) { bitStream.WritePositiveVIntMax255OftenZero(CoolDown); if (bitStream.WritePositiveVIntMax255OftenZero(State) != 1) return; bitStream.WritePositiveIntMax16383(0); bitStream.WritePositiveIntMax511(0); } else { if (!bitStream.WriteBoolean(IsActive && AccessoryData.Type == "next_attack_change")) return; bitStream.WritePositiveIntMax16383(0); bitStream.WritePositiveIntMax511(0); } } } }*/