public void UseAbility(RealmTime time, int abilitySlot, Position target) { if (Ability[abilitySlot] == null) return; var ability = Ability[abilitySlot]; if (MP < ability.MpCost || AbilityCooldown[abilitySlot] != 0) return; MP -= ability.MpCost; AbilityCooldown[abilitySlot] = ability.Cooldown; foreach (ActivateEffect eff in ability.ActivateEffects) { switch (eff.Effect) { case ActivateEffects.BulletNova: { ProjectileDesc prjDesc = ability.Projectiles[0]; //Assume only one var batch = new Packet[21]; uint s = Random.CurrentSeed; Random.CurrentSeed = (uint)(s * time.tickTimes); for (int i = 0; i < 20; i++) { Projectile proj = CreateProjectile(prjDesc, ability.AbilityType, (int)statsMgr.GetAttackDamage(prjDesc.MinDamage, prjDesc.MaxDamage), time.tickTimes, target, (float)(i * (Math.PI * 2) / 20)); Owner.EnterWorld(proj); fames.Shoot(proj); batch[i] = new ShootPacket { BulletId = proj.ProjectileId, OwnerId = Id, ContainerType = ability.AbilityType, Position = target, Angle = proj.Angle, Damage = (short)proj.Damage, FromAbility = true }; } Random.CurrentSeed = s; batch[20] = new ShowEffectPacket { EffectType = EffectType.Trail, PosA = target, TargetId = Id, Color = new ARGB(0xFFFF00AA) }; BroadcastSync(batch, p => this.Dist(p) < 25); } break; case ActivateEffects.Shoot: { ActivateAbilityShoot(time, ability, target); } break; } } UpdateCount++; }
public bool Activate(RealmTime time, Item item, UseItemPacket pkt) { bool endMethod = false; Position target = pkt.ItemUsePos; Mp -= item.MpCost; IContainer con = Owner.GetEntity(pkt.SlotObject.ObjectId) as IContainer; if (con == null) return true; if (pkt.SlotObject.SlotId != 255 && pkt.SlotObject.SlotId != 254 && con.Inventory[pkt.SlotObject.SlotId] != item) { Entity.logger.FatalFormat("Cheat engine detected for player {0},\nItem should be {1}, but its {2}.", Name, Inventory[pkt.SlotObject.SlotId].ObjectId, item.ObjectId); foreach (Player player in Owner.Players.Values) if (player.Client.Account.Rank >= 2) player.SendInfo(String.Format("Cheat engine detected for player {0},\nItem should be {1}, but its {2}.", Name, Inventory[pkt.SlotObject.SlotId].ObjectId, item.ObjectId)); Client.Disconnect(); return true; } if (item.IsBackpack) { if (HasBackpack) return true; Client.Character.Backpack = new[] { -1, -1, -1, -1, -1, -1, -1, -1 }; HasBackpack = true; Client.Character.HasBackpack = 1; Manager.Database.DoActionAsync(db => db.SaveBackpacks(Client.Character, Client.Account)); Array.Resize(ref inventory, 20); int[] slotTypes = Utils.FromCommaSepString32( Manager.GameData.ObjectTypeToElement[ObjectType].Element("SlotTypes").Value); Array.Resize(ref slotTypes, 20); for (int i = 0; i < slotTypes.Length; i++) if (slotTypes[i] == 0) slotTypes[i] = 10; SlotTypes = slotTypes; return false; } if (item.XpBooster) { if (!XpBoosted) { XpBoostTimeLeft = (float)item.Timer; XpBoosted = item.XpBooster; xpFreeTimer = (float)item.Timer == -1.0 ? false : true; return false; } else { SendInfo("You have already an active XP Booster."); return true; } } if (item.LootDropBooster) { if (!LootDropBoost) { LootDropBoostTimeLeft = (float)item.Timer; lootDropBoostFreeTimer = (float)item.Timer == -1.0 ? false : true; return false; } else { SendInfo("You have already an active Loot Drop Booster."); return true; } } if (item.LootTierBooster) { if (!LootTierBoost) { LootTierBoostTimeLeft = (float)item.Timer; lootTierBoostFreeTimer = (float)item.Timer == -1.0 ? false : true; return false; } else { SendInfo("You have already an active Loot Tier Booster."); return true; } } foreach (ActivateEffect eff in item.ActivateEffects) { switch (eff.Effect) { case ActivateEffects.BulletNova: { ProjectileDesc prjDesc = item.Projectiles[0]; //Assume only one Packet[] batch = new Packet[21]; uint s = Random.CurrentSeed; Random.CurrentSeed = (uint)(s * time.tickTimes); for (int i = 0; i < 20; i++) { Projectile proj = CreateProjectile(prjDesc, item.ObjectType, (int)StatsManager.GetAttackDamage(prjDesc.MinDamage, prjDesc.MaxDamage), time.tickTimes, target, (float)(i * (Math.PI * 2) / 20)); Owner.EnterWorld(proj); FameCounter.Shoot(proj); batch[i] = new Shoot2Packet() { BulletId = proj.ProjectileId, OwnerId = Id, ContainerType = item.ObjectType, StartingPos = target, Angle = proj.Angle, Damage = (short)proj.Damage }; } Random.CurrentSeed = s; batch[20] = new ShowEffectPacket() { EffectType = EffectType.Trail, PosA = target, TargetId = Id, Color = new ARGB(0xFFFF00AA) }; BroadcastSync(batch, p => this.Dist(p) < 35); } break; case ActivateEffects.Shoot: { ActivateShoot(time, item, target); } break; case ActivateEffects.StatBoostSelf: { int idx = -1; if (eff.Stats == StatsType.MaximumHP) idx = 0; else if (eff.Stats == StatsType.MaximumMP) idx = 1; else if (eff.Stats == StatsType.Attack) idx = 2; else if (eff.Stats == StatsType.Defense) idx = 3; else if (eff.Stats == StatsType.Speed) idx = 4; else if (eff.Stats == StatsType.Vitality) idx = 5; else if (eff.Stats == StatsType.Wisdom) idx = 6; else if (eff.Stats == StatsType.Dexterity) idx = 7; List<Packet> pkts = new List<Packet>(); ActivateBoostStat(this, idx, pkts); int OGstat = oldstat; int bit = idx + 39; int s = eff.Amount; Boost[idx] += s; ApplyConditionEffect(new ConditionEffect { DurationMS = eff.DurationMS, Effect = (ConditionEffectIndex)bit }); UpdateCount++; Owner.Timers.Add(new WorldTimer(eff.DurationMS, (world, t) => { Boost[idx] = OGstat; UpdateCount++; })); Owner.BroadcastPacket(new ShowEffectPacket { EffectType = EffectType.Potion, TargetId = Id, Color = new ARGB(0xffffffff) }, null); } break; case ActivateEffects.StatBoostAura: { int idx = -1; if (eff.Stats == StatsType.MaximumHP) idx = 0; if (eff.Stats == StatsType.MaximumMP) idx = 1; if (eff.Stats == StatsType.Attack) idx = 2; if (eff.Stats == StatsType.Defense) idx = 3; if (eff.Stats == StatsType.Speed) idx = 4; if (eff.Stats == StatsType.Vitality) idx = 5; if (eff.Stats == StatsType.Wisdom) idx = 6; if (eff.Stats == StatsType.Dexterity) idx = 7; int bit = idx + 39; var amountSBA = eff.Amount; var durationSBA = eff.DurationMS; var rangeSBA = eff.Range; if (eff.UseWisMod) { amountSBA = (int)UseWisMod(eff.Amount, 0); durationSBA = (int)(UseWisMod(eff.DurationSec) * 1000); rangeSBA = UseWisMod(eff.Range); } this.Aoe(rangeSBA, true, player => { // TODO support for noStack StatBoostAura attribute (paladin total // hp increase / insta heal) ApplyConditionEffect(new ConditionEffect { DurationMS = durationSBA, Effect = (ConditionEffectIndex)bit }); (player as Player).Boost[idx] += amountSBA; player.UpdateCount++; Owner.Timers.Add(new WorldTimer(durationSBA, (world, t) => { (player as Player).Boost[idx] -= amountSBA; player.UpdateCount++; })); }); BroadcastSync(new ShowEffectPacket() { EffectType = EffectType.AreaBlast, TargetId = Id, Color = new ARGB(0xffffffff), PosA = new Position() { X = rangeSBA } }, p => this.Dist(p) < 25); } break; case ActivateEffects.ConditionEffectSelf: { var durationCES = eff.DurationMS; if (eff.UseWisMod) durationCES = (int)(UseWisMod(eff.DurationSec) * 1000); var color = 0xffffffff; switch (eff.ConditionEffect.Value) { case ConditionEffectIndex.Damaging: color = 0xffff0000; break; case ConditionEffectIndex.Berserk: color = 0x808080; break; } ApplyConditionEffect(new ConditionEffect { Effect = eff.ConditionEffect.Value, DurationMS = durationCES }); Owner.BroadcastPacket(new ShowEffectPacket { EffectType = EffectType.AreaBlast, TargetId = Id, Color = new ARGB(color), PosA = new Position { X = 2 } }, null); } break; case ActivateEffects.ConditionEffectAura: { var durationCEA = eff.DurationMS; var rangeCEA = eff.Range; if (eff.UseWisMod) { durationCEA = (int)(UseWisMod(eff.DurationSec) * 1000); rangeCEA = UseWisMod(eff.Range); } this.Aoe(rangeCEA, true, player => { player.ApplyConditionEffect(new ConditionEffect { Effect = eff.ConditionEffect.Value, DurationMS = durationCEA }); }); var color = 0xffffffff; switch (eff.ConditionEffect.Value) { case ConditionEffectIndex.Damaging: color = 0xffff0000; break; case ConditionEffectIndex.Berserk: color = 0x808080; break; } BroadcastSync(new ShowEffectPacket { EffectType = EffectType.AreaBlast, TargetId = Id, Color = new ARGB(color), PosA = new Position { X = rangeCEA } }, p => this.Dist(p) < 25); } break; case ActivateEffects.Heal: { List<Packet> pkts = new List<Packet>(); ActivateHealHp(this, eff.Amount, pkts); Owner.BroadcastPackets(pkts, null); } break; case ActivateEffects.HealNova: { var amountHN = eff.Amount; var rangeHN = eff.Range; if (eff.UseWisMod) { amountHN = (int)UseWisMod(eff.Amount, 0); rangeHN = UseWisMod(eff.Range); } List<Packet> pkts = new List<Packet>(); this.Aoe(rangeHN, true, player => { ActivateHealHp(player as Player, amountHN, pkts); }); pkts.Add(new ShowEffectPacket { EffectType = EffectType.AreaBlast, TargetId = Id, Color = new ARGB(0xffffffff), PosA = new Position { X = rangeHN } }); BroadcastSync(pkts, p => this.Dist(p) < 25); } break; case ActivateEffects.Magic: { List<Packet> pkts = new List<Packet>(); ActivateHealMp(this, eff.Amount, pkts); Owner.BroadcastPackets(pkts, null); } break; case ActivateEffects.MagicNova: { List<Packet> pkts = new List<Packet>(); this.Aoe(eff.Range / 2, true, player => { ActivateHealMp(player as Player, eff.Amount, pkts); }); pkts.Add(new ShowEffectPacket { EffectType = EffectType.AreaBlast, TargetId = Id, Color = new ARGB(0xffffffff), PosA = new Position { X = eff.Range } }); Owner.BroadcastPackets(pkts, null); } break; case ActivateEffects.Teleport: { Move(target.X, target.Y); UpdateCount++; Owner.BroadcastPackets(new Packet[] { new GotoPacket { ObjectId = Id, Position = new Position { X = X, Y = Y } }, new ShowEffectPacket { EffectType = EffectType.Teleport, TargetId = Id, PosA = new Position { X = X, Y = Y }, Color = new ARGB(0xFFFFFFFF) } }, null); } break; case ActivateEffects.VampireBlast: { List<Packet> pkts = new List<Packet>(); pkts.Add(new ShowEffectPacket { EffectType = EffectType.Trail, TargetId = Id, PosA = target, Color = new ARGB(0xFFFF0000) }); pkts.Add(new ShowEffectPacket { EffectType = EffectType.Diffuse, Color = new ARGB(0xFFFF0000), TargetId = Id, PosA = target, PosB = new Position { X = target.X + eff.Radius, Y = target.Y } }); int totalDmg = 0; List<Enemy> enemies = new List<Enemy>(); Owner.Aoe(target, eff.Radius, false, enemy => { enemies.Add(enemy as Enemy); totalDmg += (enemy as Enemy).Damage(this, time, eff.TotalDamage, false); }); List<Player> players = new List<Player>(); this.Aoe(eff.Radius, true, player => { players.Add(player as Player); ActivateHealHp(player as Player, totalDmg, pkts); }); if (enemies.Count > 0) { Random rand = new Random(); for (int i = 0; i < 5; i++) { Enemy a = enemies[rand.Next(0, enemies.Count)]; Player b = players[rand.Next(0, players.Count)]; pkts.Add(new ShowEffectPacket { EffectType = EffectType.Flow, TargetId = b.Id, PosA = new Position { X = a.X, Y = a.Y }, Color = new ARGB(0xffffffff) }); } } BroadcastSync(pkts, p => this.Dist(p) < 25); } break; case ActivateEffects.Trap: { BroadcastSync(new ShowEffectPacket { EffectType = EffectType.Throw, Color = new ARGB(0xff9000ff), TargetId = Id, PosA = target }, p => this.Dist(p) < 25); Owner.Timers.Add(new WorldTimer(1500, (world, t) => { Trap trap = new Trap( this, eff.Radius, eff.TotalDamage, eff.ConditionEffect ?? ConditionEffectIndex.Slowed, eff.EffectDuration); trap.Move(target.X, target.Y); world.EnterWorld(trap); })); } break; case ActivateEffects.StasisBlast: { List<Packet> pkts = new List<Packet>(); pkts.Add(new ShowEffectPacket { EffectType = EffectType.Concentrate, TargetId = Id, PosA = target, PosB = new Position { X = target.X + 3, Y = target.Y }, Color = new ARGB(0xFF00D0) }); Owner.Aoe(target, 3, false, enemy => { if (IsSpecial(enemy.ObjectType)) return; if (enemy.HasConditionEffect(ConditionEffectIndex.StasisImmune)) { if (!enemy.HasConditionEffect(ConditionEffectIndex.Invincible)) { pkts.Add(new NotificationPacket { ObjectId = enemy.Id, Color = new ARGB(0xff00ff00), Text = "{\"key\":\"blank\",\"tokens\":{\"data\":\"Immune\"}}" }); } } else if (!enemy.HasConditionEffect(ConditionEffectIndex.Stasis)) { enemy.ApplyConditionEffect(new ConditionEffect { Effect = ConditionEffectIndex.Stasis, DurationMS = eff.DurationMS }); Owner.Timers.Add(new WorldTimer(eff.DurationMS, (world, t) => { enemy.ApplyConditionEffect(new ConditionEffect { Effect = ConditionEffectIndex.StasisImmune, DurationMS = 3000 }); })); pkts.Add(new NotificationPacket { ObjectId = enemy.Id, Color = new ARGB(0xffff0000), Text = "{\"key\":\"blank\",\"tokens\":{\"data\":\"Stasis\"}}" }); } }); BroadcastSync(pkts, p => this.Dist(p) < 25); } break; case ActivateEffects.Decoy: { Decoy decoy = new Decoy(Manager, this, eff.DurationMS, StatsManager.GetSpeed()); decoy.Move(X, Y); Owner.EnterWorld(decoy); } break; case ActivateEffects.Lightning: { Enemy start = null; double angle = Math.Atan2(target.Y - Y, target.X - X); double diff = Math.PI / 3; Owner.Aoe(target, 6, false, enemy => { if (!(enemy is Enemy)) return; double x = Math.Atan2(enemy.Y - Y, enemy.X - X); if (Math.Abs(angle - x) < diff) { start = enemy as Enemy; diff = Math.Abs(angle - x); } }); if (start == null) break; Enemy current = start; Enemy[] targets = new Enemy[eff.MaxTargets]; for (int i = 0; i < targets.Length; i++) { targets[i] = current; Enemy next = current.GetNearestEntity(8, false, enemy => enemy is Enemy && Array.IndexOf(targets, enemy) == -1 && this.Dist(enemy) <= 6) as Enemy; if (next == null) break; current = next; } List<Packet> pkts = new List<Packet>(); for (int i = 0; i < targets.Length; i++) { if (targets[i] == null) break; if (targets[i].HasConditionEffect(ConditionEffectIndex.Invincible)) continue; Entity prev = i == 0 ? (Entity)this : targets[i - 1]; targets[i].Damage(this, time, eff.TotalDamage, false); if (eff.ConditionEffect != null) targets[i].ApplyConditionEffect(new ConditionEffect { Effect = eff.ConditionEffect.Value, DurationMS = (int)(eff.EffectDuration * 1000) }); pkts.Add(new ShowEffectPacket { EffectType = EffectType.Lightning, TargetId = prev.Id, Color = new ARGB(0xffff0088), PosA = new Position { X = targets[i].X, Y = targets[i].Y }, PosB = new Position { X = 350 } }); } BroadcastSync(pkts, p => this.Dist(p) < 25); } break; case ActivateEffects.PoisonGrenade: { try { BroadcastSync(new ShowEffectPacket { EffectType = EffectType.Throw, Color = new ARGB(0xffddff00), TargetId = Id, PosA = target }, p => this.Dist(p) < 25); Placeholder x = new Placeholder(Manager, 1500); x.Move(target.X, target.Y); Owner.EnterWorld(x); try { Owner.Timers.Add(new WorldTimer(1500, (world, t) => { world.BroadcastPacket(new ShowEffectPacket { EffectType = EffectType.AreaBlast, Color = new ARGB(0xffddff00), TargetId = x.Id, PosA = new Position { X = eff.Radius } }, null); world.Aoe(target, eff.Radius, false, enemy => PoisonEnemy(enemy as Enemy, eff)); })); } catch (Exception ex) { Entity.logger.ErrorFormat("Poison ShowEffect:\n{0}", ex); } } catch (Exception ex) { Entity.logger.ErrorFormat("Poisons General:\n{0}", ex); } } break; case ActivateEffects.RemoveNegativeConditions: { this.Aoe(eff.Range / 2, true, player => { ApplyConditionEffect(NegativeEffs); }); BroadcastSync(new ShowEffectPacket { EffectType = EffectType.AreaBlast, TargetId = Id, Color = new ARGB(0xffffffff), PosA = new Position { X = eff.Range / 2 } }, p => this.Dist(p) < 25); } break; case ActivateEffects.RemoveNegativeConditionsSelf: { ApplyConditionEffect(NegativeEffs); Owner.BroadcastPacket(new ShowEffectPacket { EffectType = EffectType.AreaBlast, TargetId = Id, Color = new ARGB(0xffffffff), PosA = new Position { X = 1 } }, null); } break; case ActivateEffects.IncrementStat: { int idx = -1; if (eff.Stats == StatsType.MaximumHP) idx = 0; else if (eff.Stats == StatsType.MaximumMP) idx = 1; else if (eff.Stats == StatsType.Attack) idx = 2; else if (eff.Stats == StatsType.Defense) idx = 3; else if (eff.Stats == StatsType.Speed) idx = 4; else if (eff.Stats == StatsType.Vitality) idx = 5; else if (eff.Stats == StatsType.Wisdom) idx = 6; else if (eff.Stats == StatsType.Dexterity) idx = 7; Stats[idx] += eff.Amount; int limit = int.Parse( Manager.GameData.ObjectTypeToElement[ObjectType].Element( StatsManager.StatsIndexToName(idx)) .Attribute("max") .Value); if (Stats[idx] > limit) Stats[idx] = limit; UpdateCount++; } break; case ActivateEffects.UnlockPortal: Portal portal = this.GetNearestEntity(5, Manager.GameData.IdToObjectType[eff.LockedName]) as Portal; Packet[] packets = new Packet[3]; packets[0] = new ShowEffectPacket { EffectType = EffectType.AreaBlast, Color = new ARGB(0xFFFFFF), PosA = new Position { X = 5 }, TargetId = Id }; if (portal == null) break; portal.Unlock(eff.DungeonName); packets[1] = new NotificationPacket { Color = new ARGB(0x00FF00), Text = "{\"key\":\"blank\",\"tokens\":{\"data\":\"Unlocked by " + Name + "\"}}", ObjectId = Id }; packets[2] = new TextPacket { BubbleTime = 0, Stars = -1, Name = "", Text = eff.DungeonName + " Unlocked by " + Name + "." }; BroadcastSync(packets); break; case ActivateEffects.Create: //this is a portal { ushort objType; if (!Manager.GameData.IdToObjectType.TryGetValue(eff.Id, out objType) || !Manager.GameData.Portals.ContainsKey(objType)) break; // object not found, ignore Entity entity = Resolve(Manager, objType); World w = Manager.GetWorld(Owner.Id); //can't use Owner here, as it goes out of scope int TimeoutTime = Manager.GameData.Portals[objType].TimeoutTime; string DungName = Manager.GameData.Portals[objType].DungeonName; ARGB c = new ARGB(0x00FF00); entity.Move(X, Y); w.EnterWorld(entity); w.BroadcastPacket(new NotificationPacket { Color = c, Text = "{\"key\":\"blank\",\"tokens\":{\"data\":\"" + DungName + " opened by " + Client.Account.Name + "\"}}", ObjectId = Client.Player.Id }, null); w.BroadcastPacket(new TextPacket { BubbleTime = 0, Stars = -1, Name = "", Text = DungName + " opened by " + Client.Account.Name }, null); w.Timers.Add(new WorldTimer(TimeoutTime * 1000, (world, t) => //default portal close time * 1000 { try { w.LeaveWorld(entity); } catch (Exception ex) //couldn't remove portal, Owner became null. Should be fixed with RealmManager implementation { logger.ErrorFormat("Couldn't despawn portal.\n{0}", ex); } })); } break; case ActivateEffects.Dye: { if (item.Texture1 != 0) { Texture1 = item.Texture1; } if (item.Texture2 != 0) { Texture2 = item.Texture2; } SaveToCharacter(); } break; case ActivateEffects.ShurikenAbility: { if (!ninjaShoot) { ApplyConditionEffect(new ConditionEffect { Effect = ConditionEffectIndex.Speedy, DurationMS = -1 }); ninjaFreeTimer = true; ninjaShoot = true; } else { ApplyConditionEffect(new ConditionEffect { Effect = ConditionEffectIndex.Speedy, DurationMS = 0 }); ushort obj; Manager.GameData.IdToObjectType.TryGetValue(item.ObjectId, out obj); if (Mp >= item.MpEndCost) { ActivateShoot(time, item, pkt.ItemUsePos); Mp -= (int)item.MpEndCost; } targetlink = target; ninjaShoot = false; } } break; case ActivateEffects.UnlockSkin: if (!Client.Account.OwnedSkins.Contains(item.ActivateEffects[0].SkinType)) { Manager.Database.DoActionAsync(db => { Client.Account.OwnedSkins.Add(item.ActivateEffects[0].SkinType); MySqlCommand cmd = db.CreateQuery(); cmd.CommandText = "UPDATE accounts SET ownedSkins=@ownedSkins WHERE id=@id"; cmd.Parameters.AddWithValue("@ownedSkins", Utils.GetCommaSepString(Client.Account.OwnedSkins.ToArray())); cmd.Parameters.AddWithValue("@id", AccountId); cmd.ExecuteNonQuery(); SendInfo( "New skin unlocked successfully. Change skins in your Vault, or start a new character to use."); Client.SendPacket(new UnlockedSkinPacket { SkinID = item.ActivateEffects[0].SkinType }); }); endMethod = false; break; } SendInfo("Error.alreadyOwnsSkin"); endMethod = true; break; case ActivateEffects.PermaPet: //Doesnt exist anymore { //psr.Character.Pet = XmlDatas.IdToType[eff.ObjectId]; //GivePet(XmlDatas.IdToType[eff.ObjectId]); //UpdateCount++; } break; case ActivateEffects.Pet: Entity en = Entity.Resolve(Manager, eff.ObjectId); en.Move(X, Y); en.SetPlayerOwner(this); Owner.EnterWorld(en); Owner.Timers.Add(new WorldTimer(30 * 1000, (w, t) => { w.LeaveWorld(en); })); break; case ActivateEffects.CreatePet: if (!Owner.Name.StartsWith("Pet Yard")) { SendInfo("server.use_in_petyard"); return true; } Pet.Create(Manager, this, item); break; case ActivateEffects.MysteryPortal: string[] dungeons = new[] { "Pirate Cave Portal", "Forest Maze Portal", "Spider Den Portal", "Snake Pit Portal", "Glowing Portal", "Forbidden Jungle Portal", "Candyland Portal", "Haunted Cemetery Portal", "Undead Lair Portal", "Davy Jones' Locker Portal", "Manor of the Immortals Portal", "Abyss of Demons Portal", "Lair of Draconis Portal", "Mad Lab Portal", "Ocean Trench Portal", "Tomb of the Ancients Portal", "Beachzone Portal", "The Shatters", "Deadwater Docks", "Woodland Labyrinth", "The Crawling Depths", "Treasure Cave Portal", "Battle Nexus Portal", "Belladonna's Garden Portal", "Lair of Shaitan Portal" }; var descs = Manager.GameData.Portals.Where(_ => dungeons.Contains<string>(_.Value.ObjectId)).Select(_ => _.Value).ToArray(); var portalDesc = descs[Random.Next(0, descs.Count())]; Entity por = Entity.Resolve(Manager, portalDesc.ObjectId); por.Move(this.X, this.Y); Owner.EnterWorld(por); Client.SendPacket(new NotificationPacket { Color = new ARGB(0x00FF00), Text = "{\"key\":\"blank\",\"tokens\":{\"data\":\"" + portalDesc.DungeonName + " opened by " + Client.Account.Name + "\"}}", ObjectId = Client.Player.Id }); Owner.BroadcastPacket(new TextPacket { BubbleTime = 0, Stars = -1, Name = "", Text = portalDesc.ObjectId + " opened by " + Name }, null); Owner.Timers.Add(new WorldTimer(portalDesc.TimeoutTime * 1000, (w, t) => //default portal close time * 1000 { try { w.LeaveWorld(por); } catch (Exception ex) { Entity.logger.ErrorFormat("Couldn't despawn portal.\n{0}", ex); } })); break; case ActivateEffects.GenericActivate: var targetPlayer = eff.Target.Equals("player"); var centerPlayer = eff.Center.Equals("player"); var duration = (eff.UseWisMod) ? (int)(UseWisMod(eff.DurationSec) * 1000) : eff.DurationMS; var range = (eff.UseWisMod) ? UseWisMod(eff.Range) : eff.Range; Owner.Aoe((eff.Center.Equals("mouse")) ? target : new Position { X = X, Y = Y }, range, targetPlayer, entity => { if (IsSpecial(entity.ObjectType)) return; if (!entity.HasConditionEffect(ConditionEffectIndex.Stasis) && !entity.HasConditionEffect(ConditionEffectIndex.Invincible)) { entity.ApplyConditionEffect( new ConditionEffect() { Effect = eff.ConditionEffect.Value, DurationMS = duration }); } }); // replaced this last bit with what I had, never noticed any issue with it. // Perhaps I'm wrong? BroadcastSync(new ShowEffectPacket() { EffectType = (EffectType)eff.VisualEffect, TargetId = Id, Color = new ARGB(eff.Color ?? 0xffffffff), PosA = centerPlayer ? new Position { X = range } : target, PosB = new Position(target.X - range, target.Y) }, p => this.DistSqr(p) < 25); /*if (eff.VisualEffect > 0) { Placeholder x = null; if (eff.Center == "mouse") { x = new Placeholder(Manager, 1500); x.Move(pkt.ItemUsePos.X, pkt.ItemUsePos.Y); Owner.EnterWorld(x); } BroadcastSync(new ShowEffectPacket { EffectType = EffectType.AreaBlast, TargetId = x?.Id ?? Id, Color = new ARGB(eff.Color ?? 0xffffffff), PosA = new Position {X = eff.VisualEffect/2}, }, p => this.Dist(p) < 25); }*/ break; } } UpdateCount++; return endMethod; }
private bool Activate(RealmTime time, Item item, ItemData data, int itemSlot, Position target) { if (MP < item.MpCost) return false; MP -= item.MpCost; bool success = true; foreach (ActivateEffect eff in item.ActivateEffects) { switch (eff.Effect) { case ActivateEffects.BulletNova: { ProjectileDesc prjDesc = item.Projectiles[0]; //Assume only one var batch = new Packet[21]; uint s = Random.CurrentSeed; Random.CurrentSeed = (uint) (s*time.tickTimes); for (int i = 0; i < 20; i++) { Projectile proj = CreateProjectile(prjDesc, item.ObjectType, (int) statsMgr.GetAttackDamage(prjDesc.MinDamage, prjDesc.MaxDamage), time.tickTimes, target, (float) (i*(Math.PI*2)/20)); Owner.EnterWorld(proj); fames.Shoot(proj); batch[i] = new ShootPacket { BulletId = proj.ProjectileId, OwnerId = Id, ContainerType = item.ObjectType, Position = target, Angle = proj.Angle, Damage = (short) proj.Damage, FromAbility = false }; } Random.CurrentSeed = s; batch[20] = new ShowEffectPacket { EffectType = EffectType.Trail, PosA = target, TargetId = Id, Color = new ARGB(0xFFFF00AA) }; BroadcastSync(batch, p => this.Dist(p) < 25); } break; case ActivateEffects.Shoot: { ActivateShoot(time, item, target); } break; case ActivateEffects.StatBoostSelf: { var idx = -1; switch ((StatsType) eff.Stats) { case StatsType.MaximumHP: idx = 0; break; case StatsType.MaximumMP: idx = 1; break; case StatsType.Attack: idx = 2; break; case StatsType.Defense: idx = 3; break; case StatsType.Speed: idx = 4; break; case StatsType.Vitality: idx = 5; break; case StatsType.Wisdom: idx = 6; break; case StatsType.Dexterity: idx = 7; break; } var s = eff.Amount; ActivateBoost[idx].Push(s); CalculateBoost(); (this as Player).UpdateCount++; Owner.Timers.Add(new WorldTimer(eff.DurationMS, (world, t) => { ActivateBoost[idx].Pop(s); CalculateBoost(); (this as Player).UpdateCount++; })); BroadcastSync(new ShowEffectPacket { EffectType = EffectType.Potion, TargetId = Id, Color = new ARGB(0xffffffff) }, p => this.Dist(p) < 25); } break; case ActivateEffects.StatBoostAura: { int idx = -1; switch ((StatsType) eff.Stats) { case StatsType.MaximumHP: idx = 0; break; case StatsType.MaximumMP: idx = 1; break; case StatsType.Attack: idx = 2; break; case StatsType.Defense: idx = 3; break; case StatsType.Speed: idx = 4; break; case StatsType.Vitality: idx = 5; break; case StatsType.Wisdom: idx = 6; break; case StatsType.Dexterity: idx = 7; break; } int s = eff.Amount; this.AOE(eff.Range, true, player => { var plr = (player as Player); if (PvP && (plr.Team == 0 || plr.Team != Team) && plr != this) return; ActivateBoost[idx].Push(s); CalculateBoost(); player.UpdateCount++; Owner.Timers.Add(new WorldTimer(eff.DurationMS, (world, t) => { ActivateBoost[idx].Pop(s); CalculateBoost(); player.UpdateCount++; })); }); BroadcastSync(new ShowEffectPacket { EffectType = EffectType.AreaBlast, TargetId = Id, Color = new ARGB(0xffffffff), PosA = new Position {X = eff.Range} }, p => this.Dist(p) < 25); } break; case ActivateEffects.ConditionEffectSelf: { ApplyConditionEffect(new ConditionEffect { Effect = eff.ConditionEffect.Value, DurationMS = eff.DurationMS }); BroadcastSync(new ShowEffectPacket { EffectType = EffectType.AreaBlast, TargetId = Id, Color = new ARGB(0xffffffff), PosA = new Position {X = 1} }, p => this.Dist(p) < 25); } break; case ActivateEffects.ConditionEffectAura: { this.AOE(eff.Range, true, player => { var plr = (player as Player); if (PvP && (plr.Team == 0 || plr.Team != Team) && plr != this) return; player.ApplyConditionEffect(new ConditionEffect { Effect = eff.ConditionEffect.Value, DurationMS = eff.DurationMS }); }); uint color = 0xffffffff; if (eff.ConditionEffect.Value == ConditionEffectIndex.Damaging) color = 0xffff0000; BroadcastSync(new ShowEffectPacket { EffectType = EffectType.AreaBlast, TargetId = Id, Color = new ARGB(color), PosA = new Position {X = eff.Range} }, p => this.Dist(p) < 25); } break; case ActivateEffects.Heal: { var pkts = new List<Packet>(); ActivateHealHp(this, this, eff.Amount, pkts); BroadcastSync(pkts, p => this.Dist(p) < 25); } break; case ActivateEffects.HealNova: { var pkts = new List<Packet>(); this.AOE(eff.Range, true, player => { ActivateHealHp(player as Player, this, eff.Amount, pkts); }); pkts.Add(new ShowEffectPacket { EffectType = EffectType.AreaBlast, TargetId = Id, Color = new ARGB(0xffffffff), PosA = new Position {X = eff.Range} }); BroadcastSync(pkts, p => this.Dist(p) < 25); } break; case ActivateEffects.Magic: { var pkts = new List<Packet>(); ActivateHealMp(this, this, eff.Amount, pkts); BroadcastSync(pkts, p => this.Dist(p) < 25); } break; case ActivateEffects.MagicNova: { var pkts = new List<Packet>(); this.AOE(eff.Range, true, player => { ActivateHealMp(player as Player, this, eff.Amount, pkts); }); pkts.Add(new ShowEffectPacket { EffectType = EffectType.AreaBlast, TargetId = Id, Color = new ARGB(0xffffffff), PosA = new Position {X = eff.Range} }); BroadcastSync(pkts, p => this.Dist(p) < 25); } break; case ActivateEffects.Teleport: { if (!Owner.AllowAbilityTeleport) { SendError("Teleporting is disabled."); break; } Move(target.X, target.Y); UpdateCount++; Owner.BroadcastPacket(new GotoPacket { ObjectId = Id, Position = new Position { X = X, Y = Y } }, null); foreach (Player i in Owner.Players.Values) if (this.Dist(i) < 25) if ((PvP && i.Team != 0 && i.Team == Team) || !PvP) i.Client.SendPackets(new Packet[] { new ShowEffectPacket { EffectType = EffectType.Teleport, TargetId = Id, PosA = new Position { X = X, Y = Y }, Color = new ARGB(0xFFFFFFFF) } }); } break; case ActivateEffects.VampireBlast: { var pkts = new List<Packet>(); pkts.Add(new ShowEffectPacket { EffectType = EffectType.Trail, TargetId = Id, PosA = target, Color = new ARGB(0xFFFF0000) }); pkts.Add(new ShowEffectPacket { EffectType = EffectType.Diffuse, TargetId = Id, PosA = target, PosB = new Position {X = target.X + eff.Radius, Y = target.Y}, Color = new ARGB(0xFFFF0000) }); BroadcastSync(pkts, p => this.Dist(p) < 25); pkts = new List<Packet>(); int totalDmg = 0; var enemies = new List<Entity>(); var targets = new List<Player>(); Owner.AOE(target, eff.Radius, false, enemy => { enemies.Add(enemy); totalDmg += (enemy as Enemy).Damage(this, time, eff.TotalDamage, false, false, null); pkts.Add(new DamagePacket { BulletId = 0, ObjectId = Id, TargetId = enemy.Id, Effects = 0, Damage = (ushort) eff.TotalDamage, Killed = (enemy as Enemy).HP <= 0 }); }); if (PvP) { Owner.AOE(target, eff.Radius, true, enemy => { var plr = (enemy as Player); if (!plr.PvP || (plr.PvP && plr.Team != 0 && plr.Team == Team) || plr == this) return; enemies.Add(enemy); (enemy as Player).Damage(eff.TotalDamage, enemy as Character, false, true, 0.20f); totalDmg += (int) Math.Max(1, (enemy as Player).statsMgr.GetDefenseDamage(eff.TotalDamage, false) * 0.20); }); } var players = new List<Player>(); this.AOE(eff.Radius, true, player => { var plr = (player as Player); if (PvP && (plr.Team == 0 || plr.Team != Team) && plr != this) return; players.Add(player as Player); ActivateHealHp(player as Player, this, totalDmg, pkts); }); var rand = new Random(); for (int i = 0; i < 5; i++) { Entity a = enemies[rand.Next(0, enemies.Count)]; Player b = players[rand.Next(0, players.Count)]; pkts.Add(new ShowEffectPacket { EffectType = EffectType.Flow, TargetId = b.Id, PosA = new Position {X = a.X, Y = a.Y}, Color = new ARGB(0xffffffff) }); } BroadcastSync(pkts, p => this.Dist(p) < 25); } break; case ActivateEffects.Trap: { BroadcastSync(new ShowEffectPacket { EffectType = EffectType.Throw, Color = new ARGB(0xff9000ff), TargetId = Id, PosA = target }, p => this.Dist(p) < 25); Owner.Timers.Add(new WorldTimer(1500, (world, t) => { var trap = new Trap( this, eff.Radius, eff.TotalDamage, eff.ConditionEffect ?? ConditionEffectIndex.Slowed, eff.EffectDuration); trap.Move(target.X, target.Y); world.EnterWorld(trap); })); } break; case ActivateEffects.StasisBlast: { var pkts = new List<Packet>(); pkts.Add(new ShowEffectPacket { EffectType = EffectType.Concentrate, TargetId = Id, PosA = target, PosB = new Position {X = target.X + 3, Y = target.Y}, Color = new ARGB(0xffffffff) }); Owner.AOE(target, 3, false, enemy => { if (enemy.HasConditionEffect(ConditionEffects.StasisImmune)) { pkts.Add(new NotificationPacket { ObjectId = enemy.Id, Color = new ARGB(0xff00ff00), Text = "Immune" }); } else if (!enemy.HasConditionEffect(ConditionEffects.Stasis)) { enemy.ApplyConditionEffect( new ConditionEffect { Effect = ConditionEffectIndex.Stasis, DurationMS = eff.DurationMS }, new ConditionEffect { Effect = ConditionEffectIndex.Paused, DurationMS = eff.DurationMS }, new ConditionEffect { Effect = ConditionEffectIndex.Confused, DurationMS = eff.DurationMS } ); } Owner.Timers.Add(new WorldTimer(eff.DurationMS, (world, t) => enemy.ApplyConditionEffect(new ConditionEffect { Effect = ConditionEffectIndex.StasisImmune, DurationMS = 3000 }))); pkts.Add(new NotificationPacket { ObjectId = enemy.Id, Color = new ARGB(0xffff0000), Text = "Stasis" }); }); if (PvP) { Owner.AOE(target, 3, true, enemy => { var plr = (enemy as Player); if (!plr.PvP || (plr.PvP && plr.Team != 0 && plr.Team == Team) || plr == this) return; if (enemy.HasConditionEffect(ConditionEffects.StasisImmune)) { pkts.Add(new NotificationPacket { ObjectId = enemy.Id, Color = new ARGB(0xff00ff00), Text = "Immune" }); } else if (!enemy.HasConditionEffect(ConditionEffects.Stasis)) { if (enemy is Player && Owner.PvP) { if (enemy.Id == Id) return; enemy.ApplyConditionEffect( new ConditionEffect { Effect = ConditionEffectIndex.Stasis, DurationMS = eff.DurationMS }, new ConditionEffect { Effect = ConditionEffectIndex.Paused, DurationMS = eff.DurationMS }, new ConditionEffect { Effect = ConditionEffectIndex.Confused, DurationMS = eff.DurationMS } ); } Owner.Timers.Add(new WorldTimer(eff.DurationMS, (world, t) => enemy.ApplyConditionEffect(new ConditionEffect { Effect = ConditionEffectIndex.StasisImmune, DurationMS = 3000 }))); pkts.Add(new NotificationPacket { ObjectId = enemy.Id, Color = new ARGB(0xffff0000), Text = "Stasis" }); } }); } BroadcastSync(pkts, p => this.Dist(p) < 25); } break; case ActivateEffects.Decoy: { var decoy = new Decoy(this, eff.DurationMS, statsMgr.GetSpeed()); decoy.Move(X, Y); Owner.EnterWorld(decoy); } break; case ActivateEffects.Lightning: { if (!PvP) { Enemy start = null; double angle = Math.Atan2(target.Y - Y, target.X - X); double diff = Math.PI/3; Owner.AOE(target, 6, false, enemy => { if (!(enemy is Enemy)) return; double x = Math.Atan2(enemy.Y - Y, enemy.X - X); if (Math.Abs(angle - x) < diff) { start = enemy as Enemy; diff = Math.Abs(angle - x); } }); if (start == null) break; Enemy current = start; var targets = new Enemy[eff.MaxTargets]; for (int i = 0; i < targets.Length; i++) { targets[i] = current; var next = current.GetNearestEntity(8, false, enemy => enemy is Enemy && Array.IndexOf(targets, enemy) == -1 && this.Dist(enemy) <= 6) as Enemy; if (next == null) break; current = next; } var pkts = new List<Packet>(); for (int i = 0; i < targets.Length; i++) { if (targets[i] == null) break; Entity prev = i == 0 ? (Entity) this : targets[i - 1]; targets[i].Damage(this, time, eff.TotalDamage, false, false, null); if (eff.ConditionEffect != null) targets[i].ApplyConditionEffect(new ConditionEffect { Effect = eff.ConditionEffect.Value, DurationMS = (int) (eff.EffectDuration*1000) }); pkts.Add(new ShowEffectPacket { EffectType = EffectType.Lightning, TargetId = prev.Id, Color = new ARGB(0xffff0088), PosA = new Position { X = targets[i].X, Y = targets[i].Y }, PosB = new Position {X = 350} }); } BroadcastSync(pkts, p => this.Dist(p) < 25); } if (PvP) { Player start = null; double angle = Math.Atan2(target.Y - Y, target.X - X); double diff = Math.PI/3; Owner.AOE(target, 6, true, enemy => { //if (!(enemy is Player)) return; var plr = (enemy as Player); if (!plr.PvP || (plr.PvP && plr.Team != 0 && plr.Team == Team) || plr == this) return; double x = Math.Atan2(enemy.Y - Y, enemy.X - X); if (Math.Abs(angle - x) < diff) { start = enemy as Player; diff = Math.Abs(angle - x); } }); if (start == null) break; Player current = start; var targets = new Player[eff.MaxTargets]; for (int i = 0; i < targets.Length; i++) { targets[i] = current; var next = current.GetNearestEntity(8, true, enemy => enemy is Player && enemy.Id != Id && Array.IndexOf(targets, enemy) == -1 && (enemy as Player).PvP && ((enemy as Player).Team == 0 || (enemy as Player).Team != Team) && this.Dist(enemy) <= 6) as Player; if (next == null) break; current = next; } var pkts = new List<Packet>(); for (int i = 0; i < targets.Length; i++) { if (targets[i] == null) break; Entity prev = i == 0 ? this : targets[i - 1]; targets[i].Damage(eff.TotalDamage, targets[i], false, true, 0.20f); if (eff.ConditionEffect != null) targets[i].ApplyConditionEffect(new ConditionEffect { Effect = eff.ConditionEffect.Value, DurationMS = (int) (eff.EffectDuration*1000) }); pkts.Add(new ShowEffectPacket { EffectType = EffectType.Lightning, TargetId = prev.Id, Color = new ARGB(0xffff0088), PosA = new Position { X = targets[i].X, Y = targets[i].Y }, PosB = new Position {X = 350} }); } BroadcastSync(pkts, p => this.Dist(p) < 25); } } break; case ActivateEffects.PoisonGrenade: { BroadcastSync(new ShowEffectPacket { EffectType = EffectType.Throw, Color = new ARGB(0xffddff00), TargetId = Id, PosA = target }, p => this.Dist(p) < 25); var x = new Placeholder(Manager, 1500); x.Move(target.X, target.Y); Owner.EnterWorld(x); Owner.Timers.Add(new WorldTimer(1500, (world, t) => { if (Owner != null) { Owner.BroadcastPacket(new ShowEffectPacket { EffectType = EffectType.AreaBlast, TargetId = x.Id, Color = new ARGB(0xffddff00), PosA = new Position { X = eff.Radius } }, null); if (PvP) { var players = new List<Player>(); Owner.AOE(target, eff.Radius, true, enemy => { var plr = (enemy as Player); if (!plr.PvP || (plr.PvP && plr.Team != 0 && plr.Team == Team) || plr == this) return; players.Add(enemy as Player); foreach (Player i in players) if (i.Id != Id) PoisonPlayer(i, eff); }); } var enemies = new List<Enemy>(); Owner.AOE(target, eff.Radius, false, enemy => PoisonEnemy(enemy as Enemy, eff)); } })); } break; case ActivateEffects.RemoveNegativeConditions: { this.AOE(eff.Range, true, player => { var plr = (player as Player); if (PvP && (plr.Team == 0 || plr.Team != Team) && plr != this) return; ApplyConditionEffect(NegativeEffs); }); BroadcastSync(new ShowEffectPacket { EffectType = EffectType.AreaBlast, TargetId = Id, Color = new ARGB(0xffffffff), PosA = new Position {X = eff.Range} }, p => this.Dist(p) < 25); } break; case ActivateEffects.RemoveNegativeConditionsSelf: { ApplyConditionEffect(NegativeEffs); BroadcastSync(new ShowEffectPacket { EffectType = EffectType.AreaBlast, TargetId = Id, Color = new ARGB(0xffffffff), PosA = new Position {X = 1} }, p => this.Dist(p) < 25); } break; case ActivateEffects.IncrementStat: { int idx = -1; switch ((StatsType) eff.Stats) { case StatsType.MaximumHP: idx = 0; break; case StatsType.MaximumMP: idx = 1; break; case StatsType.Attack: idx = 2; break; case StatsType.Defense: idx = 3; break; case StatsType.Speed: idx = 4; break; case StatsType.Vitality: idx = 5; break; case StatsType.Wisdom: idx = 6; break; case StatsType.Dexterity: idx = 7; break; } if (eff.Amount > 0) Stats[idx] += eff.Amount; else Stats[idx] -= eff.Amount; int limit = int.Parse( Manager.GameData.ObjectTypeToElement[ObjectType].Element( StatsManager.StatsIndexToName(idx)).Attribute("max").Value); if (Stats[idx] > limit) Stats[idx] = limit; UpdateCount++; } break; case ActivateEffects.Create: //this is a portal { ushort objType; if (!Manager.GameData.IdToObjectType.TryGetValue(eff.Id, out objType) || !Manager.GameData.Portals.ContainsKey(objType)) break; // object not found, ignore Entity entity = Resolve(Manager, objType); entity.Move(X, Y); int TimeoutTime = Manager.GameData.Portals[objType].TimeoutTime; string DungeonName = Manager.GameData.Portals[objType].DungeonName; Owner.EnterWorld(entity); World w = Manager.GetWorld(Owner.Id); //can't use Owner here, as it goes out of scope Client.SendPacket(new NotificationPacket { Color = new ARGB(0xff00ff00), Text = "Opened by " + Client.Account.Name, ObjectId = Client.Player.Id, }); w.BroadcastPacket(new TextPacket { BubbleTime = 0, Stars = -1, Name = "", Text = DungeonName + " opened by " + Client.Account.Name }, null); w.Timers.Add(new WorldTimer(TimeoutTime*1000, (world, t) => //default portal close time * 1000 { try { w.LeaveWorld(entity); } catch //couldn't remove portal, Owner became null. Should be fixed with RealmManager implementation { Console.WriteLine("Couldn't despawn portal."); } })); } break; case ActivateEffects.PermaPet: client.Character.Pet = Manager.GameData.IdToObjectType[eff.ObjectId]; GivePet(Manager.GameData.IdToObjectType[eff.ObjectId]); UpdateCount++; break; case ActivateEffects.UnlockPortal: break; case ActivateEffects.Dye: if (item.Texture1 != 0) { Texture1 = item.Texture1; } if (item.Texture2 != 0) { Texture2 = item.Texture2; } SaveToCharacter(); break; case ActivateEffects.UnlockSkin: if (Manager.GameData.Skins.ContainsKey((ushort) eff.SkinType)) { SkinDesc skin = Manager.GameData.Skins[(ushort) eff.SkinType]; if (skin.PlayerClassType == -1 || skin.PlayerClassType == ObjectType) { Skin = eff.SkinType; PermaSkin = !item.Consumable || (data != null ? data.MultiUse : false); if (data != null && data.Effect != "") { Effect = (data.FullEffect == "" ? UnusualEffects.Save(data.Effect) : data.FullEffect); } else { Effect = ""; } SendInfo("Successfully changed skin."); } else { success = false; SendError("Your class cannot use this skin."); } } else { success = false; SendError("Invalid skin type."); } break; case ActivateEffects.ShurikenAbility: { usingShuriken = !usingShuriken; if (usingShuriken) { ApplyConditionEffect(new ConditionEffect { Effect = ConditionEffectIndex.Speedy, DurationMS = -1 }); } else { ApplyConditionEffect(new ConditionEffect { Effect = ConditionEffectIndex.Speedy, DurationMS = 0 }); if (MP >= item.MpEndCost) { MP -= item.MpEndCost; ActivateShoot(time, item, target); } } } break; case ActivateEffects.SwitchMusic: { Client.SendPacket(new SwitchMusicPacket { Music = eff.Id }); } break; case ActivateEffects.OpenCrate: { success = false; try { this.ItemSelect((_item, _data) => { return _item.IsCrate; }, _slot => { bool succeeded = false; for (int i = 0; i < Inventory.Length; i++) { if (Inventory[i] == null) continue; if (Inventory[i].ObjectId == "Supply Crate Key") { Inventory[i] = null; Inventory.Data[i] = null; succeeded = true; break; } } if (succeeded) { Item originalItem = Inventory[_slot]; Random rand1 = new Random(); int choice = rand1.Next(1, 101); if (choice > 20 && !originalItem.UnusualCrate) { if (rand1.Next(0,5) != 0) { int[] types = new int[] { 1, 2, 3, 8, 17, 24 }; List<Item> candidates = Manager.GameData.Items .Where(_item => Array.IndexOf(types, _item.Value.SlotType) != -1) .Where(_item => _item.Value.Tier == rand1.Next(8, 11 + 1)) .Select(_item => _item.Value) .ToList(); candidates.Shuffle(); Inventory[_slot] = Manager.GameData.Items[Manager.GameData.IdToObjectType["Strangifier"]]; Inventory.Data[_slot] = new ItemData { NamePrefix = candidates[0].ObjectId, NameColor = 0xFF5A28 }; } else { List<string> Parts = new List<string>(){ "God Kills", "Quest Kills", "Oryx Kills", "Kills While Cloaked", "Kills Near Death" }; Parts.Shuffle(); Inventory[_slot] = Manager.GameData.Items[Manager.GameData.IdToObjectType["Strange Part"]]; Inventory.Data[_slot] = new ItemData { NamePrefix = Parts[0] }; } } else { List<Item> candidates = Manager.GameData.Items .Where(_item => { foreach (var activEff in _item.Value.ActivateEffects) if (activEff.Effect == ActivateEffects.UnlockSkin) return true; return false; }) .Where(_item => { if (originalItem.Premium && !_item.Value.Premium) return false; if (!originalItem.Premium && _item.Value.Premium) return false; return true; }) .Select(_item => _item.Value) .ToList(); candidates.Shuffle(); Inventory[_slot] = candidates[0]; Inventory.Data[_slot] = null; if (rand1.Next(0, 6) == 0 || originalItem.UnusualCrate) { List<string> effects = new List<string>(); if (originalItem.Crate != 0) effects = UnusualEffects.Series[originalItem.Crate]; else if (!this.Client.Account.Admin) { foreach (var i in UnusualEffects.Series) if (i.Key > 0 && i.Key <= UnusualEffects.CurrentSeries) effects.AddRange(i.Value); } else { foreach (var i in UnusualEffects.Series) if (i.Key != 0) effects.AddRange(i.Value); } Inventory.Data[_slot] = new ItemData { NamePrefix = "Unusual", NameColor = 0x8000FF, Effect = effects.RandomElement(rand1), }; Inventory.Data[_slot].FullEffect = UnusualEffects.Save(Inventory.Data[_slot].Effect); } } client.SendPacket(new ItemResultPacket { ItemID = Inventory[_slot].ObjectType, Data = Inventory.Data[_slot] != null ? Inventory.Data[_slot].GetJson() : "{}" }); string msg = "{c}" + this.GetNameColor() + "{/c}" + Name + "{c}0xFFFFFF{/c} has unboxed: {c}" + ((Inventory.Data[_slot] != null && Inventory.Data[_slot].NameColor != 0xFFFFFF) ? Inventory.Data[_slot].NameColor.ToString() : "0xFFFF00") + "{/c}" + ((Inventory.Data[_slot] != null && Inventory.Data[_slot].NamePrefix != "") ? Inventory.Data[_slot].NamePrefix + " " : "") + ((Inventory.Data[_slot] != null && Inventory.Data[_slot].Name != "") ? Inventory.Data[_slot].Name : Inventory[_slot].DisplayId ?? Inventory[_slot].ObjectId); Owner.BroadcastPacket(new TextPacket { BubbleTime = 0, Stars = -1, Name = "", Text = msg }, null); UpdateCount++; } }); } catch (Exception e) { Console.WriteLine(e); } } break; case ActivateEffects.RenameItem: { success = false; this.ItemSelect((_item, _data) => { return _item != item; }, _slot => { client.SendPacket(new GetTextInputPacket { Name = "Choose a new item name", Action = "renameSlot" + _slot.ToString() }); }); } break; case ActivateEffects.RemoveSkin: { success = false; if (Skin == -1) { SendError("No skin equipped"); break; } if (Manager.GameData.SkinToItem.ContainsKey((ushort)Skin) && !PermaSkin) { Inventory[itemSlot] = Manager.GameData.SkinToItem[(ushort)Skin]; Inventory.Data[itemSlot] = null; if (Effect != "") { string effId = Utils.FromCommaSepString(Effect)[0]; Inventory.Data[itemSlot] = new ItemData() { NamePrefix = "Unusual", NameColor = 0x8000FF, Effect = effId, FullEffect = Effect }; } } Damage((int)Math.Ceiling((double)HP / 2), this, true, true, 1.0f); Skin = -1; PermaSkin = false; Effect = ""; UpdateCount++; } break; case ActivateEffects.BindSkin: { success = false; this.ItemSelect((_item, _data) => { foreach (var activEff in _item.ActivateEffects) if (activEff.Effect == ActivateEffects.UnlockSkin) return (_data != null) ? !_data.Soulbound : true; return false; }, _slot => { if(Inventory[_slot] == null) { SendError("Item no longer exists"); return; } bool isSkin = false; foreach (var activEff in Inventory[_slot].ActivateEffects) if (activEff.Effect == ActivateEffects.UnlockSkin) isSkin = (Inventory.Data[_slot] != null) ? !Inventory.Data[_slot].Soulbound : true; if (!isSkin) { SendError("Item is not a valid skin"); return; } if (Inventory[itemSlot] == null) { SendError("Skin keeper no longer exists"); return; } bool succeeded = false; foreach (var activEff in Inventory[itemSlot].ActivateEffects) if (activEff.Effect == ActivateEffects.BindSkin) succeeded = true; if (!succeeded) { SendError("Invalid skin keeper"); return; } if (Inventory.Data[_slot] == null) Inventory.Data[_slot] = new ItemData(); Inventory.Data[_slot].Soulbound = true; Inventory.Data[_slot].MultiUse = true; Inventory[itemSlot] = null; Inventory.Data[itemSlot] = null; UpdateCount++; }); } break; case ActivateEffects.StrangePart: { success = false; this.ItemSelect((_item, _data) => { return _item != null && _data != null && _data.Strange && !data.StrangeParts.ContainsKey(data.NamePrefix); }, _slot => { if (Inventory[_slot] == null || Inventory.Data[_slot] == null) { SendError("Item no longer exists"); return; } if (Inventory[itemSlot] == null || Inventory.Data[itemSlot] == null) { SendError("Strange part no longer exists"); return; } bool succeeded = false; foreach (var activEff in Inventory[itemSlot].ActivateEffects) if (activEff.Effect == ActivateEffects.StrangePart) succeeded = true; if (!succeeded || Inventory.Data[itemSlot].NamePrefix == "") { SendError("Invalid strange part"); return; } Inventory.Data[_slot].StrangeParts.TryAdd(Inventory.Data[itemSlot].NamePrefix, 0); Inventory[itemSlot] = null; Inventory.Data[itemSlot] = null; UpdateCount++; }); } break; case ActivateEffects.Strangify: { success = false; if(data.NamePrefix == "") break; this.ItemSelect((_item, _data) => { return _item != null && _item.ObjectId == data.NamePrefix && ((_data != null && !_data.Strange) || (_data == null)); }, _slot => { if (Inventory[_slot] == null) { SendError("Item no longer exists"); return; } if (Inventory[itemSlot] == null || Inventory.Data[itemSlot] == null) { SendError("Strangifier no longer exists"); return; } bool succeeded = false; foreach (var activEff in Inventory[itemSlot].ActivateEffects) if (activEff.Effect == ActivateEffects.Strangify) succeeded = true; if (!succeeded || Inventory.Data[itemSlot].NamePrefix != Inventory[_slot].ObjectId) { SendError("Invalid strangifier"); return; } if (Inventory.Data[_slot] == null) Inventory.Data[_slot] = new ItemData(); Inventory.Data[_slot].Strange = true; Inventory.Data[_slot].NamePrefix = "Strange"; Inventory.Data[_slot].NameColor = 0xFF5A28; Inventory[itemSlot] = null; Inventory.Data[itemSlot] = null; UpdateCount++; }); } break; case ActivateEffects.UnbindSkin: { success = false; if (Skin != -1) { SendError("You cannot wear a skin while unbinding a skin item."); break; } this.ItemSelect((_item, _data) => { foreach (var activEff in _item.ActivateEffects) if (activEff.Effect == ActivateEffects.UnlockSkin) return _data != null && _data.Soulbound && _data.MultiUse; return false; }, _slot => { if (Skin != -1) { SendError("You cannot wear a skin while unbinding a skin item."); return; } if (Inventory[_slot] == null) { SendError("Item no longer exists"); return; } bool isSkin = false; foreach (var activEff in Inventory[_slot].ActivateEffects) if (activEff.Effect == ActivateEffects.UnlockSkin) isSkin = Inventory.Data[_slot] != null && Inventory.Data[_slot].Soulbound && Inventory.Data[_slot].MultiUse; if (!isSkin) { SendError("Item is not a valid skin"); return; } if (Inventory[itemSlot] == null) { SendError("Skin disowner no longer exists"); return; } bool succeeded = false; foreach (var activEff in Inventory[itemSlot].ActivateEffects) if (activEff.Effect == ActivateEffects.UnbindSkin) succeeded = true; if (!succeeded) { SendError("Invalid skin disowner"); return; } if (Inventory.Data[_slot] != null) { Inventory.Data[_slot].Soulbound = false; Inventory.Data[_slot].MultiUse = false; } Inventory[itemSlot] = null; Inventory.Data[itemSlot] = null; UpdateCount++; }); } break; } } UpdateCount++; return success; }
void Activate(RealmTime time, Item item, Position target) { MP -= item.MpCost; foreach (var eff in item.ActivateEffects) { switch (eff.Effect) { case ActivateEffects.BulletNova: { var prjDesc = item.Projectiles[0]; //Assume only one Packet[] batch = new Packet[21]; uint s = Random.CurrentSeed; Random.CurrentSeed = (uint)(s * time.tickTimes); for (int i = 0; i < 20; i++) { Projectile proj = CreateProjectile(prjDesc, item.ObjectType, (int)statsMgr.GetAttackDamage(prjDesc.MinDamage, prjDesc.MaxDamage), time.tickTimes, target, (float)(i * (Math.PI * 2) / 20)); Owner.EnterWorld(proj); fames.Shoot(proj); batch[i] = new ShootPacket() { BulletId = proj.ProjectileId, OwnerId = Id, ContainerType = item.ObjectType, Position = target, Angle = proj.Angle, Damage = (short)proj.Damage }; } Random.CurrentSeed = s; batch[20] = new ShowEffectPacket() { EffectType = EffectType.Trail, PosA = target, TargetId = Id, Color = new ARGB(0xFFFF00AA) }; BroadcastSync(batch, p => this.Dist(p) < 25); } break; case ActivateEffects.Shoot: { ActivateShoot(time, item, target); } break; case ActivateEffects.StatBoostSelf: { int idx = -1; switch ((StatsType)eff.Stats) { case StatsType.MaximumHP: idx = 0; break; case StatsType.MaximumMP: idx = 1; break; case StatsType.Attack: idx = 2; break; case StatsType.Defense: idx = 3; break; case StatsType.Speed: idx = 4; break; case StatsType.Vitality: idx = 5; break; case StatsType.Wisdom: idx = 6; break; case StatsType.Dexterity: idx = 7; break; } int s = eff.Amount; Boost[idx] += s; UpdateCount++; Owner.Timers.Add(new WorldTimer(eff.DurationMS, (world, t) => { Boost[idx] -= s; UpdateCount++; })); BroadcastSync(new ShowEffectPacket() { EffectType = EffectType.Potion, TargetId = Id, Color = new ARGB(0xffffffff) }, null); } break; case ActivateEffects.StatBoostAura: { int idx = -1; switch ((StatsType)eff.Stats) { case StatsType.MaximumHP: idx = 0; break; case StatsType.MaximumMP: idx = 1; break; case StatsType.Attack: idx = 2; break; case StatsType.Defense: idx = 3; break; case StatsType.Speed: idx = 4; break; case StatsType.Vitality: idx = 5; break; case StatsType.Wisdom: idx = 6; break; case StatsType.Dexterity: idx = 7; break; } int s = eff.Amount; this.AOE(eff.Range / 2, true, player => { (player as Player).Boost[idx] += s; player.UpdateCount++; Owner.Timers.Add(new WorldTimer(eff.DurationMS, (world, t) => { (player as Player).Boost[idx] -= s; player.UpdateCount++; })); }); BroadcastSync(new ShowEffectPacket() { EffectType = EffectType.AreaBlast, TargetId = Id, Color = new ARGB(0xffffffff), PosA = new Position() { X = eff.Range / 2 } }, p => this.Dist(p) < 25); } break; case ActivateEffects.ConditionEffectSelf: { ApplyConditionEffect(new ConditionEffect() { Effect = eff.ConditionEffect.Value, DurationMS = eff.DurationMS }); BroadcastSync(new ShowEffectPacket() { EffectType = EffectType.AreaBlast, TargetId = Id, Color = new ARGB(0xffffffff), PosA = new Position() { X = 1 } }, p => this.Dist(p) < 25); } break; case ActivateEffects.ConditionEffectAura: { this.AOE(eff.Range / 2, true, player => { player.ApplyConditionEffect(new ConditionEffect() { Effect = eff.ConditionEffect.Value, DurationMS = eff.DurationMS }); }); uint color = 0xffffffff; if (eff.ConditionEffect.Value == ConditionEffectIndex.Damaging) color = 0xffff0000; BroadcastSync(new ShowEffectPacket() { EffectType = EffectType.AreaBlast, TargetId = Id, Color = new ARGB(color), PosA = new Position() { X = eff.Range / 2 } }, p => this.Dist(p) < 25); } break; case ActivateEffects.Heal: { List<Packet> pkts = new List<Packet>(); ActivateHealHp(this, eff.Amount, pkts); BroadcastSync(pkts, p => this.Dist(p) < 25); } break; case ActivateEffects.HealNova: { List<Packet> pkts = new List<Packet>(); this.AOE(eff.Range / 2, true, player => { ActivateHealHp(player as Player, eff.Amount, pkts); }); pkts.Add(new ShowEffectPacket() { EffectType = EffectType.AreaBlast, TargetId = Id, Color = new ARGB(0xffffffff), PosA = new Position() { X = eff.Range / 2 } }); BroadcastSync(pkts, p => this.Dist(p) < 25); } break; case ActivateEffects.Magic: { List<Packet> pkts = new List<Packet>(); ActivateHealMp(this, eff.Amount, pkts); BroadcastSync(pkts, p => this.Dist(p) < 25); } break; case ActivateEffects.MagicNova: { List<Packet> pkts = new List<Packet>(); this.AOE(eff.Range / 2, true, player => { ActivateHealMp(player as Player, eff.Amount, pkts); }); pkts.Add(new ShowEffectPacket() { EffectType = EffectType.AreaBlast, TargetId = Id, Color = new ARGB(0xffffffff), PosA = new Position() { X = eff.Range / 2 } }); BroadcastSync(pkts, p => this.Dist(p) < 25); } break; case ActivateEffects.Teleport: { Move(target.X, target.Y); UpdateCount++; BroadcastSync(new Packet[] { new GotoPacket() { ObjectId = Id, Position = new Position() { X = X, Y = Y } }, new ShowEffectPacket() { EffectType = EffectType.Teleport, TargetId = Id, PosA = new Position() { X = X, Y = Y }, Color = new ARGB(0xFFFFFFFF) } }, p => this.Dist(p) < 25); } break; case ActivateEffects.VampireBlast: { List<Packet> pkts = new List<Packet>(); pkts.Add(new ShowEffectPacket() { EffectType = EffectType.Trail, TargetId = Id, PosA = target, Color = new ARGB(0xFFFF0000) }); pkts.Add(new AOEPacket() { Position = target, Radius = eff.Radius, Damage = (ushort)eff.TotalDamage, EffectDuration = 0, Effects = 0, OriginType = item.ObjectType }); int totalDmg = 0; var enemies = new List<Enemy>(); Owner.AOE(target, eff.Radius, false, enemy => { enemies.Add(enemy as Enemy); totalDmg += (enemy as Enemy).Damage(this, time, eff.TotalDamage, false); }); var players = new List<Player>(); this.AOE(eff.Radius, true, player => { players.Add(player as Player); ActivateHealHp(player as Player, totalDmg, pkts); }); Random rand = new System.Random(); for (int i = 0; i < 5; i++) { Enemy a = enemies[rand.Next(0, enemies.Count)]; Player b = players[rand.Next(0, players.Count)]; pkts.Add(new ShowEffectPacket() { EffectType = EffectType.Flow, TargetId = b.Id, PosA = new Position() { X = a.X, Y = a.Y }, Color = new ARGB(0xffffffff) }); } BroadcastSync(pkts, p => this.Dist(p) < 25); } break; case ActivateEffects.Trap: { BroadcastSync(new ShowEffectPacket() { EffectType = EffectType.Throw, Color = new ARGB(0xff9000ff), TargetId = Id, PosA = target }, p => this.Dist(p) < 25); Owner.Timers.Add(new WorldTimer(1500, (world, t) => { Trap trap = new Trap( this, eff.Radius, eff.TotalDamage, eff.ConditionEffect ?? ConditionEffectIndex.Slowed, eff.EffectDuration); trap.Move(target.X, target.Y); world.EnterWorld(trap); })); } break; case ActivateEffects.StasisBlast: { List<Packet> pkts = new List<Packet>(); pkts.Add(new ShowEffectPacket() { EffectType = EffectType.Concentrate, TargetId = Id, PosA = target, PosB = new Position() { X = target.X + 3, Y = target.Y }, Color = new ARGB(0xffffffff) }); Owner.AOE(target, 3, false, enemy => { if (enemy.HasConditionEffect(ConditionEffects.StasisImmune)) { pkts.Add(new NotificationPacket() { ObjectId = enemy.Id, Color = new ARGB(0xff00ff00), Text = "Immune" }); } else if (!enemy.HasConditionEffect(ConditionEffects.Stasis)) { enemy.ApplyConditionEffect( new ConditionEffect() { Effect = ConditionEffectIndex.Stasis, DurationMS = eff.DurationMS }, new ConditionEffect() { Effect = ConditionEffectIndex.Confused, DurationMS = eff.DurationMS } ); Owner.Timers.Add(new WorldTimer(eff.DurationMS, (world, t) => { enemy.ApplyConditionEffect(new ConditionEffect() { Effect = ConditionEffectIndex.StasisImmune, DurationMS = 3000 } ); } )); pkts.Add(new NotificationPacket() { ObjectId = enemy.Id, Color = new ARGB(0xffff0000), Text = "Stasis" }); } }); BroadcastSync(pkts, p => this.Dist(p) < 25); } break; case ActivateEffects.Decoy: { var decoy = new Decoy(this, eff.DurationMS, statsMgr.GetSpeed()); decoy.Move(X, Y); Owner.EnterWorld(decoy); } break; case ActivateEffects.Lightning: { Enemy start = null; double angle = Math.Atan2(target.Y - Y, target.X - X); double diff = Math.PI / 3; Owner.AOE(target, 6, false, enemy => { if (!(enemy is Enemy)) return; var x = Math.Atan2(enemy.Y - Y, enemy.X - X); if (Math.Abs(angle - x) < diff) { start = enemy as Enemy; diff = Math.Abs(angle - x); } }); if (start == null) break; Enemy current = start; Enemy[] targets = new Enemy[eff.MaxTargets]; for (int i = 0; i < targets.Length; i++) { targets[i] = current; Enemy next = current.GetNearestEntity(8, false, enemy => enemy is Enemy && Array.IndexOf(targets, enemy) == -1 && this.Dist(enemy) <= 6) as Enemy; if (next == null) break; else current = next; } List<Packet> pkts = new List<Packet>(); for (int i = 0; i < targets.Length; i++) { if (targets[i] == null) break; Entity prev = i == 0 ? (Entity)this : targets[i - 1]; targets[i].Damage(this, time, eff.TotalDamage, false); if (eff.ConditionEffect != null) targets[i].ApplyConditionEffect(new ConditionEffect() { Effect = eff.ConditionEffect.Value, DurationMS = (int)(eff.EffectDuration * 1000) }); pkts.Add(new ShowEffectPacket() { EffectType = EffectType.Lightning, TargetId = prev.Id, Color = new ARGB(0xffff0088), PosA = new Position() { X = targets[i].X, Y = targets[i].Y }, PosB = new Position() { X = 350 } }); } BroadcastSync(pkts, p => this.Dist(p) < 25); } break; case ActivateEffects.PoisonGrenade: { BroadcastSync(new ShowEffectPacket() { EffectType = EffectType.Throw, Color = new ARGB(0xffddff00), TargetId = Id, PosA = target }, p => this.Dist(p) < 25); Placeholder x = new Placeholder(Manager, 1500); x.Move(target.X, target.Y); Owner.EnterWorld(x); Owner.Timers.Add(new WorldTimer(1500, (world, t) => { Owner.BroadcastPacket(new ShowEffectPacket() { EffectType = EffectType.AreaBlast, Color = new ARGB(0xffddff00), TargetId = x.Id, PosA = new Position() { X = eff.Radius } }, null); List<Enemy> enemies = new List<Enemy>(); Owner.AOE(target, eff.Radius, false, enemy => PoisonEnemy(enemy as Enemy, eff)); })); } break; case ActivateEffects.RemoveNegativeConditions: { this.AOE(eff.Range / 2, true, player => { ApplyConditionEffect(NegativeEffs); }); BroadcastSync(new ShowEffectPacket() { EffectType = EffectType.AreaBlast, TargetId = Id, Color = new ARGB(0xffffffff), PosA = new Position() { X = eff.Range / 2 } }, p => this.Dist(p) < 25); } break; case ActivateEffects.RemoveNegativeConditionsSelf: { ApplyConditionEffect(NegativeEffs); BroadcastSync(new ShowEffectPacket() { EffectType = EffectType.AreaBlast, TargetId = Id, Color = new ARGB(0xffffffff), PosA = new Position() { X = 1 } }, p => this.Dist(p) < 25); } break; case ActivateEffects.IncrementStat: { int idx = -1; switch ((StatsType)eff.Stats) { case StatsType.MaximumHP: idx = 0; break; case StatsType.MaximumMP: idx = 1; break; case StatsType.Attack: idx = 2; break; case StatsType.Defense: idx = 3; break; case StatsType.Speed: idx = 4; break; case StatsType.Vitality: idx = 5; break; case StatsType.Wisdom: idx = 6; break; case StatsType.Dexterity: idx = 7; break; } Stats[idx] += eff.Amount; int limit = int.Parse(Manager.GameData.ObjectTypeToElement[ObjectType].Element(StatsManager.StatsIndexToName(idx)).Attribute("max").Value); if (Stats[idx] > limit) Stats[idx] = limit; UpdateCount++; } break; case ActivateEffects.Create: //this is a portal { ushort objType; if (!Manager.GameData.IdToObjectType.TryGetValue(eff.Id, out objType) || !Manager.GameData.Portals.ContainsKey(objType)) break;// object not found, ignore var entity = Entity.Resolve(Manager, objType); entity.Move(X, Y); int TimeoutTime = Manager.GameData.Portals[objType].TimeoutTime; Owner.EnterWorld(entity); World w = Manager.GetWorld(Owner.Id); //can't use Owner here, as it goes out of scope w.Timers.Add(new WorldTimer(TimeoutTime * 1000, (world, t) => //default portal close time * 1000 { try { w.LeaveWorld(entity); } catch //couldn't remove portal, Owner became null. Should be fixed with RealmManager implementation { Console.WriteLine("Couldn't despawn portal."); } })); } break; case ActivateEffects.Pet: case ActivateEffects.UnlockPortal: break; } } UpdateCount++; }