diff options
Diffstat (limited to 'src/game/PetHandler.cpp')
| -rw-r--r-- | src/game/PetHandler.cpp | 265 | 
1 files changed, 185 insertions, 80 deletions
diff --git a/src/game/PetHandler.cpp b/src/game/PetHandler.cpp index 05c889b8cf9..17c2ba4275b 100644 --- a/src/game/PetHandler.cpp +++ b/src/game/PetHandler.cpp @@ -1,7 +1,7 @@  /* - * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/> + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>   * - * Copyright (C) 2008 Trinity <http://www.trinitycore.org/> + * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License as published by @@ -106,7 +106,7 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )                      }                      // only place where pet can be player                      pet->clearUnitState(UNIT_STAT_FOLLOW); -                    uint64 selguid = _player->GetSelection(); +                    const uint64& selguid = _player->GetSelection();                      Unit *TargetUnit = ObjectAccessor::GetUnit(*_player, selguid);                      if(!TargetUnit)                          return; @@ -118,27 +118,35 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )                      //if(!pet->IsWithinLOSInMap(TargetUnit))                      //    return; -                    if(pet->GetTypeId() != TYPEID_PLAYER) +                    // This is true if pet has no target or has target but targets differs. +                    if(pet->getVictim() != TargetUnit)                      { -                        if (((Creature*)pet)->AI()) -                            ((Creature*)pet)->AI()->AttackStart(TargetUnit); +                        if (pet->getVictim()) +                            pet->AttackStop(); -                        //10% chance to play special pet attack talk, else growl -                        if(((Creature*)pet)->isPet() && ((Pet*)pet)->getPetType() == SUMMON_PET && pet != TargetUnit && urand(0, 100) < 10) -                            pet->SendPetTalk((uint32)PET_TALK_ATTACK); -                        else +                        if(pet->GetTypeId() != TYPEID_PLAYER)                          { -                            // 90% chance for pet and 100% chance for charmed creature -                            pet->SendPetAIReaction(guid1); +                            pet->GetMotionMaster()->Clear(); +                            if (((Creature*)pet)->AI()) +                                ((Creature*)pet)->AI()->AttackStart(TargetUnit); + +                            //10% chance to play special pet attack talk, else growl +                            if(((Creature*)pet)->isPet() && ((Pet*)pet)->getPetType() == SUMMON_PET && pet != TargetUnit && urand(0, 100) < 10) +                                pet->SendPetTalk((uint32)PET_TALK_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(); +                        else                                    // charmed player +                        { +                            if(pet->getVictim() && pet->getVictim() != TargetUnit) +                                pet->AttackStop(); -                        pet->Attack(TargetUnit,true); -                        pet->SendPetAIReaction(guid1); +                            pet->Attack(TargetUnit,true); +                            pet->SendPetAIReaction(guid1); +                        }                      }                      break;                  } @@ -169,19 +177,17 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )                      break;              }              break; -        case ACT_DISABLED:                                  //0x8100    spell (disabled), ignore -        case ACT_CAST:                                      //0x0100 -        case ACT_ENABLED:                                   //0xc100    spell +        case ACT_DISABLED:                                  // 0x8100    spell (disabled), ignore +        case ACT_PASSIVE:                                   // 0x0100 +        case ACT_ENABLED:                                   // 0xC100    spell          { -            Unit* unit_target; -            if(guid2) -                unit_target = ObjectAccessor::GetUnit(*_player,guid2); -            else -                unit_target = NULL; - +            Unit* unit_target = NULL;              if (((Creature*)pet)->GetGlobalCooldown() > 0)                  return; +            if(guid2) +                unit_target = ObjectAccessor::GetUnit(*_player,guid2); +              // do not cast unknown spells              SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid );              if(!spellInfo) @@ -206,7 +212,7 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )              int16 result = spell->PetCanCast(unit_target); -                                                            //auto turn to target unless possessed +            //auto turn to target unless possessed              if(result == SPELL_FAILED_UNIT_NOT_INFRONT && !pet->isPossessed())              {                  pet->SetInFront(unit_target); @@ -237,12 +243,15 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )                  if( unit_target && !GetPlayer()->IsFriendlyTo(unit_target) && !pet->isPossessed())                  { -                    pet->clearUnitState(UNIT_STAT_FOLLOW); -                    if(pet->getVictim()) -                        pet->AttackStop(); -                    pet->GetMotionMaster()->Clear(); -                    if (((Creature*)pet)->AI()) -                        ((Creature*)pet)->AI()->AttackStart(unit_target); +                    // 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 (((Creature*)pet)->AI()) +                            ((Creature*)pet)->AI()->AttackStart(unit_target); +                    }                  }                  spell->prepare(&(spell->m_targets)); @@ -252,15 +261,12 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )                  if(pet->isPossessed())                  {                      WorldPacket data(SMSG_CAST_FAILED, (4+1+1)); -                    data << uint32(spellid) << uint8(2) << uint8(result); +                    data << uint8(0) << uint32(spellid) << uint8(result);                      switch (result)                      {                          case SPELL_FAILED_REQUIRES_SPELL_FOCUS:                              data << uint32(spellInfo->RequiresSpellFocus);                              break; -                        case SPELL_FAILED_REQUIRES_AREA: -                            data << uint32(spellInfo->AreaId); -                            break;                      }                      SendPacket(&data);                  } @@ -297,7 +303,7 @@ void WorldSession::HandlePetNameQuery( WorldPacket & recv_data )  void WorldSession::SendPetNameQuery( uint64 petguid, uint32 petnumber)  { -    Creature* pet = ObjectAccessor::GetCreatureOrPet(*_player, petguid); +    Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, petguid);      if(!pet || !pet->GetCharmInfo() || pet->GetCharmInfo()->GetPetNumber() != petnumber)          return; @@ -339,7 +345,7 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data )      if(ObjectAccessor::FindPlayer(petguid))          return; -    Creature* pet = ObjectAccessor::GetCreatureOrPet(*_player, petguid); +    Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, petguid);      if(!pet || (pet != _player->GetPet() && pet != _player->GetCharm()))      { @@ -364,7 +370,7 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data )          sLog.outDetail( "Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X\n", _player->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 == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_CAST) && spell_id && !pet->HasSpell(spell_id))) +        if(!((act_state == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_PASSIVE) && spell_id && !pet->HasSpell(spell_id)))          {              //sign for autocast              if(act_state == ACT_ENABLED && spell_id) @@ -476,7 +482,7 @@ void WorldSession::HandlePetAbandon( WorldPacket & recv_data )      sLog.outDetail( "HandlePetAbandon. CMSG_PET_ABANDON pet guid is %u", GUID_LOPART(guid) );      // pet/charmed -    Creature* pet = ObjectAccessor::GetCreatureOrPet(*_player, guid); +    Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid);      if(pet)      {          if(pet->isPet()) @@ -500,11 +506,11 @@ void WorldSession::HandlePetUnlearnOpcode(WorldPacket& recvPacket)      sLog.outDetail("CMSG_PET_UNLEARN");      uint64 guid; -    recvPacket >> guid; +    recvPacket >> guid;                 // Pet guid      Pet* pet = _player->GetPet(); -    if(!pet || pet->getPetType() != HUNTER_PET || pet->m_spells.size() <= 1) +    if(!pet || pet->getPetType() != HUNTER_PET || pet->m_usedTalentCount == 0)          return;      if(guid != pet->GetGUID()) @@ -519,38 +525,7 @@ void WorldSession::HandlePetUnlearnOpcode(WorldPacket& recvPacket)          sLog.outError("WorldSession::HandlePetUnlearnOpcode: object "I64FMTD" is considered pet-like but doesn't have a charminfo!", pet->GetGUID());          return;      } - -    uint32 cost = pet->resetTalentsCost(); - -    if (GetPlayer()->GetMoney() < cost) -    { -        GetPlayer()->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, 0, 0, 0); -        return; -    } - -    for(PetSpellMap::iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end();) -    { -        uint32 spell_id = itr->first;                       // Pet::removeSpell can invalidate iterator at erase NEW spell -        ++itr; -        pet->removeSpell(spell_id); -    } - -    pet->SetTP(pet->getLevel() * (pet->GetLoyaltyLevel() - 1)); - -    for(uint8 i = 0; i < 10; i++) -    { -        if(charmInfo->GetActionBarEntry(i)->SpellOrAction && charmInfo->GetActionBarEntry(i)->Type == ACT_ENABLED || charmInfo->GetActionBarEntry(i)->Type == ACT_DISABLED) -            charmInfo->GetActionBarEntry(i)->SpellOrAction = 0; -    } - -    // relearn pet passives -    pet->LearnPetPassives(); - -    pet->m_resetTalentsTime = time(NULL); -    pet->m_resetTalentsCost = cost; -    GetPlayer()->ModifyMoney(-(int32)cost); - -    GetPlayer()->PetSpellInitialize(); +    pet->resetTalents();  }  void WorldSession::HandlePetSpellAutocastOpcode( WorldPacket& recvPacket ) @@ -570,7 +545,7 @@ void WorldSession::HandlePetSpellAutocastOpcode( WorldPacket& recvPacket )      if(ObjectAccessor::FindPlayer(guid))          return; -    Creature* pet=ObjectAccessor::GetCreatureOrPet(*_player,guid); +    Creature* pet=ObjectAccessor::GetCreatureOrPetOrVehicle(*_player,guid);      if(!pet || (pet != _player->GetPet() && pet != _player->GetCharm()))      { @@ -606,11 +581,15 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket )  {      sLog.outDetail("WORLD: CMSG_PET_CAST_SPELL"); -    CHECK_PACKET_SIZE(recvPacket,8+4); +    CHECK_PACKET_SIZE(recvPacket,8+1+4+1);      uint64 guid;      uint32 spellid; +    uint8  cast_count; +    uint8  unk_flags;                                       // flags (if 0x02 - some additional data are received) + +    recvPacket >> guid >> cast_count >> spellid >> unk_flags; -    recvPacket >> guid >> spellid; +    sLog.outDebug("WORLD: CMSG_PET_CAST_SPELL, cast_count: %u, spellid %u, unk_flags %u", cast_count, spellid, unk_flags);      // This opcode is also sent from charmed and possessed units (players and creatures)      if(!_player->GetPet() && !_player->GetCharm()) @@ -645,6 +624,7 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket )      caster->clearUnitState(UNIT_STAT_FOLLOW);      Spell *spell = new Spell(caster, spellInfo, false); +    spell->m_cast_count = cast_count;                       // probably pending spell cast      spell->m_targets = targets;      int16 result = spell->PetCanCast(NULL); @@ -704,3 +684,128 @@ void WorldSession::SendPetNameInvalid(uint32 error, const std::string& name, Dec      SendPacket(&data);  } +void WorldSession::HandlePetLearnTalent( WorldPacket & recv_data ) +{ +    sLog.outDebug("WORLD: CMSG_PET_LEARN_TALENT"); +    recv_data.hexlike(); + +    CHECK_PACKET_SIZE(recv_data, 8+4+4); + +    uint64 guid; +    uint32 talent_id, requested_rank; +    recv_data >> guid >> talent_id >> requested_rank; + +    Pet *pet = _player->GetPet(); + +    if(!pet) +        return; + +    if(guid != pet->GetGUID()) +        return; + +    uint32 CurTalentPoints =  pet->GetFreeTalentPoints(); + +    if(CurTalentPoints == 0) +        return; + +    if (requested_rank > 4) +        return; + +    TalentEntry const *talentInfo = sTalentStore.LookupEntry(talent_id); + +    if(!talentInfo) +        return; + +    TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TalentTab); + +    if(!talentTabInfo) +        return; + +    CreatureInfo const *ci = pet->GetCreatureInfo(); + +    if(!ci) +        return; + +    CreatureFamilyEntry const *pet_family = sCreatureFamilyStore.LookupEntry(ci->family); + +    if(!pet_family) +        return; + +    if(pet_family->petTalentType < 0)                       // not hunter pet +        return; + +    // prevent learn talent for different family (cheating) +    if(!((1 << pet_family->petTalentType) & talentTabInfo->petTalentMask)) +        return; + +    // prevent skip talent ranks (cheating) +    if(requested_rank > 0 && !pet->HasSpell(talentInfo->RankID[requested_rank-1])) +        return; + +    // Check if it requires another talent +    if (talentInfo->DependsOn > 0) +    { +        if(TalentEntry const *depTalentInfo = sTalentStore.LookupEntry(talentInfo->DependsOn)) +        { +            bool hasEnoughRank = false; +            for (int i = talentInfo->DependsOnRank; i <= 4; i++) +            { +                if (depTalentInfo->RankID[i] != 0) +                    if (pet->HasSpell(depTalentInfo->RankID[i])) +                        hasEnoughRank = true; +            } +            if (!hasEnoughRank) +                return; +        } +    } + +    // Find out how many points we have in this field +    uint32 spentPoints = 0; + +    uint32 tTab = talentInfo->TalentTab; +    if (talentInfo->Row > 0) +    { +        unsigned int numRows = sTalentStore.GetNumRows(); +        for (unsigned int i = 0; i < numRows; i++)          // Loop through all talents. +        { +            // Someday, someone needs to revamp +            const TalentEntry *tmpTalent = sTalentStore.LookupEntry(i); +            if (tmpTalent)                                  // the way talents are tracked +            { +                if (tmpTalent->TalentTab == tTab) +                { +                    for (int j = 0; j <= 4; j++) +                    { +                        if (tmpTalent->RankID[j] != 0) +                        { +                            if (pet->HasSpell(tmpTalent->RankID[j])) +                            { +                                spentPoints += j + 1; +                            } +                        } +                    } +                } +            } +        } +    } + +    // not have required min points spent in talent tree +    if(spentPoints < (talentInfo->Row * 3)) +        return; + +    // spell not set in talent.dbc +    uint32 spellid = talentInfo->RankID[requested_rank]; +    if( spellid == 0 ) +    { +        sLog.outError("Talent.dbc have for talent: %u Rank: %u spell id = 0", talent_id, requested_rank); +        return; +    } + +    // already known +    if(pet->HasSpell(spellid)) +        return; + +    // learn! (other talent ranks will unlearned at learning) +    pet->learnSpell(spellid); +    sLog.outDetail("TalentID: %u Rank: %u Spell: %u\n", talent_id, requested_rank, spellid); +}  | 
