/// <summary> /// Use a offensive skills /// </summary> /// <param name="target"></param> /// <param name="source"></param> /// <param name="skillid"></param> /// <param name="skilltype"></param> /// <remarks> /// This functions is invoked by mob ai. The character has it's own skill handler /// inside the network client. /// </remarks> public static void OffensiveSkillUse(MapObject target, MapObject source, uint skillid, byte skilltype) { try { SkillUsageEventArgs argument = null; if (SkillUsageEventArgs.Create(skillid, source, target, out argument) && argument.Use()) { Predicate <Character> SendToCharacter = delegate(Character forwardTarget) { //Skill sucess SMSG_OFFENSIVESKILL spkt = new SMSG_OFFENSIVESKILL(); spkt.SkillID = skillid; spkt.SkillType = 1; spkt.TargetActor = target.id; spkt.SourceActor = source.id; spkt.IsCritical = (forwardTarget.id == source.id || forwardTarget.id == target.id) ? (byte)argument.Result : (byte)7; spkt.Damage = argument.Damage; spkt.SessionId = forwardTarget.id; forwardTarget.client.Send((byte[])spkt); //Process some general updates if (forwardTarget._targetid == target.id) { Common.Actions.SelectActor(forwardTarget, target as Actor); } if (argument.TargetHasDied) { Common.Actions.UpdateStance(forwardTarget, target as Actor); } if (argument.TargetHasDied && MapObject.IsNpc(target)) { Common.Actions.UpdateIcon(forwardTarget, target as BaseMob); } if (forwardTarget.id == target.id) { LifeCycle.Update(forwardTarget); } return(true); }; Regiontree tree = source.currentzone.Regiontree; foreach (Character forwardTarget in tree.SearchActors(source, SearchFlags.Characters)) { SendToCharacter(forwardTarget); } } } catch (Exception e) { Console.WriteLine(e); } }
/// <summary> /// Occurs when using an offensive skill /// </summary> /// <param name="cpkt"></param> private void CM_USEOFFENSIVESKILL(CMSG_OFFENSIVESKILL cpkt) { lock (this.character.cooldowncollection) { try { MapObject target; uint skillid = cpkt.SkillID; byte skilltype = cpkt.SkillType; SkillUsageEventArgs argument = null; bool cancast = Regiontree.TryFind(cpkt.TargetActor, this.character, out target) && SkillUsageEventArgs.Create(skillid, this.character, target, out argument) && argument.SpellInfo.casttime > -1 && (argument.SpellInfo.casttime == 0 || this.character._lastcastedskill == skillid) && ((long)((uint)Environment.TickCount) - this.character._lastcastedtick) > 0 && (argument.SpellInfo.delay == 0 || !this.character.cooldowncollection.IsCoolDown(skillid)) && (argument.SpellInfo.maximumrange == 0 || argument.SpellInfo.IsInRangeOf((int)(Vector.GetDistance2D(this.character.Position, target.Position)))) && argument.SpellInfo.requiredWeapons[this.character.weapons.GetCurrentWeaponType()] == 1 && this.character.jlvl >= argument.SpellInfo.requiredJobs[this.character.job - 1] && this.character.Status.CurrentLp >= (argument.SpellInfo.requiredlp == 6?1:argument.SpellInfo.requiredlp) && argument.SpellInfo.IsTarget(this.character, target); if (cancast && argument.Use()) { //Clear casted skill this.character._lastcastedskill = 0; this.character._lastcastedtick = Environment.TickCount; //Set cooldown timer int delay = (int)(argument.SpellInfo.delay - ((character.stats.Dexterity * 2) + (character.stats.Concentration * 2))); if (delay > 0) { this.character.cooldowncollection.Add(skillid, delay); } this.character.cooldowncollection.Update(); //Use required sp points if (argument.SpellInfo.SP > -1) { this.character.LASTSP_TICK = Environment.TickCount; this.character.SP = (ushort)(this.character.SP - argument.SpellInfo.SP); } //Set sp to 0 else if (argument.SpellInfo.SP == -1) { this.character.LASTSP_TICK = Environment.TickCount; this.character.SP = 0; } //Use required lp points if (argument.SpellInfo.requiredlp == 6) { this.character._status.CurrentLp = 0; this.character._status.Updates |= 1; } else if (argument.SpellInfo.requiredlp > 0) { this.character._status.CurrentLp -= argument.SpellInfo.requiredlp; this.character._status.Updates |= 1; } //Add intergrated durabillity checks if (argument.CanCheckWeaponDurabillity) { Common.Durabillity.DoWeapon(this.character); } //Skill sucess Predicate <Character> SendToCharacter = delegate(Character forwardTarget) { //Skill sucess SMSG_OFFENSIVESKILL spkt = new SMSG_OFFENSIVESKILL(); spkt.SkillID = cpkt.SkillID; spkt.SkillType = cpkt.SkillType; spkt.TargetActor = cpkt.TargetActor; spkt.SourceActor = this.character.id; spkt.IsCritical = (forwardTarget.id == this.character.id || forwardTarget.id == target.id) ? (byte)argument.Result : (byte)7; spkt.Damage = argument.Damage; spkt.SessionId = forwardTarget.id; forwardTarget.client.Send((byte[])spkt); //Process some general updates if (forwardTarget._targetid == target.id) { Common.Actions.SelectActor(forwardTarget, target as Actor); } if (argument.TargetHasDied) { Common.Actions.UpdateStance(forwardTarget, target as Actor); } if (argument.TargetHasDied && MapObject.IsNpc(target)) { Common.Actions.UpdateIcon(forwardTarget, target as BaseMob); } return(true); }; SendToCharacter(this.character); Regiontree tree = this.character.currentzone.Regiontree; foreach (Character forwardTarget in tree.SearchActors(this.character, SearchFlags.Characters)) { if (forwardTarget.id == this.character.id) { continue; } SendToCharacter(forwardTarget); } //Always update myself and oponent if it's character LifeCycle.Update(this.character); if (MapObject.IsPlayer(target)) { LifeCycle.Update(target as Character); } } else { //Skill failed SMSG_OFFENSIVESKILLFAILED spkt = new SMSG_OFFENSIVESKILLFAILED(); spkt.SkillID = cpkt.SkillID; spkt.SkillType = cpkt.SkillType; spkt.SourceActor = this.character.id; spkt.SessionId = this.character.id; this.Send((byte[])spkt); } } catch (Exception e) { Trace.TraceError("Exception processing the skill {0}", e.ToString()); //Skill failed SMSG_OFFENSIVESKILLFAILED spkt = new SMSG_OFFENSIVESKILLFAILED(); spkt.SkillID = cpkt.SkillID; spkt.SkillType = cpkt.SkillType; spkt.SourceActor = this.character.id; spkt.SessionId = this.character.id; this.Send((byte[])spkt); } } }