/// <summary> /// Uses LightningRod /// </summary> /// <param name="attacker"></param> /// <param name="skill"></param> /// <param name="packet"></param> public void Use(Creature attacker, Skill skill, Packet packet) { // Set full charge variable attacker.Temp.LightningRodFullCharge = (DateTime.Now >= attacker.Temp.LightningRodPrepareTime.AddMilliseconds(skill.RankData.Var3)); // Get direction for target Area var direction = Mabi.MabiMath.ByteToRadian(attacker.Direction); var attackerPos = attacker.GetPosition(); // Calculate polygon points var r = MabiMath.ByteToRadian(attacker.Direction); var poe = attackerPos.GetRelative(r, 800); var pivot = new Point(poe.X, poe.Y); var p1 = new Point(pivot.X - SkillLength / 2, pivot.Y - SkillWidth / 2); var p2 = new Point(pivot.X - SkillLength / 2, pivot.Y + SkillWidth / 2); var p3 = new Point(pivot.X + SkillLength / 2, pivot.Y + SkillWidth / 2); var p4 = new Point(pivot.X + SkillLength / 2, pivot.Y - SkillWidth / 2); p1 = this.RotatePoint(p1, pivot, r); p2 = this.RotatePoint(p2, pivot, r); p3 = this.RotatePoint(p3, pivot, r); p4 = this.RotatePoint(p4, pivot, r); // TargetProp var lProp = new Prop(280, attacker.RegionId, poe.X, poe.Y, MabiMath.ByteToRadian(attacker.Direction), 1f, 0f, "single"); attacker.Region.AddProp(lProp); // Prepare Combat Actions var cap = new CombatActionPack(attacker, skill.Info.Id); var targetAreaId = new Location(attacker.RegionId, poe).ToLocationId(); var aAction = new AttackerAction(CombatActionType.SpecialHit, attacker, targetAreaId); aAction.Set(AttackerOptions.KnockBackHit1 | AttackerOptions.UseEffect); aAction.PropId = lProp.EntityId; cap.Add(aAction); // Get targets in Polygon - includes collission check var targets = attacker.Region.GetCreaturesInPolygon(p1, p2, p3, p4).Where(x => attacker.CanTarget(x) && !attacker.Region.Collisions.Any(attacker.GetPosition(), x.GetPosition())).ToList(); var rnd = RandomProvider.Get(); // Check crit var crit = false; var critSkill = attacker.Skills.Get(SkillId.CriticalHit); if (critSkill != null && critSkill.Info.Rank > SkillRank.Novice) { var critChance = Math2.Clamp(0, 30, attacker.GetTotalCritChance(0)); if (rnd.NextDouble() * 100 < critChance) crit = true; } foreach (var target in targets) { var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, SkillId.CombatMastery); tAction.Set(TargetOptions.None); tAction.AttackerSkillId = skill.Info.Id; cap.Add(tAction); var damage = attacker.GetRndMagicDamage(skill, skill.RankData.Var1, skill.RankData.Var2); // Add damage if the skill is fully charged var dmgMultiplier = skill.RankData.Var4 / 100f; if (attacker.Temp.LightningRodFullCharge) { damage += (damage * dmgMultiplier); } // Critical Hit if (crit) { var bonus = critSkill.RankData.Var1 / 100f; damage = damage + (damage * bonus); tAction.Set(TargetOptions.Critical); } // MDef and MProt SkillHelper.HandleMagicDefenseProtection(target, ref damage); // Conditions SkillHelper.HandleConditions(attacker, target, ref damage); // Mana Deflector var delayReduction = ManaDeflector.Handle(attacker, target, ref damage, tAction); // Mana Shield ManaShield.Handle(target, ref damage, tAction); // Apply Damage target.TakeDamage(tAction.Damage = damage, attacker); // Stun Time tAction.Stun = TargetStun; // Death or Knockback if (target.IsDead) { tAction.Set(TargetOptions.FinishingKnockDown); attacker.Shove(target, KnockbackDistance); } else { // Always knock down if (target.Is(RaceStands.KnockDownable)) { tAction.Set(TargetOptions.KnockDown); attacker.Shove(target, KnockbackDistance); } } } // Update current weapon SkillHelper.UpdateWeapon(attacker, targets.FirstOrDefault(), ProficiencyGainType.Melee, attacker.RightHand); cap.Handle(); Send.Effect(attacker, Effect.LightningRod, (int)LightningRodEffect.Attack, poe.X, poe.Y); Send.SkillUse(attacker, skill.Info.Id, targetAreaId, 0, 1); skill.Train(1); // Use the Skill attacker.Region.RemoveProp(lProp); }
/// <summary> /// Saves characters, despawns and disposes them, etc. /// </summary> public override void CleanUp() { // Moved here to always be called when a client is being killed off. if (this.Controlling != null) ChannelServer.Instance.Events.OnPlayerDisconnect(this.Controlling); // Dispose creatures, to remove subscriptions and stuff. // Do this before unspawning, the creature might need the region. foreach (var creature in this.Creatures.Values) creature.Dispose(); foreach (var creature in this.Creatures.Values.Where(a => a.Region != Region.Limbo)) { // Close NPC sessions if (creature.Client.NpcSession.Script != null) creature.Client.NpcSession.Clear(); var newLocation = new Location(); // Use fallback location if creature is in a temp region. if (creature.Region is DynamicRegion) newLocation = creature.FallbackLocation; // Use dungeon exit as fallback location if in a dungeon. var dungeonRegion = creature.Region as DungeonRegion; if (dungeonRegion != null) { try { newLocation = new Location(dungeonRegion.Dungeon.Data.Exit); } catch (Exception ex) { Log.Exception(ex, "Failed to fallback warp character in dungeon."); newLocation = new Location(1, 12800, 38100); // Tir square } if (dungeonRegion.Dungeon.Script != null) dungeonRegion.Dungeon.Script.OnLeftEarly(dungeonRegion.Dungeon, creature); } // Unspawn creature creature.Region.RemoveCreature(creature); // Set new location (if applicable) after everyting else is done, // in case on of the previous calls needs the creature's // original position. if (newLocation.RegionId != 0) creature.SetLocation(newLocation); } // Save everything after we're done cleaning up if (this.Account != null) ChannelServer.Instance.Database.SaveAccount(this.Account); this.Creatures.Clear(); this.Account = null; }
protected void ShootFirework(Location location, FireworkType type, string message) { var region = ChannelServer.Instance.World.GetRegion(location.RegionId); if (region == null) { Log.Warning(this.GetType().Name + ".ShootFirework: Unknown region."); return; } if (message == null) message = ""; var delay = 500; var rnd = RandomProvider.Get(); var height = rnd.Between(750, 2000); var heightf = height / 100f; var prop = new Prop(208, location.RegionId, location.X, location.Y, 0); prop.DisappearTime = DateTime.Now.AddMilliseconds(20000 + delay); region.AddProp(prop); Task.Delay(delay).ContinueWith(__ => { prop.Xml.SetAttributeValue("height", height); prop.Xml.SetAttributeValue("message", message + " (" + heightf.ToString("0.##") + "m)"); prop.Xml.SetAttributeValue("type", (int)type); prop.Xml.SetAttributeValue("seed", Interlocked.Increment(ref _fireworkSeed)); Send.PropUpdate(prop); }); }
/// <summary> /// Warps creature, based on the item's properties. /// </summary> /// <param name="creature"></param> /// <param name="item"></param> /// <returns>Whether a warp happened or not.</returns> public static bool Warp(Creature creature, Item item) { if (creature == null) throw new ArgumentNullException("creature"); if (item == null) throw new ArgumentNullException("item"); // Check meta data if (!item.MetaData1.Has("TARGET")) { Send.ServerMessage(creature, Localization.Get("No target found.")); return false; } // Get target var target = item.MetaData1.GetString("TARGET"); // Get location based on target Location loc; if (target.StartsWith("pos")) // pos@regionId,x,y { var match = Regex.Match(target, @"pos@(?<regionId>[0-9]+),(?<x>[0-9]+),(?<y>[0-9]+)"); if (!match.Success) { Log.Warning("HiddenTownBack: Invalid position target: {0}", target); Send.ServerMessage(creature, Localization.Get("Invalid target.")); return false; } loc.RegionId = Convert.ToInt32(match.Groups["regionId"].Value); loc.X = Convert.ToInt32(match.Groups["x"].Value); loc.Y = Convert.ToInt32(match.Groups["y"].Value); } else if (target.StartsWith("portal")) // portal@name { // Remove "portal@" prefix target = target.Substring(7).Trim(); // Get portal data var portalData = AuraData.PortalDb.Find(target); if (portalData == null) { Log.Warning("HiddenTownBack: Unknown target: {0}", target); Send.ServerMessage(creature, Localization.Get("Unknown target.")); return false; } // Get location try { loc = new Location(portalData.Location); } catch { Log.Warning("HiddenTownBack: Invalid portal location: {0}", target); Send.ServerMessage(creature, Localization.Get("Invalid portal location.")); return false; } } else if (target == "last_town") { loc = new Location(creature.LastTown); } else { Log.Warning("HiddenTownBack: Unknown target type: {0}", target); Send.ServerMessage(creature, Localization.Get("Unknown target type.")); return false; } // Warp creature.Warp(loc); return true; }