namespace Supercell.Laser.Logic.Battle.Objects { using System.IO; using System.Runtime.CompilerServices; using Supercell.Laser.Logic.Battle.Level; using Supercell.Laser.Logic.Data; using Supercell.Laser.Logic.Util; using Supercell.Laser.Titan.DataStream; using Supercell.Laser.Titan.Math; using Supercell.Laser.Logic.Battle.Structures; public class Item : GameObject { public ItemData ItemData; public int SpawningTick; public int SpawnTick; // tick when item spawned public int PickUpTimerDefault; public int PickUpTimer; public int PickUpStartX; public int PickUpStartY; public int PickUpZ; public int PickUpStartZ; public Character Picker; public bool PickedUp; public int MoveTimer; public int MoveTimerDefault; public int TargetX; public int TargetY; public int SpawnedTick; public int Damage; public Character Owner; public SprayData SprayData; public Character AttachedCharacter; public int AttachTicks; public int SilenceDamage; public int LastAttachDamageTicks = 20; public bool IsHealing = false; public bool IsVisible; public int LastTick; public int IsTriggeredMine; public int TriggerTicks; public bool TriggerTicksSet; public bool PortalArrive; public bool PortalClosed; public int PortalTicks; public Item TwinPortal; private int _jumpTime; private int _jumpDuration = 10; private int _jumpHeight = 500; private bool _isJumping = false; private int _startX, _startY, _startZ; private int _targetX, _targetY, _targetZ; public long TeamId = -1; private bool _isDestroyed; private int _state; public Item(ItemData itemData) : base(itemData) { ItemData = itemData; SpawningTick = 1; PickUpTimerDefault = 250; MoveTimer = 750; MoveTimerDefault = 750; } public override void Tick() { SpawnTick++; if (ItemData.Name == "BattleRoyaleBuff" || ItemData.Name == "Point" || ItemData.Name == "Scrap") { TileMap tileMap = GetBattle()?.GetTileMap(); if (tileMap == null) return; var tile = tileMap.GetTile(GetX(), GetY()); if (tile == null || tile.Data == null) return; if (tile.Data.BlocksMovement) { LogicVector2 vec = new LogicVector2(GetX(), GetY()); GamePlayUtil.GetClosestPassableSpot( 1, GetX(), GetY(), 10, tileMap, vec, false); SetPosition(vec.X, vec.Y, 0); } } if (_isJumping) { _jumpTime++; float progress = (float)_jumpTime / _jumpDuration; if (progress >= 1f) { SetPosition(_targetX, _targetY, _targetZ); _isJumping = false; return; } SetPosition(_startX + (int)((_targetX - _startX) * progress), _startY + (int)((_targetY - _startY) * progress), _startZ + (int)(_jumpHeight * 4 * progress * (1 - progress))); } if (ItemData.Name == "Healing") { var playersInZone = GameObjectManager.GetGameObjects() .Where(g => g.GetObjectType() == 0) .Cast() .Where(c => c.CharacterData.IsHero()) .Where(c => Position.GetDistance(c.GetPosition()) <= 300) .ToList(); foreach (GameObject gameObject in GameObjectManager.GetGameObjects()) { if (gameObject.GetObjectType() != 0) continue; Character c = (Character)gameObject; if (!c.CharacterData.IsHero()) continue; if (Position.GetDistance(c.GetPosition()) > 300) continue; if (GetBattle().GetTicksGone() >= LastTick + 25) c.Heal(0, 500, true, null); else return; if (IsHealing == false) IsHealing = true; LastTick = GetBattle().GetTicksGone(); } if (playersInZone.Count <= 0) IsHealing = false; } if (SpawnTick > 22 && ItemData.Name.StartsWith("StickyBomb")) { SpawnTick--; GameObjectManager.RemoveGameObject(this); if (Owner == null) return; AreaEffect v224 = GameObjectFactory.CreateGameObjectByData(DataTables.GetAreaEffectByName(DataTables.GetAreaEffectByName(ItemData.TriggerAreaEffect).Name ?? "StickyBombClusterExplosion")); v224.SetSource(Owner, 1); v224.SetPosition(GetX(), GetY(), 0); v224.SetIndex(Owner.GetIndex()); v224.Damage = Damage; GameObjectManager.AddGameObject(v224); v224.Trigger(); } if (ItemData.Name.StartsWith("StickyBomb") && AttachedCharacter != null) { SetPosition(AttachedCharacter.GetX(), AttachedCharacter.GetY(), AttachedCharacter.GetZ()); } if (ItemData.Name == "ClusterMine" || ItemData.Name.StartsWith("Tick00")) { int totalProgress = 0; if (MoveTimerDefault > 0) totalProgress = LogicMath.Min(1000, 1000 - (1000 * MoveTimer / MoveTimerDefault)); if (_state == 0) { int currentX = (PickUpStartX * (1000 - totalProgress) + TargetX * totalProgress) / 1000; int currentY = (PickUpStartY * (1000 - totalProgress) + TargetY * totalProgress) / 1000; long progress = totalProgress; int fallProgress = (int)((progress * progress) / 1000); int currentZ = (PickUpStartZ * (1000 - fallProgress)) / 1000; int peakHeight = 300; long arcOffset = (4L * peakHeight * totalProgress * (1000 - totalProgress)) / 1000000L; int finalZ = currentZ + (int)arcOffset; if (totalProgress < 1000) { SetPosition(currentX, currentY, LogicMath.Max(0, finalZ)); } else { SetPosition(TargetX, TargetY, 0); _state = 1; SpawnTick = 0; } } else if (_state == 1) { SpawnTick++; if (SpawnTick >= 110) { ExecuteClusterExplosion(); return; } foreach (Character character in GameObjectManager.GetCharacters()) { if (character.IsAlive() && character.GetTeamIndex() != TeamId && character.CharacterData.Name != "LaserBall") { if (character.GetPosition().GetDistance(Position) <= 450) { ExecuteClusterExplosion(); return; } } } } } if (SpawnTick > 22 && ItemData.Name.EndsWith("BombUlti")) { SpawnTick--; GameObjectManager.RemoveGameObject(this); if (Owner == null) return; AreaEffect v224 = GameObjectFactory.CreateGameObjectByData(DataTables.GetAreaEffectByName(DataTables.GetAreaEffectByName(ItemData.TriggerAreaEffect).Name ?? "StickyBombUltiExplosion")); v224.SetSource(Owner, 1); v224.SetPosition(GetX(), GetY(), 0); v224.SetIndex(Owner.GetIndex()); GameObjectManager.AddGameObject(v224); v224.Trigger(); } if (ItemData.Name.EndsWith("BombUlti") && AttachedCharacter != null) { SetPosition(AttachedCharacter.GetX(), AttachedCharacter.GetY(), AttachedCharacter.GetZ()); } if (SpawnTick > 22 && ItemData.Name.StartsWith("StickyBomb")) { SpawnTick--; GameObjectManager.RemoveGameObject(this); if (Owner == null) return; AreaEffect v224 = GameObjectFactory.CreateGameObjectByData(DataTables.GetAreaEffectByName(DataTables.GetAreaEffectByName(ItemData.TriggerAreaEffect).Name ?? "StickyBombClusterExplosion")); v224.SetSource(Owner, 1); v224.SetPosition(GetX(), GetY(), 0); v224.SetIndex(Owner.GetIndex()); GameObjectManager.AddGameObject(v224); v224.Trigger(); } if (ItemData.Name == "SilencerHugger" || ItemData.ParentItemForSkin == "SilencerHugger") { if (AttachedCharacter != null && AttachedCharacter.Silence) SetPosition(AttachedCharacter.GetX(), AttachedCharacter.GetY(), AttachedCharacter.GetZ()); if (AttachedCharacter != null && AttachedCharacter.SilenceTick < TicksGone) GameObjectManager.RemoveGameObject(this); if (AttachedCharacter != null && !AttachedCharacter.IsAlive()) GameObjectManager.RemoveGameObject(this); } if (SpawnTick > 20 && ItemData.Name.StartsWith("Piper")) { SpawnTick--; GameObjectManager.RemoveGameObject(this); if (Owner == null) return; AreaEffect v224 = GameObjectFactory.CreateGameObjectByData(DataTables.GetAreaEffectByName(DataTables.GetAreaEffectByName(ItemData.TriggerAreaEffect).Name ?? "Piper_def_ulti")); v224.SetPosition(GetX(), GetY(), 0); v224.SetIndex(Owner.GetIndex()); v224.Damage = 900; v224.NormalDMG = 0; GameObjectManager.AddGameObject(v224); v224.Trigger(); } if (ItemData.Name == "Mine" || ItemData.Name == "ElectroTrap" || ItemData.ParentItemForSkin == "Mine") { if (SpawnTick >= 20 && IsTriggeredMine <= 0) IsVisible = false; else IsVisible = true; if (SpawnTick >= 20) { var playersInZone = GameObjectManager.GetGameObjects() .Where(g => g.GetObjectType() == 0) .Cast() .Where(c => c.CharacterData.IsHero()) .Where(c => Position.GetDistance(c.GetPosition()) <= 600) .Where(c => c.GetIndex() / 16 != GetIndex() / 16) .ToList(); if (playersInZone.Count >= 1 && !TriggerTicksSet) { IsTriggeredMine = 100; TriggerTicks = TicksGone + 22; TriggerTicksSet = true; IsVisible = true; } if (IsTriggeredMine > 0 && TriggerTicks <= TicksGone) { SpawnTick--; GameObjectManager.RemoveGameObject(this); AreaEffect v224 = GameObjectFactory.CreateGameObjectByData(DataTables.GetAreaEffectByName(DataTables.GetAreaEffectByName(ItemData.TriggerAreaEffect).Name ?? "Bo_def_ulti2_area")); v224.SetPosition(GetX(), GetY(), 0); v224.SetIndex(GetIndex()); v224.SetSource(Owner,1); v224.Damage = 900; v224.NormalDMG = 0; GameObjectManager.AddGameObject(v224); v224.Trigger(); } } } if(ItemData.Name == "BattleRoyaleBuff") { SetPosition(GetX(), GetY(), GetZ()); PickUpStartX = GetX(); PickUpStartY = GetY(); PickUpStartZ = 1000 * GetZ(); int angle = GetBattle().GetRandomInt(360); TargetX = GetX() + LogicMath.GetRotatedX(600, 0, angle); TargetY = GetY() + LogicMath.GetRotatedY(600, 0, angle); } if (ItemData.Name == "OrbSpawner") { if (SpawningTick == 1) SpawningTick = 40; if (TicksGone < SpawningTick) goto LABEL_235; Item v269 = GameObjectFactory.CreateGameObjectByData(DataTables.GetItemByName("Point")); v269.SetPosition(GetX(), GetY(), GetZ()); v269.PickUpStartX = GetX(); v269.PickUpStartY = GetY(); v269.PickUpStartZ = 1000 * GetZ(); int angle = GetBattle().GetRandomInt(360); v269.TargetX = GetX() + LogicMath.GetRotatedX(600, 0, angle); v269.TargetY = GetY() + LogicMath.GetRotatedY(600, 0, angle); GameObjectManager.AddGameObject(v269); SpawningTick = TicksGone + 140; SpawnedTick = TicksGone; } if (ItemData.Name == "TrainSpawner") { // if (SpawningTick == 1) SpawningTick = 40; //if (TicksGone < SpawningTick) goto LABEL_235; // SpawnTrain(); //GameObjectManager.AddGameObject(v269); //SpawningTick = TicksGone + 140; } if (PickedUp) { if (PickUpTimer < 1) goto LABEL_235; if (Picker != null) { if (!Picker.IsAlive()) { PickedUp = false; goto LABEL_235; } } PickUpTimer -= 50; int v196 = LogicMath.Min(1000, 1000 - 1000 * PickUpTimer / PickUpTimerDefault); int v200 = PickUpStartZ + (v196 - 1000) * v196 * (-1) + (PickUpZ - PickUpStartZ) * v196 / 1000; SetPosition((Picker.GetX() * v196 + PickUpStartX * (1000 - v196)) / 1000, (Picker.GetY() * v196 + PickUpStartY * (1000 - v196)) / 1000, v200 / 1000); if (PickUpTimer <= 0) { if (Picker.IsAlive()) { Picker.ApplyItem(this); } } goto LABEL_235; } MoveTimer -= 50; if (MoveTimer < 0) MoveTimer = 0; if (TargetX == 0) goto LABEL_263; int v187 = LogicMath.Min(1000, 1000 - 1000 * MoveTimer / MoveTimerDefault); if (ItemData.Name == "Point") { if (v187 > 700) { int v186 = 700; int v189 = 300; int v206 = v187 - v186; int v211 = TargetX - PickUpStartX; int v212 = TargetY - PickUpStartY; int v213 = (TargetX - PickUpStartX) * v186; int v214 = (PickUpStartX * v189 + TargetX * v186); int v215 = (PickUpZ + v206 * (-6) * (v206 - v189)); int v216 = (PickUpStartY * v189 + TargetY * v186); int v217 = ((v214 / 1000) * (v189 - v206) + (v213 / 1000 + PickUpStartX + v211 * v189 / 2000) * v206) / v189; int v218 = ((v216 / 1000) * (v189 - v206) + (v212 * v186 / 1000 + PickUpStartY + v212 * v189 / 2000) * v206) / v189; int v219 = v215 / 1000; SetPosition(v217, v218, LogicMath.Clamp(v219, 0, 3000)); } else { int v186 = 700; int v206 = v187 - 700; int v220 = (PickUpStartY * (1000 - v187) + TargetY * v187); int v221 = (PickUpStartZ + (-6) * v187 * v206 + (PickUpZ - PickUpStartZ) * v187 / v186); int v218 = v220 / 1000; int v217 = (PickUpStartX * (1000 - v187) + TargetX * v187) / 1000; int v219 = v221 / 1000; SetPosition(v217, v218, LogicMath.Clamp(v219, 0, 3000)); } } LABEL_263: ; LABEL_235: ; } private void ExecuteClusterExplosion() { if (_isDestroyed) return; _isDestroyed = true; Character finalOwner = Owner as Character; int currentTicks = GameObjectManager.GetBattle().GetTicksGone(); string mainEffect = ItemData.TriggerAreaEffect; if (string.IsNullOrEmpty(mainEffect)) mainEffect = "ClusterBombExplosion2"; string[] explosionEffects = { mainEffect, "ClusterBombExplosion" }; foreach (string effectName in explosionEffects) { AreaEffectData data = DataTables.GetAreaEffectByName(effectName); if (data == null) continue; AreaEffect areaEffect = new AreaEffect(data); areaEffect.SetPosition(GetX(), GetY(), 0); if (finalOwner != null) { areaEffect.SetSource(finalOwner, 1); areaEffect.SetIndex(finalOwner.GetIndex()); } areaEffect.Damage = Damage; areaEffect.NormalDMG = Damage; areaEffect.DeployedTick = currentTicks; areaEffect.EndingTick = currentTicks + 10; GameObjectManager.AddGameObject(areaEffect); areaEffect.Trigger(); } if (finalOwner != null) { BattlePlayer player = finalOwner.GetPlayer(); if (player?.BoMines != null) { player.BoMines.Remove(this); } } GameObjectManager.RemoveGameObject(this); } public void SetCharacter(Character character) { Owner = character; } public void PickUp(Character character) { PickedUp = true; Picker = character; PickUpTimer = PickUpTimerDefault; PickUpStartX = GetX(); PickUpStartY = GetY(); PickUpZ = 20000; } public void SetAngle(int angle) { ; } public void DisableAppearAnimation() { ; } public override bool ShouldDestruct() { return PickedUp && PickUpTimer <= 0; } public bool CanBePickedUp(Character a1) { if (ItemData.CanBePickedUp && !PickedUp) { switch (ItemData.Name) { case "BattleRoyaleBuff": case "Money": case "Scrap": case "Point": case "EventCollectToken": return true; case "RuffsBuff": if (a1.GetIndex() / 16 == GetIndex() / 16&& !a1.HasBuff(13)) return true; return false; case "SoulCollectorSoul": return a1.GetIndex() / 16 == GetIndex() / 16 && a1.GetHitpointPercentage() < 100; case "WeaponThrowerWeapon": return a1.GetIndex() == GetIndex(); } switch (ItemData.ParentItemForSkin) { case "WeaponThrowerWeapon": return a1.GetIndex() == GetIndex(); } } return false; } public override void Encode(BitStream bitStream, bool isOwnObject, int visionTeam) { base.Encode(bitStream, isOwnObject, visionTeam); var instanceId = ItemData.GetInstanceId(); //Console.WriteLine($"{instanceId}"); switch (instanceId) { case 5://orbspawner bitStream.WritePositiveIntMax16383(SpawningTick); bitStream.WritePositiveIntMax16383(SpawnedTick); break; case 24: bitStream.WritePositiveIntMax16383(170); bitStream.WritePositiveIntMax16383(30); if (instanceId == 24) bitStream.WritePositiveIntMax16383(0); break; case 1: case 2: // case 3: case 4: case 6: case 7: // case 9: case 13: case 17: case 18: case 19: case 20: case 21: case 22: case 23: bitStream.WritePositiveIntMax63(0); bitStream.WritePositiveIntMax63(0); break; case 25: case 26: case 27: if (_state == 0) //летит { bitStream.WritePositiveIntMax63(10); bitStream.WritePositiveIntMax63(10); } else if (_state == 1) //лежит { if (SpawnTick > 75) { bitStream.WritePositiveIntMax63(10); bitStream.WritePositiveIntMax63(10); } else { bitStream.WritePositiveIntMax63(10); bitStream.WritePositiveIntMax63(10); } } break; default: if ((instanceId & 7) == 0) return; // bitStream.WritePositiveIntMax3(0); // bitStream.WritePositiveIntMax63(0); break; } if (ItemData.Name.StartsWith("Piper")) { for (int i = 0; i < 12; i++) bitStream.WriteBoolean(true); } if (ItemData.Name.StartsWith("Sticky")) { bitStream.WritePositiveIntMax127(1); } } public void SetFromToPosition(int X, int Y, int Z, int TX, int TY, int TZ) { SetPosition(X, Y, Z); PickUpStartX = X; PickUpStartY = Y; PickUpStartZ = Z; TargetX = TX; TargetY = TY; PickUpZ = TZ; } public void StartJumpEffect(int fromX, int fromY, int fromZ, int toX, int toY, int toZ) { _startX = fromX; _startY = fromY; _startZ = fromZ; _targetX = toX; _targetY = toY; _targetZ = toZ; _jumpTime = 0; _isJumping = true; SetPosition(fromX, fromY, fromZ); } public override int GetObjectType() { return 3; } } }