/// <summary> /// Handles Heavy Stander bonuses and auto-defense, reducing damage /// and setting the appropriate options on tAction. Returns whether /// or not Heavy Stander pinged. /// </summary> /// <remarks> /// All active and passive Heavy Standers are checked in sequence, /// followed by the equipment, with the passive damage reduction /// stacking. It's unknown whether this is official, and assumedly /// no monsters have multiple Heavy Stander skills. /// The ping reduction is only applied once, no matter where it /// came from. /// </remarks> /// <param name="attacker"></param> /// <param name="target"></param> /// <param name="damage"></param> /// <param name="tAction"></param> public static bool Handle(Creature attacker, Creature target, ref float damage, TargetAction tAction) { var pinged = false; var rank = DefaultMsgRank; var rnd = RandomProvider.Get(); // Dark Lord is immune to melee and magic damage, // like a R1 passive defense, but he doesn't ping. if (target.HasTag("/darklord/") && !target.HasTag("/darklord/darklord2/")) { damage = 1; return false; } // Monsters with the /beatable_only/ tag don't take damage from // anything but pillows. Pillows on the other hand do 3x damage. // (Guessed, based on event information and client data.) if (target.HasTag("/beatable_only/")) { var rightHand = attacker.RightHand; if (rightHand == null || !rightHand.HasTag("/pillow/")) damage = 1; else damage *= 3; } // Check skills for (int i = 0; i < Skills.Length; ++i) { // Check if skill exists and it's either in use or passive var skill = target.Skills.Get(Skills[i]); if (skill != null && (skill.Info.Id == SkillId.HeavyStanderPassive || skill.Has(SkillFlags.InUse))) { var damageReduction = skill.RankData.Var1; var activationChance = skill.RankData.Var3; // Apply damage reduction if (damageReduction > 0) damage = Math.Max(1, damage - (damage / 100 * damageReduction)); // Apply auto defense if (!pinged && rnd.Next(100) < activationChance) { pinged = true; rank = skill.Info.Rank; } } } // Check equipment if (!pinged) { var equipment = target.Inventory.GetMainEquipment(); for (int i = 0; i < equipment.Length; ++i) { var activationChance = equipment[i].Data.AutoDefenseMelee; // Add upgrades activationChance += equipment[i].MetaData1.GetFloat("IM_MLE") * 100; if (activationChance > 0 && rnd.Next(100) < activationChance) { pinged = true; break; } } } // Notice, flag, and damage reduction if (pinged) { damage = Math.Max(1, damage / 2); tAction.EffectFlags |= EffectFlags.HeavyStander; var msg = ""; if (rank >= SkillRank.Novice && rank <= SkillRank.RA) msg = rnd.Rnd(Lv1Msgs); else if (rank >= SkillRank.R9 && rank <= SkillRank.R5) msg = rnd.Rnd(Lv2Msgs); else if (rank >= SkillRank.R4 && rank <= SkillRank.R1) msg = rnd.Rnd(Lv3Msgs); Send.Notice(attacker, msg); } return pinged; }
/// <summary> /// Returns true if creature is able to attack this creature. /// </summary> /// <param name="creature"></param> /// <returns></returns> public bool CanAttack(Creature creature) { if (creature.IsInvincible) return false; //Check override first... foreach (object target in this.AttackOverride) { //Check state first, then tag, then the creature itself. if (target is CreatureStates) { if (creature.Has((CreatureStates)target)) return true; } else if (target is string) { if (creature.HasTag((string)target)) return true; } else { if (creature == target) return true; } } //Then check the actual filter. foreach (object target in this.AttackFilter) { //Check state first, then tag, then the creature itself. if (target is CreatureStates) { if (creature.Has((CreatureStates)target)) return false; } else if (target is string) { if (creature.HasTag((string)target)) return false; } else { if (creature == target) return false; } } return true; }
public override bool Matches(Creature creature) { var isTag = (creature.HasTag(this.Tag)); return isTag; }