Beispiel #1
0
        void HandlePetSetAction(PetSetAction packet)
        {
            ObjectGuid petguid = packet.PetGUID;
            Unit       pet     = Global.ObjAccessor.GetUnit(GetPlayer(), petguid);

            if (!pet || pet != GetPlayer().GetFirstControlled())
            {
                Log.outError(LogFilter.Network, "HandlePetSetAction: Unknown {0} or pet owner {1}", petguid.ToString(), GetPlayer().GetGUID().ToString());
                return;
            }

            CharmInfo charmInfo = pet.GetCharmInfo();

            if (charmInfo == null)
            {
                Log.outError(LogFilter.Network, "WorldSession.HandlePetSetAction: {0} is considered pet-like but doesn't have a charminfo!", pet.GetGUID().ToString());
                return;
            }

            uint position   = packet.Index;
            uint actionData = packet.Action;

            uint         spell_id  = UnitActionBarEntry.UNIT_ACTION_BUTTON_ACTION(actionData);
            ActiveStates act_state = (ActiveStates)UnitActionBarEntry.UNIT_ACTION_BUTTON_TYPE(actionData);

            Log.outDebug(LogFilter.Network, "Player {0} has changed pet spell action. Position: {1}, Spell: {2}, State: {3}", GetPlayer().GetName(), position, spell_id, act_state);


            //if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add
            if (!((act_state == ActiveStates.Enabled || act_state == ActiveStates.Disabled || act_state == ActiveStates.Passive) && spell_id != 0 && !pet.HasSpell(spell_id)))
            {
                SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell_id);
                if (spellInfo != null)
                {
                    //sign for autocast
                    if (act_state == ActiveStates.Enabled)
                    {
                        if (pet.GetTypeId() == TypeId.Unit && pet.IsPet())
                        {
                            ((Pet)pet).ToggleAutocast(spellInfo, true);
                        }
                        else
                        {
                            foreach (var unit in GetPlayer().m_Controlled)
                            {
                                if (unit.GetEntry() == pet.GetEntry())
                                {
                                    unit.GetCharmInfo().ToggleCreatureAutocast(spellInfo, true);
                                }
                            }
                        }
                    }
                    //sign for no/turn off autocast
                    else if (act_state == ActiveStates.Disabled)
                    {
                        if (pet.GetTypeId() == TypeId.Unit && pet.IsPet())
                        {
                            pet.ToPet().ToggleAutocast(spellInfo, false);
                        }
                        else
                        {
                            foreach (var unit in GetPlayer().m_Controlled)
                            {
                                if (unit.GetEntry() == pet.GetEntry())
                                {
                                    unit.GetCharmInfo().ToggleCreatureAutocast(spellInfo, false);
                                }
                            }
                        }
                    }
                }

                charmInfo.SetActionBar((byte)position, spell_id, act_state);
            }
        }
        void HandleMovementOpcode(ClientOpcodes opcode, MovementInfo movementInfo)
        {
            Unit   mover    = GetPlayer().m_unitMovedByMe;
            Player plrMover = mover.ToPlayer();

            if (plrMover && plrMover.IsBeingTeleported())
            {
                return;
            }

            GetPlayer().ValidateMovementInfo(movementInfo);

            if (movementInfo.Guid != mover.GetGUID())
            {
                Log.outError(LogFilter.Network, "HandleMovementOpcodes: guid error");
                return;
            }
            if (!movementInfo.Pos.IsPositionValid())
            {
                Log.outError(LogFilter.Network, "HandleMovementOpcodes: Invalid Position");
                return;
            }

            // stop some emotes at player move
            if (plrMover && (plrMover.GetEmoteState() != 0))
            {
                plrMover.SetEmoteState(Emote.OneshotNone);
            }

            //handle special cases
            if (!movementInfo.transport.guid.IsEmpty())
            {
                // We were teleported, skip packets that were broadcast before teleport
                if (movementInfo.Pos.GetExactDist2d(mover) > MapConst.SizeofGrids)
                {
                    return;
                }

                if (Math.Abs(movementInfo.transport.pos.GetPositionX()) > 75f || Math.Abs(movementInfo.transport.pos.GetPositionY()) > 75f || Math.Abs(movementInfo.transport.pos.GetPositionZ()) > 75f)
                {
                    return;
                }

                if (!GridDefines.IsValidMapCoord(movementInfo.Pos.posX + movementInfo.transport.pos.posX, movementInfo.Pos.posY + movementInfo.transport.pos.posY,
                                                 movementInfo.Pos.posZ + movementInfo.transport.pos.posZ, movementInfo.Pos.Orientation + movementInfo.transport.pos.Orientation))
                {
                    return;
                }

                if (plrMover)
                {
                    if (!plrMover.GetTransport())
                    {
                        Transport transport = plrMover.GetMap().GetTransport(movementInfo.transport.guid);
                        if (transport)
                        {
                            transport.AddPassenger(plrMover);
                        }
                    }
                    else if (plrMover.GetTransport().GetGUID() != movementInfo.transport.guid)
                    {
                        plrMover.GetTransport().RemovePassenger(plrMover);
                        Transport transport = plrMover.GetMap().GetTransport(movementInfo.transport.guid);
                        if (transport)
                        {
                            transport.AddPassenger(plrMover);
                        }
                        else
                        {
                            movementInfo.ResetTransport();
                        }
                    }
                }

                if (!mover.GetTransport() && !mover.GetVehicle())
                {
                    GameObject go = mover.GetMap().GetGameObject(movementInfo.transport.guid);
                    if (!go || go.GetGoType() != GameObjectTypes.Transport)
                    {
                        movementInfo.transport.Reset();
                    }
                }
            }
            else if (plrMover && plrMover.GetTransport())                // if we were on a transport, leave
            {
                plrMover.GetTransport().RemovePassenger(plrMover);
            }

            // fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map).
            if (opcode == ClientOpcodes.MoveFallLand && plrMover && !plrMover.IsInFlight())
            {
                plrMover.HandleFall(movementInfo);
            }

            // interrupt parachutes upon falling or landing in water
            if (opcode == ClientOpcodes.MoveFallLand || opcode == ClientOpcodes.MoveStartSwim || opcode == ClientOpcodes.MoveSetFly)
            {
                mover.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.LandingOrFlight); // Parachutes
            }
            uint mstime = GameTime.GetGameTimeMS();

            if (m_clientTimeDelay == 0)
            {
                m_clientTimeDelay = mstime - movementInfo.Time;
            }

            movementInfo.Time = movementInfo.Time + m_clientTimeDelay;

            movementInfo.Guid    = mover.GetGUID();
            mover.m_movementInfo = movementInfo;

            // Some vehicles allow the passenger to turn by himself
            Vehicle vehicle = mover.GetVehicle();

            if (vehicle)
            {
                VehicleSeatRecord seat = vehicle.GetSeatForPassenger(mover);
                if (seat != null)
                {
                    if (seat.HasFlag(VehicleSeatFlags.AllowTurning))
                    {
                        if (movementInfo.Pos.GetOrientation() != mover.GetOrientation())
                        {
                            mover.SetOrientation(movementInfo.Pos.GetOrientation());
                            mover.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Turning);
                        }
                    }
                }
                return;
            }

            mover.UpdatePosition(movementInfo.Pos);

            MoveUpdate moveUpdate = new();

            moveUpdate.Status = mover.m_movementInfo;
            mover.SendMessageToSet(moveUpdate, GetPlayer());

            if (plrMover)                                            // nothing is charmed, or player charmed
            {
                if (plrMover.IsSitState() && movementInfo.HasMovementFlag(MovementFlag.MaskMoving | MovementFlag.MaskTurning))
                {
                    plrMover.SetStandState(UnitStandStateType.Stand);
                }

                plrMover.UpdateFallInformationIfNeed(movementInfo, opcode);

                if (movementInfo.Pos.posZ < plrMover.GetMap().GetMinHeight(plrMover.GetPhaseShift(), movementInfo.Pos.GetPositionX(), movementInfo.Pos.GetPositionY()))
                {
                    if (!(plrMover.GetBattleground() && plrMover.GetBattleground().HandlePlayerUnderMap(GetPlayer())))
                    {
                        // NOTE: this is actually called many times while falling
                        // even after the player has been teleported away
                        // @todo discard movement packets after the player is rooted
                        if (plrMover.IsAlive())
                        {
                            plrMover.AddPlayerFlag(PlayerFlags.IsOutOfBounds);
                            plrMover.EnvironmentalDamage(EnviromentalDamage.FallToVoid, (uint)GetPlayer().GetMaxHealth());
                            // player can be alive if GM/etc
                            // change the death state to CORPSE to prevent the death timer from
                            // starting in the next player update
                            if (plrMover.IsAlive())
                            {
                                plrMover.KillPlayer();
                            }
                        }
                    }
                }
                else
                {
                    plrMover.RemovePlayerFlag(PlayerFlags.IsOutOfBounds);
                }

                if (opcode == ClientOpcodes.MoveJump)
                {
                    plrMover.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2.Jump); // Mind Control
                    Unit.ProcSkillsAndAuras(plrMover, null, ProcFlags.Jump, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null);
                }
            }
        }
Beispiel #3
0
        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;
            }
        }