//действие атаки. Атакуемый подписывается на событие атаки атакуеющего, затем атакующий вызывает свой метод атаки. Отслеживается здоровье атакованного и, если нужно, вызывает метод смерти public static void Attack(Unit Unit1, Unit Unit2, List <Unit> Units2) { Unit1.DoAttack += Unit2.Wound; Unit1.Attack(Unit1.weapon.Damage); Console.WriteLine($"{Unit1.Name}({Unit1.Number}) атакует {Unit2.Name}({Unit2.Number}) и наносит урон равный {Unit1.weapon.Damage}"); Unit1.DoAttack -= Unit2.Wound; if (Unit2.Health == 0) { Unit2.Dead(Units2, Unit2); } }
void HandlePetActionHelper(Unit pet, ObjectGuid guid1, uint spellid, ActiveStates flag, ObjectGuid guid2, float x, float y, float z) { CharmInfo charmInfo = pet.GetCharmInfo(); if (charmInfo == null) { Log.outError(LogFilter.Network, "WorldSession.HandlePetAction(petGuid: {0}, tagGuid: {1}, spellId: {2}, flag: {3}): object (GUID: {4} Entry: {5} TypeId: {6}) is considered pet-like but doesn't have a charminfo!", guid1, guid2, spellid, flag, pet.GetGUID().ToString(), pet.GetEntry(), pet.GetTypeId()); return; } switch (flag) { case ActiveStates.Command: //0x07 switch ((CommandStates)spellid) { case CommandStates.Stay: //flat=1792 //STAY pet.StopMoving(); pet.GetMotionMaster().Clear(false); pet.GetMotionMaster().MoveIdle(); charmInfo.SetCommandState(CommandStates.Stay); charmInfo.SetIsCommandAttack(false); charmInfo.SetIsAtStay(true); charmInfo.SetIsCommandFollow(false); charmInfo.SetIsFollowing(false); charmInfo.SetIsReturning(false); charmInfo.SaveStayPosition(); break; case CommandStates.Follow: //spellid=1792 //FOLLOW pet.AttackStop(); pet.InterruptNonMeleeSpells(false); pet.GetMotionMaster().MoveFollow(GetPlayer(), SharedConst.PetFollowDist, pet.GetFollowAngle()); charmInfo.SetCommandState(CommandStates.Follow); charmInfo.SetIsCommandAttack(false); charmInfo.SetIsAtStay(false); charmInfo.SetIsReturning(true); charmInfo.SetIsCommandFollow(true); charmInfo.SetIsFollowing(false); break; case CommandStates.Attack: //spellid=1792 //ATTACK { // Can't attack if owner is pacified if (GetPlayer().HasAuraType(AuraType.ModPacify)) { // @todo Send proper error message to client return; } // only place where pet can be player Unit TargetUnit = Global.ObjAccessor.GetUnit(GetPlayer(), guid2); if (!TargetUnit) { return; } Unit owner = pet.GetOwner(); if (owner) { if (!owner.IsValidAttackTarget(TargetUnit)) { return; } } pet.ClearUnitState(UnitState.Follow); // This is true if pet has no target or has target but targets differs. if (pet.GetVictim() != TargetUnit || (pet.GetVictim() == TargetUnit && !pet.GetCharmInfo().IsCommandAttack())) { if (pet.GetVictim()) { pet.AttackStop(); } if (!pet.IsTypeId(TypeId.Player) && pet.ToCreature().IsAIEnabled) { charmInfo.SetIsCommandAttack(true); charmInfo.SetIsAtStay(false); charmInfo.SetIsFollowing(false); charmInfo.SetIsCommandFollow(false); charmInfo.SetIsReturning(false); pet.ToCreature().GetAI().AttackStart(TargetUnit); //10% chance to play special pet attack talk, else growl if (pet.IsPet() && pet.ToPet().getPetType() == PetType.Summon && pet != TargetUnit && RandomHelper.IRand(0, 100) < 10) { pet.SendPetTalk(PetTalk.Attack); } else { // 90% chance for pet and 100% chance for charmed creature pet.SendPetAIReaction(guid1); } } else // charmed player { if (pet.GetVictim() && pet.GetVictim() != TargetUnit) { pet.AttackStop(); } charmInfo.SetIsCommandAttack(true); charmInfo.SetIsAtStay(false); charmInfo.SetIsFollowing(false); charmInfo.SetIsCommandFollow(false); charmInfo.SetIsReturning(false); pet.Attack(TargetUnit, true); pet.SendPetAIReaction(guid1); } } break; } case CommandStates.Abandon: // abandon (hunter pet) or dismiss (summoned pet) if (pet.GetCharmerGUID() == GetPlayer().GetGUID()) { GetPlayer().StopCastingCharm(); } else if (pet.GetOwnerGUID() == GetPlayer().GetGUID()) { Cypher.Assert(pet.IsTypeId(TypeId.Unit)); if (pet.IsPet()) { if (pet.ToPet().getPetType() == PetType.Hunter) { GetPlayer().RemovePet(pet.ToPet(), PetSaveMode.AsDeleted); } else { //dismissing a summoned pet is like killing them (this prevents returning a soulshard...) pet.setDeathState(DeathState.Corpse); } } else if (pet.HasUnitTypeMask(UnitTypeMask.Minion)) { ((Minion)pet).UnSummon(); } } break; case CommandStates.MoveTo: pet.StopMoving(); pet.GetMotionMaster().Clear(false); pet.GetMotionMaster().MovePoint(0, x, y, z); charmInfo.SetCommandState(CommandStates.MoveTo); charmInfo.SetIsCommandAttack(false); charmInfo.SetIsAtStay(true); charmInfo.SetIsFollowing(false); charmInfo.SetIsReturning(false); charmInfo.SaveStayPosition(); break; default: Log.outError(LogFilter.Network, "WORLD: unknown PET flag Action {0} and spellid {1}.", flag, spellid); break; } break; case ActiveStates.Reaction: // 0x6 switch ((ReactStates)spellid) { case ReactStates.Passive: //passive pet.AttackStop(); goto case ReactStates.Defensive; case ReactStates.Defensive: //recovery case ReactStates.Aggressive: //activete if (pet.IsTypeId(TypeId.Unit)) { pet.ToCreature().SetReactState((ReactStates)spellid); } break; } break; case ActiveStates.Disabled: // 0x81 spell (disabled), ignore case ActiveStates.Passive: // 0x01 case ActiveStates.Enabled: // 0xC1 spell { Unit unit_target = null; if (!guid2.IsEmpty()) { unit_target = Global.ObjAccessor.GetUnit(GetPlayer(), guid2); } // do not cast unknown spells SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellid); if (spellInfo == null) { Log.outError(LogFilter.Network, "WORLD: unknown PET spell id {0}", spellid); return; } foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None)) { if (effect != null && (effect.TargetA.GetTarget() == Targets.UnitSrcAreaEnemy || effect.TargetA.GetTarget() == Targets.UnitDestAreaEnemy || effect.TargetA.GetTarget() == Targets.DestDynobjEnemy)) { return; } } // do not cast not learned spells if (!pet.HasSpell(spellid) || spellInfo.IsPassive()) { return; } // Clear the flags as if owner clicked 'attack'. AI will reset them // after AttackStart, even if spell failed if (pet.GetCharmInfo() != null) { pet.GetCharmInfo().SetIsAtStay(false); pet.GetCharmInfo().SetIsCommandAttack(true); pet.GetCharmInfo().SetIsReturning(false); pet.GetCharmInfo().SetIsFollowing(false); } Spell spell = new Spell(pet, spellInfo, TriggerCastFlags.None); SpellCastResult result = spell.CheckPetCast(unit_target); //auto turn to target unless possessed if (result == SpellCastResult.UnitNotInfront && !pet.isPossessed() && !pet.IsVehicle()) { Unit unit_target2 = spell.m_targets.GetUnitTarget(); if (unit_target) { pet.SetInFront(unit_target); Player player = unit_target.ToPlayer(); if (player) { pet.SendUpdateToPlayer(player); } } else if (unit_target2) { pet.SetInFront(unit_target2); Player player = unit_target2.ToPlayer(); if (player) { pet.SendUpdateToPlayer(player); } } Unit powner = pet.GetCharmerOrOwner(); if (powner) { Player player = powner.ToPlayer(); if (player) { pet.SendUpdateToPlayer(player); } } result = SpellCastResult.SpellCastOk; } if (result == SpellCastResult.SpellCastOk) { unit_target = spell.m_targets.GetUnitTarget(); //10% chance to play special pet attack talk, else growl //actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell if (pet.IsPet() && (pet.ToPet().getPetType() == PetType.Summon) && (pet != unit_target) && (RandomHelper.IRand(0, 100) < 10)) { pet.SendPetTalk(PetTalk.SpecialSpell); } else { pet.SendPetAIReaction(guid1); } if (unit_target && !GetPlayer().IsFriendlyTo(unit_target) && !pet.isPossessed() && !pet.IsVehicle()) { // This is true if pet has no target or has target but targets differs. if (pet.GetVictim() != unit_target) { if (pet.GetVictim()) { pet.AttackStop(); } pet.GetMotionMaster().Clear(); if (pet.ToCreature().IsAIEnabled) { pet.ToCreature().GetAI().AttackStart(unit_target); } } } spell.prepare(spell.m_targets); } else { if (pet.isPossessed() || pet.IsVehicle()) // @todo: confirm this check { Spell.SendCastResult(GetPlayer(), spellInfo, spell.m_SpellVisual, spell.m_castId, result); } else { spell.SendPetCastResult(result); } if (!pet.GetSpellHistory().HasCooldown(spellid)) { pet.GetSpellHistory().ResetCooldown(spellid, true); } spell.finish(false); spell.Dispose(); // reset specific flags in case of spell fail. AI will reset other flags if (pet.GetCharmInfo() != null) { pet.GetCharmInfo().SetIsCommandAttack(false); } } break; } default: Log.outError(LogFilter.Network, "WORLD: unknown PET flag Action {0} and spellid {1}.", flag, spellid); break; } }
public IEnumerator MoveByAction(Action action, float duration) { var path = action?.Path; if (path != null) { associatedUnit.IsMoving = true; associatedUnit.UnitAnimator?.PlayMoveAnimation(); Tile finalTile = null; var pathCount = path.Count; for (int i = 0; i < pathCount; i++) { if (path[i] != null) { finalTile = path[i]; } float counter = 0; if (finalTile != null) { if (path.IndexOf(finalTile) != pathCount - 1) { associatedUnit.MovesLeft -= finalTile.CostToMove; } var startPos = associatedUnit.Transform.position; LookAt(finalTile.WorldPosition); while (counter < duration) { counter += Time.deltaTime; associatedUnit.Transform.position = Vector3.Lerp(startPos, finalTile.WorldPosition, counter / duration); yield return(null); } if (associatedUnit.MovesLeft < 0 && path.IndexOf(finalTile) != pathCount - 1) { i = pathCount; } } } associatedUnit.OnUnitMove.Publish(associatedUnit); associatedUnit.CurrentTile = finalTile; if (associatedUnit.CurrentTile != null) { associatedUnit.Transform.position = associatedUnit.CurrentTile.WorldPosition; } associatedUnit.IsMoving = false; associatedUnit.UnitAnimator?.StopMoveAnimation(); } if (action != null) { if (action.ActionType != ActionType.Nothing) { if (action.ActionType == ActionType.Attack && action.Target != null) { associatedUnit.OnAttack.Publish(associatedUnit); if (associatedUnit.TargetIsInRange(action.Target)) { Harmony.Finder.LevelController.BattleOngoing = true; yield return(associatedUnit.Attack(action.Target)); if (action.Target is Unit) { if (!Harmony.Finder.LevelController.CinematicController.IsPlayingACinematic) { uiController.LaunchBattleReport(associatedUnit.IsEnemy); while (uiController.IsBattleReportActive) { yield return(null); } } } Harmony.Finder.LevelController.BattleOngoing = false; } else { associatedUnit.Rest(); } } else if (action.ActionType == ActionType.Recruit && action.Target != null) { associatedUnit.UnitAnimator?.PlayAttackAnimation(); if (action.Target.GetType() == typeof(Unit) && !associatedUnit.RecruitUnit((Unit)action.Target)) { associatedUnit.Rest(); } associatedUnit.UnitAnimator?.StopAttackAnimation(); } else if (action.ActionType == ActionType.Heal && action.Target != null) { associatedUnit.UnitAnimator?.PlayAttackAnimation(); if (action.Target.GetType() == typeof(Unit) && !associatedUnit.HealUnit((Unit)action.Target)) { associatedUnit.Rest(); } associatedUnit.UnitAnimator?.StopAttackAnimation(); } else { associatedUnit.Rest(); } } } else { associatedUnit.Rest(); } }