Esempio n. 1
0
        void HandleCastSpell(CastSpell cast)
        {
            // ignore for remote control state (for player case)
            Unit mover = GetPlayer().m_unitMovedByMe;

            if (mover != GetPlayer() && mover.IsTypeId(TypeId.Player))
            {
                return;
            }

            SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(cast.Cast.SpellID, mover.GetMap().GetDifficultyID());

            if (spellInfo == null)
            {
                Log.outError(LogFilter.Network, "WORLD: unknown spell id {0}", cast.Cast.SpellID);
                return;
            }

            if (spellInfo.IsPassive())
            {
                return;
            }

            Unit caster = mover;

            if (caster.IsTypeId(TypeId.Unit) && !caster.ToCreature().HasSpell(spellInfo.Id))
            {
                // If the vehicle creature does not have the spell but it allows the passenger to cast own spells
                // change caster to player and let him cast
                if (!GetPlayer().IsOnVehicle(caster) || spellInfo.CheckVehicle(GetPlayer()) != SpellCastResult.SpellCastOk)
                {
                    return;
                }

                caster = GetPlayer();
            }

            // check known spell or raid marker spell (which not requires player to know it)
            if (caster.IsTypeId(TypeId.Player) && !caster.ToPlayer().HasActiveSpell(spellInfo.Id) && !spellInfo.HasEffect(SpellEffectName.ChangeRaidMarker) && !spellInfo.HasAttribute(SpellAttr8.RaidMarker))
            {
                return;
            }

            // Check possible spell cast overrides
            spellInfo = caster.GetCastSpellInfo(spellInfo);

            // Client is resending autoshot cast opcode when other spell is casted during shoot rotation
            // Skip it to prevent "interrupt" message
            if (spellInfo.IsAutoRepeatRangedSpell() && GetPlayer().GetCurrentSpell(CurrentSpellTypes.AutoRepeat) != null &&
                GetPlayer().GetCurrentSpell(CurrentSpellTypes.AutoRepeat).m_spellInfo == spellInfo)
            {
                return;
            }

            // can't use our own spells when we're in possession of another unit,
            if (GetPlayer().IsPossessing())
            {
                return;
            }

            // client provided targets
            SpellCastTargets targets = new(caster, cast.Cast);

            // auto-selection buff level base at target level (in spellInfo)
            if (targets.GetUnitTarget() != null)
            {
                SpellInfo actualSpellInfo = spellInfo.GetAuraRankForLevel(targets.GetUnitTarget().GetLevelForTarget(caster));

                // if rank not found then function return NULL but in explicit cast case original spell can be casted and later failed with appropriate error message
                if (actualSpellInfo != null)
                {
                    spellInfo = actualSpellInfo;
                }
            }

            if (cast.Cast.MoveUpdate.HasValue)
            {
                HandleMovementOpcode(ClientOpcodes.MoveStop, cast.Cast.MoveUpdate.Value);
            }

            Spell spell = new(caster, spellInfo, TriggerCastFlags.None, ObjectGuid.Empty, false);

            SpellPrepare spellPrepare = new();

            spellPrepare.ClientCastID = cast.Cast.CastID;
            spellPrepare.ServerCastID = spell.m_castId;
            SendPacket(spellPrepare);

            spell.m_fromClient = true;
            spell.m_misc.Data0 = cast.Cast.Misc[0];
            spell.m_misc.Data1 = cast.Cast.Misc[1];
            spell.Prepare(targets);
        }
Esempio n. 2
0
        void HandleUseItem(UseItem packet)
        {
            Player user = GetPlayer();

            // ignore for remote control state
            if (user.m_unitMovedByMe != user)
            {
                return;
            }

            Item item = user.GetUseableItemByPos(packet.PackSlot, packet.Slot);

            if (item == null)
            {
                user.SendEquipError(InventoryResult.ItemNotFound);
                return;
            }

            if (item.GetGUID() != packet.CastItem)
            {
                user.SendEquipError(InventoryResult.ItemNotFound);
                return;
            }

            ItemTemplate proto = item.GetTemplate();

            if (proto == null)
            {
                user.SendEquipError(InventoryResult.ItemNotFound, item);
                return;
            }

            // some item classes can be used only in equipped state
            if (proto.GetInventoryType() != InventoryType.NonEquip && !item.IsEquipped())
            {
                user.SendEquipError(InventoryResult.ItemNotFound, item);
                return;
            }

            InventoryResult msg = user.CanUseItem(item);

            if (msg != InventoryResult.Ok)
            {
                user.SendEquipError(msg, item);
                return;
            }

            // only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB)
            if (proto.GetClass() == ItemClass.Consumable && !proto.GetFlags().HasAnyFlag(ItemFlags.IgnoreDefaultArenaRestrictions) && user.InArena())
            {
                user.SendEquipError(InventoryResult.NotDuringArenaMatch, item);
                return;
            }

            // don't allow items banned in arena
            if (proto.GetFlags().HasAnyFlag(ItemFlags.NotUseableInArena) && user.InArena())
            {
                user.SendEquipError(InventoryResult.NotDuringArenaMatch, item);
                return;
            }

            if (user.IsInCombat())
            {
                foreach (ItemEffectRecord effect in item.GetEffects())
                {
                    SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)effect.SpellID, user.GetMap().GetDifficultyID());
                    if (spellInfo != null)
                    {
                        if (!spellInfo.CanBeUsedInCombat())
                        {
                            user.SendEquipError(InventoryResult.NotInCombat, item);
                            return;
                        }
                    }
                }
            }

            // check also  BIND_WHEN_PICKED_UP and BIND_QUEST_ITEM for .additem or .additemset case by GM (not binded at adding to inventory)
            if (item.GetBonding() == ItemBondingType.OnUse || item.GetBonding() == ItemBondingType.OnAcquire || item.GetBonding() == ItemBondingType.Quest)
            {
                if (!item.IsSoulBound())
                {
                    item.SetState(ItemUpdateState.Changed, user);
                    item.SetBinding(true);
                    GetCollectionMgr().AddItemAppearance(item);
                }
            }

            SpellCastTargets targets = new(user, packet.Cast);

            // Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state.
            if (!Global.ScriptMgr.OnItemUse(user, item, targets, packet.Cast.CastID))
            {
                // no script or script not process request by self
                user.CastItemUseSpell(item, targets, packet.Cast.CastID, packet.Cast.Misc);
            }
        }
Esempio n. 3
0
        void HandleAcceptTrade(AcceptTrade acceptTrade)
        {
            TradeData my_trade = GetPlayer().GetTradeData();

            if (my_trade == null)
            {
                return;
            }

            Player trader = my_trade.GetTrader();

            TradeData his_trade = trader.GetTradeData();

            if (his_trade == null)
            {
                return;
            }

            Item[] myItems  = new Item[(int)TradeSlots.Count];
            Item[] hisItems = new Item[(int)TradeSlots.Count];

            // set before checks for propertly undo at problems (it already set in to client)
            my_trade.SetAccepted(true);

            TradeStatusPkt info = new TradeStatusPkt();

            if (his_trade.GetServerStateIndex() != acceptTrade.StateIndex)
            {
                info.Status = TradeStatus.StateChanged;
                SendTradeStatus(info);
                my_trade.SetAccepted(false);
                return;
            }

            if (!GetPlayer().IsWithinDistInMap(trader, 11.11f, false))
            {
                info.Status = TradeStatus.TooFarAway;
                SendTradeStatus(info);
                my_trade.SetAccepted(false);
                return;
            }

            // not accept case incorrect money amount
            if (!GetPlayer().HasEnoughMoney(my_trade.GetMoney()))
            {
                info.Status    = TradeStatus.Failed;
                info.BagResult = InventoryResult.NotEnoughMoney;
                SendTradeStatus(info);
                my_trade.SetAccepted(false, true);
                return;
            }

            // not accept case incorrect money amount
            if (!trader.HasEnoughMoney(his_trade.GetMoney()))
            {
                info.Status    = TradeStatus.Failed;
                info.BagResult = InventoryResult.NotEnoughMoney;
                trader.GetSession().SendTradeStatus(info);
                his_trade.SetAccepted(false, true);
                return;
            }

            if (GetPlayer().GetMoney() >= PlayerConst.MaxMoneyAmount - his_trade.GetMoney())
            {
                info.Status    = TradeStatus.Failed;
                info.BagResult = InventoryResult.TooMuchGold;
                SendTradeStatus(info);
                my_trade.SetAccepted(false, true);
                return;
            }

            if (trader.GetMoney() >= PlayerConst.MaxMoneyAmount - my_trade.GetMoney())
            {
                info.Status    = TradeStatus.Failed;
                info.BagResult = InventoryResult.TooMuchGold;
                trader.GetSession().SendTradeStatus(info);
                his_trade.SetAccepted(false, true);
                return;
            }

            // not accept if some items now can't be trade (cheating)
            for (byte i = 0; i < (byte)TradeSlots.Count; ++i)
            {
                Item item = my_trade.GetItem((TradeSlots)i);
                if (item)
                {
                    if (!item.CanBeTraded(false, true))
                    {
                        info.Status = TradeStatus.Cancelled;
                        SendTradeStatus(info);
                        return;
                    }

                    if (item.IsBindedNotWith(trader))
                    {
                        info.Status    = TradeStatus.Failed;
                        info.BagResult = InventoryResult.TradeBoundItem;
                        SendTradeStatus(info);
                        return;
                    }
                }
                item = his_trade.GetItem((TradeSlots)i);
                if (item)
                {
                    if (!item.CanBeTraded(false, true))
                    {
                        info.Status = TradeStatus.Cancelled;
                        SendTradeStatus(info);
                        return;
                    }
                }
            }

            if (his_trade.IsAccepted())
            {
                SetAcceptTradeMode(my_trade, his_trade, myItems, hisItems);

                Spell            my_spell   = null;
                SpellCastTargets my_targets = new SpellCastTargets();

                Spell            his_spell   = null;
                SpellCastTargets his_targets = new SpellCastTargets();

                // not accept if spell can't be casted now (cheating)
                uint my_spell_id = my_trade.GetSpell();
                if (my_spell_id != 0)
                {
                    SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(my_spell_id, _player.GetMap().GetDifficultyID());
                    Item      castItem   = my_trade.GetSpellCastItem();

                    if (spellEntry == null || !his_trade.GetItem(TradeSlots.NonTraded) ||
                        (my_trade.HasSpellCastItem() && !castItem))
                    {
                        ClearAcceptTradeMode(my_trade, his_trade);
                        ClearAcceptTradeMode(myItems, hisItems);

                        my_trade.SetSpell(0);
                        return;
                    }

                    my_spell            = new Spell(GetPlayer(), spellEntry, TriggerCastFlags.FullMask);
                    my_spell.m_CastItem = castItem;
                    my_targets.SetTradeItemTarget(GetPlayer());
                    my_spell.m_targets = my_targets;

                    SpellCastResult res = my_spell.CheckCast(true);
                    if (res != SpellCastResult.SpellCastOk)
                    {
                        my_spell.SendCastResult(res);

                        ClearAcceptTradeMode(my_trade, his_trade);
                        ClearAcceptTradeMode(myItems, hisItems);

                        my_spell.Dispose();
                        my_trade.SetSpell(0);
                        return;
                    }
                }

                // not accept if spell can't be casted now (cheating)
                uint his_spell_id = his_trade.GetSpell();
                if (his_spell_id != 0)
                {
                    SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(his_spell_id, trader.GetMap().GetDifficultyID());
                    Item      castItem   = his_trade.GetSpellCastItem();

                    if (spellEntry == null || !my_trade.GetItem(TradeSlots.NonTraded) || (his_trade.HasSpellCastItem() && !castItem))
                    {
                        his_trade.SetSpell(0);

                        ClearAcceptTradeMode(my_trade, his_trade);
                        ClearAcceptTradeMode(myItems, hisItems);
                        return;
                    }

                    his_spell            = new Spell(trader, spellEntry, TriggerCastFlags.FullMask);
                    his_spell.m_CastItem = castItem;
                    his_targets.SetTradeItemTarget(trader);
                    his_spell.m_targets = his_targets;

                    SpellCastResult res = his_spell.CheckCast(true);
                    if (res != SpellCastResult.SpellCastOk)
                    {
                        his_spell.SendCastResult(res);

                        ClearAcceptTradeMode(my_trade, his_trade);
                        ClearAcceptTradeMode(myItems, hisItems);

                        my_spell.Dispose();
                        his_spell.Dispose();

                        his_trade.SetSpell(0);
                        return;
                    }
                }

                // inform partner client
                info.Status = TradeStatus.Accepted;
                trader.GetSession().SendTradeStatus(info);

                // test if item will fit in each inventory
                TradeStatusPkt myCanCompleteInfo  = new TradeStatusPkt();
                TradeStatusPkt hisCanCompleteInfo = new TradeStatusPkt();
                hisCanCompleteInfo.BagResult = trader.CanStoreItems(myItems, (int)TradeSlots.TradedCount, ref hisCanCompleteInfo.ItemID);
                myCanCompleteInfo.BagResult  = GetPlayer().CanStoreItems(hisItems, (int)TradeSlots.TradedCount, ref myCanCompleteInfo.ItemID);

                ClearAcceptTradeMode(myItems, hisItems);

                // in case of missing space report error
                if (myCanCompleteInfo.BagResult != InventoryResult.Ok)
                {
                    ClearAcceptTradeMode(my_trade, his_trade);

                    myCanCompleteInfo.Status = TradeStatus.Failed;
                    trader.GetSession().SendTradeStatus(myCanCompleteInfo);
                    myCanCompleteInfo.FailureForYou = true;
                    SendTradeStatus(myCanCompleteInfo);
                    my_trade.SetAccepted(false);
                    his_trade.SetAccepted(false);
                    return;
                }
                else if (hisCanCompleteInfo.BagResult != InventoryResult.Ok)
                {
                    ClearAcceptTradeMode(my_trade, his_trade);

                    hisCanCompleteInfo.Status = TradeStatus.Failed;
                    SendTradeStatus(hisCanCompleteInfo);
                    hisCanCompleteInfo.FailureForYou = true;
                    trader.GetSession().SendTradeStatus(hisCanCompleteInfo);
                    my_trade.SetAccepted(false);
                    his_trade.SetAccepted(false);
                    return;
                }

                // execute trade: 1. remove
                for (byte i = 0; i < (int)TradeSlots.TradedCount; ++i)
                {
                    if (myItems[i])
                    {
                        myItems[i].SetGiftCreator(GetPlayer().GetGUID());
                        GetPlayer().MoveItemFromInventory(myItems[i].GetBagSlot(), myItems[i].GetSlot(), true);
                    }
                    if (hisItems[i])
                    {
                        hisItems[i].SetGiftCreator(trader.GetGUID());
                        trader.MoveItemFromInventory(hisItems[i].GetBagSlot(), hisItems[i].GetSlot(), true);
                    }
                }

                // execute trade: 2. store
                MoveItems(myItems, hisItems);

                // logging money
                if (HasPermission(RBACPermissions.LogGmTrade))
                {
                    if (my_trade.GetMoney() > 0)
                    {
                        Log.outCommand(GetPlayer().GetSession().GetAccountId(), "GM {0} (Account: {1}) give money (Amount: {2}) to player: {3} (Account: {4})",
                                       GetPlayer().GetName(), GetPlayer().GetSession().GetAccountId(), my_trade.GetMoney(), trader.GetName(), trader.GetSession().GetAccountId());
                    }

                    if (his_trade.GetMoney() > 0)
                    {
                        Log.outCommand(GetPlayer().GetSession().GetAccountId(), "GM {0} (Account: {1}) give money (Amount: {2}) to player: {3} (Account: {4})",
                                       trader.GetName(), trader.GetSession().GetAccountId(), his_trade.GetMoney(), GetPlayer().GetName(), GetPlayer().GetSession().GetAccountId());
                    }
                }


                // update money
                GetPlayer().ModifyMoney(-(long)my_trade.GetMoney());
                GetPlayer().ModifyMoney((long)his_trade.GetMoney());
                trader.ModifyMoney(-(long)his_trade.GetMoney());
                trader.ModifyMoney((long)my_trade.GetMoney());

                if (my_spell)
                {
                    my_spell.Prepare(my_targets);
                }

                if (his_spell)
                {
                    his_spell.Prepare(his_targets);
                }

                // cleanup
                ClearAcceptTradeMode(my_trade, his_trade);
                GetPlayer().SetTradeData(null);
                trader.SetTradeData(null);

                // desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards)
                SQLTransaction trans = new SQLTransaction();
                GetPlayer().SaveInventoryAndGoldToDB(trans);
                trader.SaveInventoryAndGoldToDB(trans);
                DB.Characters.CommitTransaction(trans);

                info.Status = TradeStatus.Complete;
                trader.GetSession().SendTradeStatus(info);
                SendTradeStatus(info);
            }
            else
            {
                info.Status = TradeStatus.Accepted;
                trader.GetSession().SendTradeStatus(info);
            }
        }
Esempio n. 4
0
        void HandlePetCastSpell(PetCastSpell petCastSpell)
        {
            SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(petCastSpell.Cast.SpellID);

            if (spellInfo == null)
            {
                Log.outError(LogFilter.Network, "WorldSession.HandlePetCastSpell: unknown spell id {0} tried to cast by {1}", petCastSpell.Cast.SpellID, petCastSpell.PetGUID.ToString());
                return;
            }

            Unit caster = Global.ObjAccessor.GetUnit(GetPlayer(), petCastSpell.PetGUID);

            if (!caster)
            {
                Log.outError(LogFilter.Network, "WorldSession.HandlePetCastSpell: Caster {0} not found.", petCastSpell.PetGUID.ToString());
                return;
            }

            // This opcode is also sent from charmed and possessed units (players and creatures)
            if (caster != GetPlayer().GetGuardianPet() && caster != GetPlayer().GetCharm())
            {
                Log.outError(LogFilter.Network, "WorldSession.HandlePetCastSpell: {0} isn't pet of player {1} ({2}).", petCastSpell.PetGUID.ToString(), GetPlayer().GetName(), GetPlayer().GetGUID().ToString());
                return;
            }

            // do not cast not learned spells
            if (!caster.HasSpell(spellInfo.Id) || spellInfo.IsPassive())
            {
                return;
            }

            SpellCastTargets targets = new SpellCastTargets(caster, petCastSpell.Cast);

            caster.ClearUnitState(UnitState.Follow);

            Spell spell = new Spell(caster, spellInfo, TriggerCastFlags.None);

            spell.m_fromClient = true;
            spell.m_misc.Data0 = petCastSpell.Cast.Misc[0];
            spell.m_misc.Data1 = petCastSpell.Cast.Misc[1];
            spell.m_targets    = targets;

            SpellCastResult result = spell.CheckPetCast(null);

            if (result == SpellCastResult.SpellCastOk)
            {
                Creature creature = caster.ToCreature();
                if (creature)
                {
                    Pet pet = creature.ToPet();
                    if (pet)
                    {
                        // 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.getPetType() == PetType.Summon && (RandomHelper.IRand(0, 100) < 10))
                        {
                            pet.SendPetTalk(PetTalk.SpecialSpell);
                        }
                        else
                        {
                            pet.SendPetAIReaction(petCastSpell.PetGUID);
                        }
                    }
                }

                SpellPrepare spellPrepare = new SpellPrepare();
                spellPrepare.ClientCastID = petCastSpell.Cast.CastID;
                spellPrepare.ServerCastID = spell.m_castId;
                SendPacket(spellPrepare);

                spell.prepare(targets);
            }
            else
            {
                spell.SendPetCastResult(result);

                if (!caster.GetSpellHistory().HasCooldown(spellInfo.Id))
                {
                    caster.GetSpellHistory().ResetCooldown(spellInfo.Id, true);
                }

                spell.finish(false);
                spell.Dispose();
            }
        }
Esempio n. 5
0
        void HandlePetAction(PetAction packet)
        {
            ObjectGuid guid1 = packet.PetGUID;         //pet guid
            ObjectGuid guid2 = packet.TargetGUID;      //tag guid

            uint         spellid = UnitActionBarEntry.UNIT_ACTION_BUTTON_ACTION(packet.Action);
            ActiveStates flag    = (ActiveStates)UnitActionBarEntry.UNIT_ACTION_BUTTON_TYPE(packet.Action);          //delete = 0x07 CastSpell = C1

            // used also for charmed creature
            Unit pet = Global.ObjAccessor.GetUnit(GetPlayer(), guid1);

            if (!pet)
            {
                Log.outError(LogFilter.Network, "HandlePetAction: {0} doesn't exist for {1}", guid1.ToString(), GetPlayer().GetGUID().ToString());
                return;
            }

            if (pet != GetPlayer().GetFirstControlled())
            {
                Log.outError(LogFilter.Network, "HandlePetAction: {0} does not belong to {1}", guid1.ToString(), GetPlayer().GetGUID().ToString());
                return;
            }

            if (!pet.IsAlive())
            {
                SpellInfo spell = (flag == ActiveStates.Enabled || flag == ActiveStates.Passive) ? Global.SpellMgr.GetSpellInfo(spellid) : null;
                if (spell == null)
                {
                    return;
                }
                if (!spell.HasAttribute(SpellAttr0.CastableWhileDead))
                {
                    return;
                }
            }

            // @todo allow control charmed player?
            if (pet.IsTypeId(TypeId.Player) && !(flag == ActiveStates.Command && spellid == (uint)CommandStates.Attack))
            {
                return;
            }

            if (GetPlayer().m_Controlled.Count == 1)
            {
                HandlePetActionHelper(pet, guid1, spellid, flag, guid2, packet.ActionPosition.X, packet.ActionPosition.Y, packet.ActionPosition.Z);
            }
            else
            {
                //If a pet is dismissed, m_Controlled will change
                List <Unit> controlled = new List <Unit>();
                foreach (var unit in GetPlayer().m_Controlled)
                {
                    if (unit.GetEntry() == pet.GetEntry() && unit.IsAlive())
                    {
                        controlled.Add(unit);
                    }
                }

                foreach (var unit in controlled)
                {
                    HandlePetActionHelper(unit, guid1, spellid, flag, guid2, packet.ActionPosition.X, packet.ActionPosition.Y, packet.ActionPosition.Z);
                }
            }
        }
Esempio n. 6
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);
            }
        }
Esempio n. 7
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;
            }
        }