Ejemplo n.º 1
0
        void HandlePetCastSpell(PetCastSpell petCastSpell)
        {
            Unit caster = Global.ObjAccessor.GetUnit(GetPlayer(), petCastSpell.PetGUID);

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

            SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(petCastSpell.Cast.SpellID, caster.GetMap().GetDifficultyID());

            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;
            }

            // This opcode is also sent from charmed and possessed units (players and creatures)
            if (caster != GetPlayer().GetGuardianPet() && caster != GetPlayer().GetCharmed())
            {
                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(caster, petCastSpell.Cast);

            Spell spell = new(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.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();
            }
        }
Ejemplo n.º 2
0
        public bool ReGenerate()
        {
            if (m_weatherChances == null)
            {
                m_type  = WeatherType.Fine;
                m_grade = 0.0f;
                return(false);
            }

            // Weather statistics:
            // 30% - no change
            // 30% - weather gets better (if not fine) or change weather type
            // 30% - weather worsens (if not fine)
            // 10% - radical change (if not fine)
            uint u = RandomHelper.URand(0, 99);

            if (u < 30)
            {
                return(false);
            }

            // remember old values
            WeatherType old_type  = m_type;
            float       old_grade = m_grade;

            long gtime  = Global.WorldMgr.GetGameTime();
            var  ltime  = Time.UnixTimeToDateTime(gtime).ToLocalTime();
            uint season = (uint)((ltime.DayOfYear - 78 + 365) / 91) % 4;

            string[] seasonName = { "spring", "summer", "fall", "winter" };

            Log.outError(LogFilter.Server, "Generating a change in {0} weather for zone {1}.", seasonName[season], m_zone);

            if ((u < 60) && (m_grade < 0.33333334f))                // Get fair
            {
                m_type  = WeatherType.Fine;
                m_grade = 0.0f;
            }

            if ((u < 60) && (m_type != WeatherType.Fine))          // Get better
            {
                m_grade -= 0.33333334f;
                return(true);
            }

            if ((u < 90) && (m_type != WeatherType.Fine))          // Get worse
            {
                m_grade += 0.33333334f;
                return(true);
            }

            if (m_type != WeatherType.Fine)
            {
                // Radical change:
                // if light . heavy
                // if medium . change weather type
                // if heavy . 50% light, 50% change weather type

                if (m_grade < 0.33333334f)
                {
                    m_grade = 0.9999f;                              // go nuts
                    return(true);
                }
                else
                {
                    if (m_grade > 0.6666667f)
                    {
                        // Severe change, but how severe?
                        uint rnd = RandomHelper.URand(0, 99);
                        if (rnd < 50)
                        {
                            m_grade -= 0.6666667f;
                            return(true);
                        }
                    }
                    m_type  = WeatherType.Fine;                    // clear up
                    m_grade = 0;
                }
            }

            // At this point, only weather that isn't doing anything remains but that have weather data
            uint chance1 = m_weatherChances.data[season].rainChance;
            uint chance2 = chance1 + m_weatherChances.data[season].snowChance;
            uint chance3 = chance2 + m_weatherChances.data[season].stormChance;
            uint rn      = RandomHelper.URand(1, 100);

            if (rn <= chance1)
            {
                m_type = WeatherType.Rain;
            }
            else if (rn <= chance2)
            {
                m_type = WeatherType.Snow;
            }
            else if (rn <= chance3)
            {
                m_type = WeatherType.Storm;
            }
            else
            {
                m_type = WeatherType.Fine;
            }

            // New weather statistics (if not fine):
            // 85% light
            // 7% medium
            // 7% heavy
            // If fine 100% sun (no fog)

            if (m_type == WeatherType.Fine)
            {
                m_grade = 0.0f;
            }
            else if (u < 90)
            {
                m_grade = (float)RandomHelper.NextDouble() * 0.3333f;
            }
            else
            {
                // Severe change, but how severe?
                rn = RandomHelper.URand(0, 99);
                if (rn < 50)
                {
                    m_grade = (float)RandomHelper.NextDouble() * 0.3333f + 0.3334f;
                }
                else
                {
                    m_grade = (float)RandomHelper.NextDouble() * 0.3333f + 0.6667f;
                }
            }

            // return true only in case weather changes
            return(m_type != old_type || m_grade != old_grade);
        }
Ejemplo n.º 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.GetMotionMaster().Clear(MovementGeneratorPriority.Normal);
                    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;
                        }
                    }

                    // This is true if pet has no target or has target but targets differs.
                    if (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);

                            CreatureAI AI = pet.ToCreature().GetAI();
                            if (AI is PetAI)
                            {
                                ((PetAI)AI)._AttackStart(TargetUnit);         // force target switch
                            }
                            else
                            {
                                AI.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
                        {
                            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();
                    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, pet.GetMap().GetDifficultyID());
                if (spellInfo == null)
                {
                    Log.outError(LogFilter.Network, "WORLD: unknown PET spell id {0}", spellid);
                    return;
                }

                foreach (var spellEffectInfo in spellInfo.GetEffects())
                {
                    if (spellEffectInfo.TargetA.GetTarget() == Targets.UnitSrcAreaEnemy || spellEffectInfo.TargetA.GetTarget() == Targets.UnitDestAreaEnemy || spellEffectInfo.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(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)
                    {
                        if (!pet.IsFocusing())
                        {
                            pet.SetInFront(unit_target);
                        }
                        Player player = unit_target.ToPlayer();
                        if (player)
                        {
                            pet.SendUpdateToPlayer(player);
                        }
                    }
                    else if (unit_target2)
                    {
                        if (!pet.IsFocusing())
                        {
                            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)
                        {
                            CreatureAI ai = pet.ToCreature().GetAI();
                            if (ai != null)
                            {
                                PetAI petAI = (PetAI)ai;
                                if (petAI != null)
                                {
                                    petAI._AttackStart(unit_target);     // force victim switch
                                }
                                else
                                {
                                    ai.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;
            }
        }