void HmacHash::Finalize() { uint32 length = 0; HMAC_Final(&m_ctx, m_digest, &length); MANGOS_ASSERT(length == SHA_DIGEST_LENGTH); }
HostileReference* ThreatContainer::selectNextVictim(Creature* pAttacker, HostileReference* pCurrentVictim) { HostileReference* currentRef = NULL; bool found = false; bool noPriorityTargetFound = false; ThreatList::const_iterator lastRef = iThreatList.end(); lastRef--; for(ThreatList::const_iterator iter = iThreatList.begin(); iter != iThreatList.end() && !found;) { currentRef = (*iter); Unit* target = currentRef->getTarget(); MANGOS_ASSERT(target); // if the ref has status online the target must be there ! // some units are prefered in comparison to others if(!noPriorityTargetFound && (target->IsImmunedToDamage(pAttacker->GetMeleeDamageSchoolMask()) || target->hasNegativeAuraWithInterruptFlag(AURA_INTERRUPT_FLAG_DAMAGE)) ) { if(iter != lastRef) { // current victim is a second choice target, so don't compare threat with it below if(currentRef == pCurrentVictim) pCurrentVictim = NULL; ++iter; continue; } else { // if we reached to this point, everyone in the threatlist is a second choice target. In such a situation the target with the highest threat should be attacked. noPriorityTargetFound = true; iter = iThreatList.begin(); continue; } } if (!pAttacker->IsOutOfThreatArea(target)) // skip non attackable currently targets { if (pCurrentVictim) // select 1.3/1.1 better target in comparison current target { // list sorted and and we check current target, then this is best case if(pCurrentVictim == currentRef || currentRef->getThreat() <= 1.1f * pCurrentVictim->getThreat() ) { currentRef = pCurrentVictim; // for second case found = true; break; } if (currentRef->getThreat() > 1.3f * pCurrentVictim->getThreat() || (currentRef->getThreat() > 1.1f * pCurrentVictim->getThreat() && pAttacker->CanReachWithMeleeAttack(target)) ) { //implement 110% threat rule for targets in melee range found = true; //and 130% rule for targets in ranged distances break; //for selecting alive targets } } else // select any { found = true; break; } } ++iter; } if(!found) currentRef = NULL; return currentRef; }
/// Logon Challenge command handler bool AuthSocket::_HandleLogonChallenge() { DEBUG_LOG("Entering _HandleLogonChallenge"); if (recv_len() < sizeof(sAuthLogonChallenge_C)) return false; ///- Read the first 4 bytes (header) to get the length of the remaining of the packet std::vector<uint8> buf; buf.resize(4); recv((char *)&buf[0], 4); EndianConvert(*((uint16*)(buf[0]))); uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size; DEBUG_LOG("[AuthChallenge] got header, body is %#04x bytes", remaining); if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (recv_len() < remaining)) return false; //No big fear of memory outage (size is int16, i.e. < 65536) buf.resize(remaining + buf.size() + 1); buf[buf.size() - 1] = 0; sAuthLogonChallenge_C *ch = (sAuthLogonChallenge_C*)&buf[0]; ///- Read the remaining of the packet recv((char *)&buf[4], remaining); DEBUG_LOG("[AuthChallenge] got full packet, %#04x bytes", ch->size); DEBUG_LOG("[AuthChallenge] name(%d): '%s'", ch->I_len, ch->I); // BigEndian code, nop in little endian case // size already converted EndianConvert(*((uint32*)(&ch->gamename[0]))); EndianConvert(ch->build); EndianConvert(*((uint32*)(&ch->platform[0]))); EndianConvert(*((uint32*)(&ch->os[0]))); EndianConvert(*((uint32*)(&ch->country[0]))); EndianConvert(ch->timezone_bias); EndianConvert(ch->ip); ByteBuffer pkt; _login = (const char*)ch->I; _build = ch->build; ///- Normalize account name //utf8ToUpperOnlyLatin(_login); -- client already send account in expected form //Escape the user login to avoid further SQL injection //Memory will be freed on AuthSocket object destruction _safelogin = _login; LoginDatabase.escape_string(_safelogin); pkt << (uint8) CMD_AUTH_LOGON_CHALLENGE; pkt << (uint8) 0x00; ///- Verify that this IP is not in the ip_banned table // No SQL injection possible (paste the IP address as passed by the socket) std::string address = get_remote_address(); LoginDatabase.escape_string(address); QueryResult *result = LoginDatabase.PQuery("SELECT unbandate FROM ip_banned WHERE " // permanent still banned "(unbandate = bandate OR unbandate > UNIX_TIMESTAMP()) AND '%s' LIKE ip", address.c_str()); if (result) { pkt << (uint8)WOW_FAIL_BANNED; BASIC_LOG("[AuthChallenge] Banned ip %s tries to login!", get_remote_address().c_str()); delete result; } else { ///- Get the account details from the account table // No SQL injection (escaped user name) result = LoginDatabase.PQuery("SELECT sha_pass_hash,id,locked,last_ip,gmlevel,v,s FROM account WHERE username = '******'",_safelogin.c_str ()); if( result ) { ///- If the IP is 'locked', check that the player comes indeed from the correct IP address bool locked = false; if((*result)[2].GetUInt8() == 1) // if ip is locked { DEBUG_LOG("[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), (*result)[3].GetString()); DEBUG_LOG("[AuthChallenge] Player address is '%s'", get_remote_address().c_str()); if ( strcmp((*result)[3].GetString(),get_remote_address().c_str()) ) { DEBUG_LOG("[AuthChallenge] Account IP differs"); pkt << (uint8) WOW_FAIL_SUSPENDED; locked=true; } else { DEBUG_LOG("[AuthChallenge] Account IP matches"); } } else { DEBUG_LOG("[AuthChallenge] Account '%s' is not locked to ip", _login.c_str()); } if (!locked) { ///- If the account is banned, reject the logon attempt QueryResult *banresult = LoginDatabase.PQuery("SELECT bandate,unbandate FROM account_banned WHERE " "id = %u AND active = 1 AND (unbandate > UNIX_TIMESTAMP() OR unbandate = bandate)", (*result)[1].GetUInt32()); if(banresult) { if((*banresult)[0].GetUInt64() == (*banresult)[1].GetUInt64()) { pkt << (uint8) WOW_FAIL_BANNED; BASIC_LOG("[AuthChallenge] Banned account %s tries to login!",_login.c_str ()); } else { pkt << (uint8) WOW_FAIL_SUSPENDED; BASIC_LOG("[AuthChallenge] Temporarily banned account %s tries to login!",_login.c_str ()); } delete banresult; } else { ///- Get the password from the account table, upper it, and make the SRP6 calculation std::string rI = (*result)[0].GetCppString(); ///- Don't calculate (v, s) if there are already some in the database std::string databaseV = (*result)[5].GetCppString(); std::string databaseS = (*result)[6].GetCppString(); DEBUG_LOG("database authentication values: v='%s' s='%s'", databaseV.c_str(), databaseS.c_str()); // multiply with 2, bytes are stored as hexstring if(databaseV.size() != s_BYTE_SIZE*2 || databaseS.size() != s_BYTE_SIZE*2) _SetVSFields(rI); else { s.SetHexStr(databaseS.c_str()); v.SetHexStr(databaseV.c_str()); } b.SetRand(19 * 8); BigNumber gmod = g.ModExp(b, N); B = ((v * 3) + gmod) % N; MANGOS_ASSERT(gmod.GetNumBytes() <= 32); BigNumber unk3; unk3.SetRand(16 * 8); ///- Fill the response packet with the result pkt << uint8(WOW_SUCCESS); // B may be calculated < 32B so we force minimal length to 32B pkt.append(B.AsByteArray(32), 32); // 32 bytes pkt << uint8(1); pkt.append(g.AsByteArray(), 1); pkt << uint8(32); pkt.append(N.AsByteArray(32), 32); pkt.append(s.AsByteArray(), s.GetNumBytes());// 32 bytes pkt.append(unk3.AsByteArray(16), 16); uint8 securityFlags = 0; pkt << uint8(securityFlags); // security flags (0x0...0x04) if(securityFlags & 0x01) // PIN input { pkt << uint32(0); pkt << uint64(0) << uint64(0); // 16 bytes hash? } if(securityFlags & 0x02) // Matrix input { pkt << uint8(0); pkt << uint8(0); pkt << uint8(0); pkt << uint8(0); pkt << uint64(0); } if(securityFlags & 0x04) // Security token input { pkt << uint8(1); } uint8 secLevel = (*result)[4].GetUInt8(); _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; _localizationName.resize(4); for(int i = 0; i < 4; ++i) _localizationName[i] = ch->country[4-i-1]; BASIC_LOG("[AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", _login.c_str (), ch->country[3], ch->country[2], ch->country[1], ch->country[0], GetLocaleByName(_localizationName)); } } delete result; } else // no account { pkt<< (uint8) WOW_FAIL_UNKNOWN_ACCOUNT; } } send((char const*)pkt.contents(), pkt.size()); return true; }
void LoadDBCStores(const std::string& dataPath) { std::string dbcPath = dataPath+"dbc/"; uint32 build = ReadDBCBuild(dbcPath); // Check the expected DBC version if (!IsAcceptableClientBuild(build)) { if (build) sLog.outError("Found DBC files for build %u but mangosd expected DBC for one from builds: %s Please extract correct DBC files.", build, AcceptableClientBuildsListStr().c_str()); else sLog.outError("Incorrect DataDir value in mangosd.conf or not found build info (outdated DBC files). Required one from builds: %s Please extract correct DBC files.",AcceptableClientBuildsListStr().c_str()); Log::WaitBeforeContinueIfNeed(); exit(1); } const uint32 DBCFilesCount = 92; BarGoLink bar(DBCFilesCount); StoreProblemList bad_dbc_files; LocalData availableDbcLocales(build); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sAreaStore, dbcPath,"AreaTable.dbc"); // must be after sAreaStore loading for (uint32 i = 0; i < sAreaStore.GetNumRows(); ++i) // areaflag numbered from 0 { if (AreaTableEntry const* area = sAreaStore.LookupEntry(i)) { // fill AreaId->DBC records sAreaFlagByAreaID.insert(AreaFlagByAreaID::value_type(uint16(area->ID),area->exploreFlag)); // fill MapId->DBC records ( skip sub zones and continents ) if(area->zone==0 && area->mapid != 0 && area->mapid != 1 && area->mapid != 530 && area->mapid != 571 ) sAreaFlagByMapID.insert(AreaFlagByMapID::value_type(area->mapid,area->exploreFlag)); } } LoadDBC(availableDbcLocales,bar,bad_dbc_files,sAchievementStore, dbcPath,"Achievement.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sAchievementCriteriaStore, dbcPath,"Achievement_Criteria.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sAreaTriggerStore, dbcPath,"AreaTrigger.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sAreaGroupStore, dbcPath,"AreaGroup.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sAuctionHouseStore, dbcPath,"AuctionHouse.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sBankBagSlotPricesStore, dbcPath,"BankBagSlotPrices.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sBattlemasterListStore, dbcPath,"BattlemasterList.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sBarberShopStyleStore, dbcPath,"BarberShopStyle.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCharStartOutfitStore, dbcPath,"CharStartOutfit.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCharTitlesStore, dbcPath,"CharTitles.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sChatChannelsStore, dbcPath,"ChatChannels.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sChrClassesStore, dbcPath,"ChrClasses.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sChrRacesStore, dbcPath,"ChrRaces.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCinematicSequencesStore, dbcPath,"CinematicSequences.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureDisplayInfoStore, dbcPath,"CreatureDisplayInfo.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureDisplayInfoExtraStore,dbcPath,"CreatureDisplayInfoExtra.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureFamilyStore, dbcPath,"CreatureFamily.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureSpellDataStore, dbcPath,"CreatureSpellData.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureTypeStore, dbcPath,"CreatureType.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCurrencyTypesStore, dbcPath,"CurrencyTypes.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sDurabilityCostsStore, dbcPath,"DurabilityCosts.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sDurabilityQualityStore, dbcPath,"DurabilityQuality.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sEmotesStore, dbcPath,"Emotes.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sEmotesTextStore, dbcPath,"EmotesText.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sFactionStore, dbcPath,"Faction.dbc"); for (uint32 i=0;i<sFactionStore.GetNumRows(); ++i) { FactionEntry const * faction = sFactionStore.LookupEntry(i); if (faction && faction->team) { SimpleFactionsList &flist = sFactionTeamMap[faction->team]; flist.push_back(i); } } LoadDBC(availableDbcLocales,bar,bad_dbc_files,sFactionTemplateStore, dbcPath,"FactionTemplate.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGameObjectDisplayInfoStore,dbcPath,"GameObjectDisplayInfo.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGemPropertiesStore, dbcPath,"GemProperties.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGlyphPropertiesStore, dbcPath,"GlyphProperties.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGlyphSlotStore, dbcPath,"GlyphSlot.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtBarberShopCostBaseStore,dbcPath,"gtBarberShopCostBase.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtCombatRatingsStore, dbcPath,"gtCombatRatings.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtChanceToMeleeCritBaseStore, dbcPath,"gtChanceToMeleeCritBase.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtChanceToMeleeCritStore, dbcPath,"gtChanceToMeleeCrit.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtChanceToSpellCritBaseStore, dbcPath,"gtChanceToSpellCritBase.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtChanceToSpellCritStore, dbcPath,"gtChanceToSpellCrit.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtOCTClassCombatRatingScalarStore,dbcPath,"gtOCTClassCombatRatingScalar.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtOCTRegenHPStore, dbcPath,"gtOCTRegenHP.dbc"); //LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtOCTRegenMPStore, dbcPath,"gtOCTRegenMP.dbc"); -- not used currently LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtRegenHPPerSptStore, dbcPath,"gtRegenHPPerSpt.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtRegenMPPerSptStore, dbcPath,"gtRegenMPPerSpt.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sHolidaysStore, dbcPath,"Holidays.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemStore, dbcPath,"Item.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemBagFamilyStore, dbcPath,"ItemBagFamily.dbc"); //LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemDisplayInfoStore, dbcPath,"ItemDisplayInfo.dbc"); -- not used currently //LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemCondExtCostsStore, dbcPath,"ItemCondExtCosts.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemExtendedCostStore, dbcPath,"ItemExtendedCost.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemLimitCategoryStore, dbcPath,"ItemLimitCategory.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemRandomPropertiesStore,dbcPath,"ItemRandomProperties.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemRandomSuffixStore, dbcPath,"ItemRandomSuffix.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemSetStore, dbcPath,"ItemSet.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sLockStore, dbcPath,"Lock.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sMailTemplateStore, dbcPath,"MailTemplate.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sMapStore, dbcPath,"Map.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sMapDifficultyStore, dbcPath,"MapDifficulty.dbc"); // fill data for(uint32 i = 1; i < sMapDifficultyStore.GetNumRows(); ++i) if(MapDifficultyEntry const* entry = sMapDifficultyStore.LookupEntry(i)) sMapDifficultyMap[MAKE_PAIR32(entry->MapId,entry->Difficulty)] = MapDifficulty(entry->resetTime,entry->maxPlayers); sMapDifficultyStore.Clear(); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sMovieStore, dbcPath,"Movie.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sOverrideSpellDataStore, dbcPath,"OverrideSpellData.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sQuestFactionRewardStore, dbcPath,"QuestFactionReward.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sQuestSortStore, dbcPath,"QuestSort.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sQuestXPLevelStore, dbcPath,"QuestXP.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sPvPDifficultyStore, dbcPath,"PvpDifficulty.dbc"); for(uint32 i = 0; i < sPvPDifficultyStore.GetNumRows(); ++i) if (PvPDifficultyEntry const* entry = sPvPDifficultyStore.LookupEntry(i)) if (entry->bracketId > MAX_BATTLEGROUND_BRACKETS) MANGOS_ASSERT(false && "Need update MAX_BATTLEGROUND_BRACKETS by DBC data"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sRandomPropertiesPointsStore, dbcPath,"RandPropPoints.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sScalingStatDistributionStore, dbcPath,"ScalingStatDistribution.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sScalingStatValuesStore, dbcPath,"ScalingStatValues.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSkillLineStore, dbcPath,"SkillLine.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSkillLineAbilityStore, dbcPath,"SkillLineAbility.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSkillRaceClassInfoStore, dbcPath,"SkillRaceClassInfo.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSoundEntriesStore, dbcPath,"SoundEntries.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellStore, dbcPath,"Spell.dbc"); for(uint32 i = 1; i < sSpellStore.GetNumRows(); ++i) { SpellEntry const * spell = sSpellStore.LookupEntry(i); if(spell && spell->Category) sSpellCategoryStore[spell->Category].insert(i); // DBC not support uint64 fields but SpellEntry have SpellFamilyFlags mapped at 2 uint32 fields // uint32 field already converted to bigendian if need, but must be swapped for correct uint64 bigendian view #if MANGOS_ENDIAN == MANGOS_BIGENDIAN std::swap(*((uint32*)(&spell->SpellFamilyFlags)),*(((uint32*)(&spell->SpellFamilyFlags))+1)); #endif } for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j) { SkillLineAbilityEntry const *skillLine = sSkillLineAbilityStore.LookupEntry(j); if(!skillLine) continue; SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillLine->spellId); if(spellInfo && (spellInfo->Attributes & 0x1D0) == 0x1D0) { for (unsigned int i = 1; i < sCreatureFamilyStore.GetNumRows(); ++i) { CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(i); if(!cFamily) continue; if(skillLine->skillId != cFamily->skillLine[0] && skillLine->skillId != cFamily->skillLine[1]) continue; sPetFamilySpellsStore[i].insert(spellInfo->Id); } } } LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellCastTimesStore, dbcPath,"SpellCastTimes.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellDurationStore, dbcPath,"SpellDuration.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellDifficultyStore, dbcPath,"SpellDifficulty.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellFocusObjectStore, dbcPath,"SpellFocusObject.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellItemEnchantmentStore,dbcPath,"SpellItemEnchantment.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellItemEnchantmentConditionStore,dbcPath,"SpellItemEnchantmentCondition.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellRadiusStore, dbcPath,"SpellRadius.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellRangeStore, dbcPath,"SpellRange.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellRuneCostStore, dbcPath,"SpellRuneCost.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellShapeshiftFormStore, dbcPath,"SpellShapeshiftForm.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sStableSlotPricesStore, dbcPath,"StableSlotPrices.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSummonPropertiesStore, dbcPath,"SummonProperties.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTalentStore, dbcPath,"Talent.dbc"); // create talent spells set for (unsigned int i = 0; i < sTalentStore.GetNumRows(); ++i) { TalentEntry const *talentInfo = sTalentStore.LookupEntry(i); if (!talentInfo) continue; for (int j = 0; j < MAX_TALENT_RANK; j++) if(talentInfo->RankID[j]) sTalentSpellPosMap[talentInfo->RankID[j]] = TalentSpellPos(i,j); } LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTalentTabStore, dbcPath,"TalentTab.dbc"); // prepare fast data access to bit pos of talent ranks for use at inspecting { // now have all max ranks (and then bit amount used for store talent ranks in inspect) for(uint32 talentTabId = 1; talentTabId < sTalentTabStore.GetNumRows(); ++talentTabId) { TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry( talentTabId ); if(!talentTabInfo) continue; // prevent memory corruption; otherwise cls will become 12 below if ((talentTabInfo->ClassMask & CLASSMASK_ALL_PLAYABLE)==0) continue; // store class talent tab pages uint32 cls = 1; for(uint32 m=1;!(m & talentTabInfo->ClassMask) && cls < MAX_CLASSES;m <<=1, ++cls) {} sTalentTabPages[cls][talentTabInfo->tabpage]=talentTabId; } } LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTaxiNodesStore, dbcPath,"TaxiNodes.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTaxiPathStore, dbcPath,"TaxiPath.dbc"); for(uint32 i = 1; i < sTaxiPathStore.GetNumRows(); ++i) if(TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(i)) sTaxiPathSetBySource[entry->from][entry->to] = TaxiPathBySourceAndDestination(entry->ID,entry->price); uint32 pathCount = sTaxiPathStore.GetNumRows(); //## TaxiPathNode.dbc ## Loaded only for initialization different structures LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTaxiPathNodeStore, dbcPath,"TaxiPathNode.dbc"); // Calculate path nodes count std::vector<uint32> pathLength; pathLength.resize(pathCount); // 0 and some other indexes not used for(uint32 i = 1; i < sTaxiPathNodeStore.GetNumRows(); ++i) if(TaxiPathNodeEntry const* entry = sTaxiPathNodeStore.LookupEntry(i)) { if (pathLength[entry->path] < entry->index + 1) pathLength[entry->path] = entry->index + 1; } // Set path length sTaxiPathNodesByPath.resize(pathCount); // 0 and some other indexes not used for(uint32 i = 1; i < sTaxiPathNodesByPath.size(); ++i) sTaxiPathNodesByPath[i].resize(pathLength[i]); // fill data (pointers to sTaxiPathNodeStore elements for(uint32 i = 1; i < sTaxiPathNodeStore.GetNumRows(); ++i) if(TaxiPathNodeEntry const* entry = sTaxiPathNodeStore.LookupEntry(i)) sTaxiPathNodesByPath[entry->path].set(entry->index, entry); // Initialize global taxinodes mask // include existing nodes that have at least single not spell base (scripted) path { std::set<uint32> spellPaths; for(uint32 i = 1; i < sSpellStore.GetNumRows (); ++i) if(SpellEntry const* sInfo = sSpellStore.LookupEntry (i)) for(int j=0; j < MAX_EFFECT_INDEX; ++j) if(sInfo->Effect[j]==123 /*SPELL_EFFECT_SEND_TAXI*/) spellPaths.insert(sInfo->EffectMiscValue[j]); memset(sTaxiNodesMask,0,sizeof(sTaxiNodesMask)); memset(sOldContinentsNodesMask,0,sizeof(sTaxiNodesMask)); for(uint32 i = 1; i < sTaxiNodesStore.GetNumRows(); ++i) { TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(i); if(!node) continue; TaxiPathSetBySource::const_iterator src_i = sTaxiPathSetBySource.find(i); if(src_i!=sTaxiPathSetBySource.end() && !src_i->second.empty()) { bool ok = false; for(TaxiPathSetForSource::const_iterator dest_i = src_i->second.begin();dest_i != src_i->second.end(); ++dest_i) { // not spell path if(spellPaths.find(dest_i->second.ID)==spellPaths.end()) { ok = true; break; } } if(!ok) continue; } // valid taxi network node uint8 field = (uint8)((i - 1) / 32); uint32 submask = 1<<((i-1)%32); sTaxiNodesMask[field] |= submask; // old continent node (+ nodes virtually at old continents, check explicitly to avoid loading map files for zone info) if (node->map_id < 2 || i == 82 || i == 83 || i == 93 || i == 94) sOldContinentsNodesMask[field] |= submask; } } LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTeamContributionPoints, dbcPath,"TeamContributionPoints.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTotemCategoryStore, dbcPath,"TotemCategory.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sVehicleStore, dbcPath,"Vehicle.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sVehicleSeatStore, dbcPath,"VehicleSeat.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sWorldMapAreaStore, dbcPath,"WorldMapArea.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sWMOAreaTableStore, dbcPath,"WMOAreaTable.dbc"); for(uint32 i = 0; i < sWMOAreaTableStore.GetNumRows(); ++i) { if(WMOAreaTableEntry const* entry = sWMOAreaTableStore.LookupEntry(i)) { sWMOAreaInfoByTripple.insert(WMOAreaInfoByTripple::value_type(WMOAreaTableTripple(entry->rootId, entry->adtId, entry->groupId), entry)); } } LoadDBC(availableDbcLocales,bar,bad_dbc_files,sWorldMapOverlayStore, dbcPath,"WorldMapOverlay.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sWorldSafeLocsStore, dbcPath,"WorldSafeLocs.dbc"); // error checks if (bad_dbc_files.size() >= DBCFilesCount ) { sLog.outError("\nIncorrect DataDir value in mangosd.conf or ALL required *.dbc files (%d) not found by path: %sdbc",DBCFilesCount,dataPath.c_str()); Log::WaitBeforeContinueIfNeed(); exit(1); } else if (!bad_dbc_files.empty() ) { std::string str; for(std::list<std::string>::iterator i = bad_dbc_files.begin(); i != bad_dbc_files.end(); ++i) str += *i + "\n"; sLog.outError("\nSome required *.dbc files (%u from %d) not found or not compatible:\n%s",(uint32)bad_dbc_files.size(),DBCFilesCount,str.c_str()); Log::WaitBeforeContinueIfNeed(); exit(1); } // Check loaded DBC files proper version if (!sAreaStore.LookupEntry(3617) || // last area (areaflag) added in 3.3.5a !sCharTitlesStore.LookupEntry(177) || // last char title added in 3.3.5a !sGemPropertiesStore.LookupEntry(1629) || // last gem property added in 3.3.5a !sItemStore.LookupEntry(56806) || // last client known item added in 3.3.5a !sItemExtendedCostStore.LookupEntry(2997) || // last item extended cost added in 3.3.5a !sMapStore.LookupEntry(724) || // last map added in 3.3.5a !sSpellStore.LookupEntry(80864) ) // last added spell in 3.3.5a { sLog.outError("\nYou have mixed version DBC files. Please re-extract DBC files for one from client build: %s",AcceptableClientBuildsListStr().c_str()); Log::WaitBeforeContinueIfNeed(); exit(1); } sLog.outString(); sLog.outString( ">> Initialized %d data stores", DBCFilesCount ); }
void CreatureAI::SendAIEvent(AIEventType eventType, Unit* pInvoker, Creature* pReceiver, uint32 miscValue /*=0*/) const { MANGOS_ASSERT(pReceiver); pReceiver->AI()->ReceiveAIEvent(eventType, m_creature, pInvoker, miscValue); }
void Player::UpdateAttackPowerAndDamage(bool ranged) { ChrClassesEntry const * chrEntry = sChrClassesStore.LookupEntry(getClass()); MANGOS_ASSERT(chrEntry); float val2 = 0.0f; float level = float(getLevel()); UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER; uint16 index = UNIT_FIELD_ATTACK_POWER; uint16 index_mod = UNIT_FIELD_ATTACK_POWER_MOD_POS; uint16 index_mult = UNIT_FIELD_ATTACK_POWER_MULTIPLIER; if (ranged) { index = UNIT_FIELD_RANGED_ATTACK_POWER; index_mod = UNIT_FIELD_RANGED_ATTACK_POWER_MOD_POS; index_mult = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER; float rapPerAgi = std::max(GetStat(STAT_AGILITY) - 10.0f, 0.0f) * chrEntry->rapPerAgi; switch (getClass()) { case CLASS_HUNTER: val2 = level * 2.0f + rapPerAgi; break; case CLASS_ROGUE: val2 = level + rapPerAgi; break; case CLASS_WARRIOR: val2 = level + rapPerAgi; break; default: break; } } else { float apPerAgi = std::max(GetStat(STAT_AGILITY) - 10.0f, 0.0f) * chrEntry->apPerAgi; float apPerStr = std::max(GetStat(STAT_STRENGTH) - 10.0f, 0.0f) * chrEntry->apPerStr; float levelmod; switch (getClass()) { case CLASS_WARRIOR: case CLASS_PALADIN: case CLASS_DEATH_KNIGHT: case CLASS_DRUID: levelmod = 3.0f; break; default: levelmod = 2.0f; break; } val2 = level * levelmod + apPerAgi + apPerStr; // extracted from client if (getClass() == CLASS_DRUID && GetShapeshiftForm()) { if (SpellShapeshiftFormEntry const * entry = sSpellShapeshiftFormStore.LookupEntry(uint32(GetShapeshiftForm()))) if (entry->flags1 & 0x20) val2 += std::max(GetStat(STAT_AGILITY) - 10.0f, 0.0f) * chrEntry->apPerStr; } } SetModifierValue(unitMod, BASE_VALUE, val2); float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT); float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE); // add dynamic flat mods if (!ranged) { AuraList const& mAPbyArmor = GetAurasByType(SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR); for (AuraList::const_iterator iter = mAPbyArmor.begin(); iter != mAPbyArmor.end(); ++iter) // always: ((*i)->GetModifier()->m_miscvalue == 1 == SPELL_SCHOOL_MASK_NORMAL) attPowerMod += int32(GetArmor() / (*iter)->GetModifier()->m_amount); } float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f; SetInt32Value(index, (uint32)base_attPower); // UNIT_FIELD_(RANGED)_ATTACK_POWER field SetInt32Value(index_mod, (uint32)attPowerMod); // UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field SetFloatValue(index_mult, attPowerMultiplier); // UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field // automatically update weapon damage after attack power modification if (ranged) { UpdateDamagePhysical(RANGED_ATTACK); Pet* pet = GetPet(); // update pet's AP if (pet) pet->UpdateAttackPowerAndDamage(); } else { UpdateDamagePhysical(BASE_ATTACK); if (CanDualWield() && haveOffhandWeapon()) // allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon UpdateDamagePhysical(OFF_ATTACK); } }
void WaypointMovementGenerator<Creature>::OnArrived(Creature& creature) { if (!i_path || i_path->empty()) return; m_lastReachedWaypoint = i_currentNode; if (m_isArrivalDone) return; creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); m_isArrivalDone = true; WaypointPath::const_iterator currPoint = i_path->find(i_currentNode); MANGOS_ASSERT(currPoint != i_path->end()); WaypointNode const& node = currPoint->second; if (node.script_id) { DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Creature movement start script %u at point %u for %s.", node.script_id, i_currentNode, creature.GetGuidStr().c_str()); creature.GetMap()->ScriptsStart(sCreatureMovementScripts, node.script_id, &creature, &creature); } // We have reached the destination and can process behavior if (WaypointBehavior* behavior = node.behavior) { if (behavior->emote != 0) creature.HandleEmote(behavior->emote); if (behavior->spell != 0) creature.CastSpell(&creature, behavior->spell, false); if (behavior->model1 != 0) creature.SetDisplayId(behavior->model1); if (behavior->textid[0]) { int32 textId = behavior->textid[0]; // Not only one text is set if (behavior->textid[1]) { // Select one from max 5 texts (0 and 1 already checked) int i = 2; for (; i < MAX_WAYPOINT_TEXT; ++i) { if (!behavior->textid[i]) break; } textId = behavior->textid[urand(0, i - 1)]; } if (MangosStringLocale const* textData = sObjectMgr.GetMangosStringLocale(textId)) creature.MonsterText(textData, nullptr); else sLog.outErrorDb("%s reached waypoint %u, attempted to do text %i, but required text-data could not be found", creature.GetGuidStr().c_str(), i_currentNode, textId); } } // Inform script if (creature.AI()) { uint32 type = WAYPOINT_MOTION_TYPE; if (m_PathOrigin == PATH_FROM_EXTERNAL && m_pathId > 0) type = EXTERNAL_WAYPOINT_MOVE + m_pathId; creature.AI()->MovementInform(type, i_currentNode); } // Wait delay ms Stop(node.delay); }
void CreatureAI::SendAIEvent(AIEventType eventType, Unit* pInvoker, Creature* pReceiver) const { MANGOS_ASSERT(pReceiver); pReceiver->AI()->ReceiveAIEvent(eventType, m_creature, pInvoker); }
void PetAI::UpdateAI(const uint32 diff) { if (!m_unit->isAlive()) return; Creature* creature = (m_unit->GetTypeId() == TYPEID_UNIT) ? static_cast<Creature*>(m_unit) : nullptr; Pet* pet = (creature && creature->IsPet()) ? static_cast<Pet*>(m_unit) : nullptr; Unit* owner = m_unit->GetCharmerOrOwner(); if (!owner) return; Unit* victim = (pet && pet->GetModeFlags() & PET_MODE_DISABLE_ACTIONS) ? nullptr : m_unit->getVictim(); if (m_updateAlliesTimer <= diff) // UpdateAllies self set update timer UpdateAllies(); else m_updateAlliesTimer -= diff; if (inCombat && !victim) { m_unit->AttackStop(true, true); inCombat = false; } CharmInfo* charminfo = m_unit->GetCharmInfo(); MANGOS_ASSERT(charminfo); if (charminfo->GetIsRetreating()) { if (!owner->IsWithinDistInMap(m_unit, (PET_FOLLOW_DIST * 2))) { if (!m_unit->hasUnitState(UNIT_STAT_FOLLOW)) m_unit->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); return; } else charminfo->SetIsRetreating(); } else if (charminfo->GetSpellOpener() != 0) // have opener stored { uint32 minRange = charminfo->GetSpellOpenerMinRange(); if (!(victim = m_unit->getVictim()) || (minRange != 0 && m_unit->IsWithinDistInMap(victim, minRange))) charminfo->SetSpellOpener(); else if (m_unit->IsWithinDistInMap(victim, charminfo->GetSpellOpenerMaxRange()) && m_unit->IsWithinLOSInMap(victim)) { // stop moving m_unit->clearUnitState(UNIT_STAT_MOVING); // auto turn to target m_unit->SetInFront(victim); if (victim->GetTypeId() == TYPEID_PLAYER) m_unit->SendCreateUpdateToPlayer((Player*)victim); if (owner->GetTypeId() == TYPEID_PLAYER) m_unit->SendCreateUpdateToPlayer((Player*)owner); uint32 spell_id = charminfo->GetSpellOpener(); SpellEntry const* spellInfo = sSpellTemplate.LookupEntry<SpellEntry>(spell_id); Spell* spell = new Spell(m_unit, spellInfo, false); SpellCastResult result = spell->CheckPetCast(victim); if (result == SPELL_CAST_OK) { if (creature) creature->AddCreatureSpellCooldown(spell_id); spell->SpellStart(&(spell->m_targets)); } else delete spell; charminfo->SetSpellOpener(); } else return; } // Auto cast (casted only in combat or persistent spells in any state) else if (!m_unit->IsNonMeleeSpellCasted(false)) { typedef std::vector<std::pair<Unit*, Spell*> > TargetSpellList; TargetSpellList targetSpellStore; if (pet) { for (uint8 i = 0; i < pet->GetPetAutoSpellSize(); ++i) { uint32 spellID = pet->GetPetAutoSpellOnPos(i); if (!spellID) continue; SpellEntry const* spellInfo = sSpellTemplate.LookupEntry<SpellEntry>(spellID); if (!spellInfo) continue; if (m_unit->GetCharmInfo() && m_unit->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) continue; // ignore some combinations of combat state and combat/non combat spells if (!inCombat) { // ignore attacking spells, and allow only self/around spells if (!IsPositiveSpell(spellInfo->Id)) continue; // non combat spells allowed // only pet spells have IsNonCombatSpell and not fit this requirements: // Consume Shadows, Lesser Invisibility, so ignore checks for its if (!IsNonCombatSpell(spellInfo)) { int32 duration = GetSpellDuration(spellInfo); int32 cooldown = GetSpellRecoveryTime(spellInfo); // allow only spell not on cooldown if (cooldown != 0 && duration < cooldown) continue; // not allow instant kill auto casts as full health cost if (IsSpellHaveEffect(spellInfo, SPELL_EFFECT_INSTAKILL)) continue; } } // just ignore non-combat spells else if (IsNonCombatSpell(spellInfo)) continue; Spell* spell = new Spell(m_unit, spellInfo, false); if (inCombat && !m_unit->hasUnitState(UNIT_STAT_FOLLOW) && spell->CanAutoCast(victim)) { targetSpellStore.push_back(TargetSpellList::value_type(victim, spell)); continue; } else { bool spellUsed = false; for (GuidSet::const_iterator tar = m_AllySet.begin(); tar != m_AllySet.end(); ++tar) { Unit* Target = m_unit->GetMap()->GetUnit(*tar); // only buff targets that are in combat, unless the spell can only be cast while out of combat if (!Target) continue; if (spell->CanAutoCast(Target)) { targetSpellStore.push_back(TargetSpellList::value_type(Target, spell)); spellUsed = true; break; } } if (!spellUsed) delete spell; } } } // found units to cast on to if (!targetSpellStore.empty()) { uint32 index = urand(0, targetSpellStore.size() - 1); Spell* spell = targetSpellStore[index].second; Unit* target = targetSpellStore[index].first; targetSpellStore.erase(targetSpellStore.begin() + index); SpellCastTargets targets; targets.setUnitTarget(target); if (!m_unit->HasInArc(M_PI_F, target)) { m_unit->SetInFront(target); if (target->GetTypeId() == TYPEID_PLAYER) m_unit->SendCreateUpdateToPlayer((Player*)target); if (owner && owner->GetTypeId() == TYPEID_PLAYER) m_unit->SendCreateUpdateToPlayer((Player*)owner); } if (creature) creature->AddCreatureSpellCooldown(spell->m_spellInfo->Id); spell->SpellStart(&targets); } // deleted cached Spell objects for (TargetSpellList::const_iterator itr = targetSpellStore.begin(); itr != targetSpellStore.end(); ++itr) delete itr->second; } // Stop here if casting spell (No melee and no movement) if (m_unit->IsNonMeleeSpellCasted(false)) return; // we may get our actions disabled during spell casting, so do entire recheck for victim victim = (pet && pet->GetModeFlags() & PET_MODE_DISABLE_ACTIONS) ? nullptr : m_unit->getVictim(); if (victim) { // i_pet.getVictim() can't be used for check in case stop fighting, i_pet.getVictim() clear at Unit death etc. // This is needed for charmed creatures, as once their target was reset other effects can trigger threat if (!victim->isTargetableForAttack()) { DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "PetAI (guid = %u) is stopping attack.", m_unit->GetGUIDLow()); m_unit->CombatStop(); inCombat = false; return; } // if pet misses its target, it will also be the first in threat list if ((!creature || !(creature->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_MELEE)) && m_unit->CanReachWithMeleeAttack(victim)) { if (!m_unit->HasInArc(2 * M_PI_F / 3, victim)) { m_unit->SetInFront(victim); if (victim->GetTypeId() == TYPEID_PLAYER) m_unit->SendCreateUpdateToPlayer((Player*)victim); if (owner && owner->GetTypeId() == TYPEID_PLAYER) m_unit->SendCreateUpdateToPlayer((Player*)owner); } DoMeleeAttackIfReady(); } else if (!m_unit->hasUnitState(UNIT_STAT_MOVING)) AttackStart(victim); } else if (owner) { CharmInfo* charmInfo = m_unit->GetCharmInfo(); if (owner->isInCombat() && !(charmInfo && charmInfo->HasReactState(REACT_PASSIVE))) AttackStart(owner->getAttackerForHelper()); else { if (charmInfo && charmInfo->HasCommandState(COMMAND_STAY)) { //if stay command is set but we don't have stay pos set then we need to establish current pos as stay position if (!charminfo->IsStayPosSet()) charminfo->SetStayPosition(true); float stayPosX = charminfo->GetStayPosX(); float stayPosY = charminfo->GetStayPosY(); float stayPosZ = charminfo->GetStayPosZ(); if (m_unit->GetPositionX() == stayPosX && m_unit->GetPositionY() == stayPosY && m_unit->GetPositionZ() == stayPosZ) { float StayPosO = charminfo->GetStayPosO(); if (m_unit->hasUnitState(UNIT_STAT_MOVING)) { m_unit->GetMotionMaster()->Clear(false); m_unit->GetMotionMaster()->MoveIdle(); } else if (m_unit->GetOrientation() != StayPosO) m_unit->SetOrientation(StayPosO); } else m_unit->GetMotionMaster()->MovePoint(0, stayPosX, stayPosY, stayPosZ, false); } else if (m_unit->hasUnitState(UNIT_STAT_FOLLOW)) { if (owner->IsWithinDistInMap(m_unit, PET_FOLLOW_DIST)) { m_unit->GetMotionMaster()->Clear(false); m_unit->GetMotionMaster()->MoveIdle(); } } else if (charmInfo && charmInfo->HasCommandState(COMMAND_FOLLOW) && !owner->IsWithinDistInMap(m_unit, (PET_FOLLOW_DIST * 2))) m_unit->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); } } }
void BattleGroundAV::HandleQuestComplete(uint32 questid, Player *player) { if (GetStatus() != STATUS_IN_PROGRESS) return; BattleGroundAVTeamIndex teamIdx = GetAVTeamIndexByTeamId(player->GetTeam()); MANGOS_ASSERT(teamIdx != BG_AV_TEAM_NEUTRAL); uint32 reputation = 0; // reputation for the whole team (other reputation must be done in db) // TODO add events (including quest not available anymore, next quest availabe, go/npc de/spawning) sLog.outError("BattleGroundAV: Quest %i completed", questid); switch(questid) { case BG_AV_QUEST_A_SCRAPS1: case BG_AV_QUEST_A_SCRAPS2: case BG_AV_QUEST_H_SCRAPS1: case BG_AV_QUEST_H_SCRAPS2: //ToDo: We have to handle the supply crates! m_Team_QuestStatus[teamIdx][0] += 20; reputation = 1; if( m_Team_QuestStatus[teamIdx][0] == 500 || m_Team_QuestStatus[teamIdx][0] == 1500 || m_Team_QuestStatus[teamIdx][0] == 3000) { //get team smith Creature* Smith = 0; if (teamIdx == BG_TEAM_ALLIANCE) Smith = player->GetMap()->GetCreature(GetSingleCreatureGuid(BG_AV_Smith_A, 0)); else if (teamIdx == BG_TEAM_HORDE) Smith = player->GetMap()->GetCreature(GetSingleCreatureGuid(BG_AV_Smith_H, 0)); //here we call the scriptevzero alterac valley.cpp to handle the smith gossip if (Smith) Smith->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); DEBUG_LOG("BattleGroundAV: Quest %i completed starting with unit upgrading..", questid); for (BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_FROSTWOLF_HUT; ++i) if (m_Nodes[i].Owner == teamIdx && m_Nodes[i].State == POINT_CONTROLLED) PopulateNode(i); } break; case BG_AV_QUEST_A_COMMANDER1: case BG_AV_QUEST_H_COMMANDER1: m_Team_QuestStatus[teamIdx][1]++; reputation = 1; if (m_Team_QuestStatus[teamIdx][1] == 120) DEBUG_LOG("BattleGroundAV: Quest %i completed (need to implement some events here", questid); break; case BG_AV_QUEST_A_COMMANDER2: case BG_AV_QUEST_H_COMMANDER2: m_Team_QuestStatus[teamIdx][2]++; reputation = 2; if (m_Team_QuestStatus[teamIdx][2] == 60) DEBUG_LOG("BattleGroundAV: Quest %i completed (need to implement some events here", questid); break; case BG_AV_QUEST_A_COMMANDER3: case BG_AV_QUEST_H_COMMANDER3: m_Team_QuestStatus[teamIdx][3]++; reputation = 5; if (m_Team_QuestStatus[teamIdx][1] == 30) DEBUG_LOG("BattleGroundAV: Quest %i completed (need to implement some events here", questid); break; case BG_AV_QUEST_A_BOSS1: case BG_AV_QUEST_H_BOSS1: m_Team_QuestStatus[teamIdx][4] += 4; // there are 2 quests where you can turn in 5 or 1 item.. ( + 4 cause +1 will be done some lines below) reputation = 4; case BG_AV_QUEST_A_BOSS2: case BG_AV_QUEST_H_BOSS2: m_Team_QuestStatus[teamIdx][4]++; reputation += 1; //Zero: this feature isn't completly finished and stable if (m_Team_QuestStatus[teamIdx][4] >= 200) { //get team smith Creature* summonMaster = 0; if (teamIdx == BG_TEAM_ALLIANCE) summonMaster = player->GetMap()->GetCreature(GetSingleCreatureGuid(BG_AV_BOSS_SUMMON_MASTER_A, 0)); else if (teamIdx == BG_TEAM_HORDE) summonMaster = player->GetMap()->GetCreature(GetSingleCreatureGuid(BG_AV_BOSS_SUMMON_MASTER_H, 0)); if (summonMaster) summonMaster->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_OUTDOORPVP); } break; case BG_AV_QUEST_A_NEAR_MINE: case BG_AV_QUEST_H_NEAR_MINE: m_Team_QuestStatus[teamIdx][5]++; reputation = 2; if (m_Team_QuestStatus[teamIdx][5] == 28) { DEBUG_LOG("BattleGroundAV: Quest %i completed (need to implement some events here", questid); if (m_Team_QuestStatus[teamIdx][6] == 7) DEBUG_LOG("BattleGroundAV: Quest %i completed (need to implement some events here - ground assault ready", questid); } break; case BG_AV_QUEST_A_OTHER_MINE: case BG_AV_QUEST_H_OTHER_MINE: m_Team_QuestStatus[teamIdx][6]++; reputation = 3; if (m_Team_QuestStatus[teamIdx][6] == 7) { DEBUG_LOG("BattleGroundAV: Quest %i completed (need to implement some events here", questid); if (m_Team_QuestStatus[teamIdx][5] == 20) DEBUG_LOG("BattleGroundAV: Quest %i completed (need to implement some events here - ground assault ready", questid); } break; case BG_AV_QUEST_A_RIDER_HIDE: case BG_AV_QUEST_H_RIDER_HIDE: m_Team_QuestStatus[teamIdx][7]++; reputation = 1; if (m_Team_QuestStatus[teamIdx][7] == 25) { DEBUG_LOG("BattleGroundAV: Quest %i completed (need to implement some events here", questid); if (m_Team_QuestStatus[teamIdx][8] == 25) DEBUG_LOG("BattleGroundAV: Quest %i completed (need to implement some events here - rider assault ready", questid); } break; case BG_AV_QUEST_A_RIDER_TAME: case BG_AV_QUEST_H_RIDER_TAME: m_Team_QuestStatus[teamIdx][8]++; reputation = 1; if (m_Team_QuestStatus[teamIdx][8] == 25) { DEBUG_LOG("BattleGroundAV: Quest %i completed (need to implement some events here", questid); if (m_Team_QuestStatus[teamIdx][7] == 25) DEBUG_LOG("BattleGroundAV: Quest %i completed (need to implement some events here - rider assault ready", questid); } break; default: DEBUG_LOG("BattleGroundAV: Quest %i completed but is not interesting for us", questid); return; break; } if (reputation) RewardReputationToTeam((player->GetTeam() == ALLIANCE) ? BG_AV_FACTION_A : BG_AV_FACTION_H, reputation, player->GetTeam()); }
HostileReference* ThreatContainer::selectNextVictim(Creature* pAttacker, HostileReference* pCurrentVictim) { HostileReference* pCurrentRef = NULL; bool found = false; bool onlySecondChoiceTargetsFound = false; bool checkedCurrentVictim = false; ThreatList::const_iterator lastRef = iThreatList.end(); --lastRef; for (ThreatList::const_iterator iter = iThreatList.begin(); iter != iThreatList.end() && !found;) { pCurrentRef = (*iter); Unit* pTarget = pCurrentRef->getTarget(); // MANGOS_ASSERT(pTarget); // if the ref has status online the target must be there! if (!pTarget) continue; MAPLOCK_READ(pTarget, MAP_LOCK_TYPE_THREAT); // some units are prefered in comparison to others // if (checkThreatArea) consider IsOutOfThreatArea - expected to be only set for pCurrentVictim // This prevents dropping valid targets due to 1.1 or 1.3 threat rule vs invalid current target if (!onlySecondChoiceTargetsFound && pAttacker->IsSecondChoiceTarget(pTarget, pCurrentRef == pCurrentVictim)) { if (iter != lastRef) ++iter; else { // if we reached to this point, everyone in the threatlist is a second choice target. In such a situation the target with the highest threat should be attacked. onlySecondChoiceTargetsFound = true; iter = iThreatList.begin(); } // current victim is a second choice target, so don't compare threat with it below if (pCurrentRef == pCurrentVictim) pCurrentVictim = NULL; // second choice targets are only handled threat dependend if we have only have second choice targets continue; } if (!pAttacker->IsOutOfThreatArea(pTarget)) // skip non attackable currently targets { if (pCurrentVictim) // select 1.3/1.1 better target in comparison current target { // normal case: pCurrentRef is still valid and most hated if (pCurrentVictim == pCurrentRef) { found = true; break; } // we found a valid target, but only compare its threat if the currect victim is also a valid target // Additional check to prevent unneeded comparision in case of valid current victim if (!checkedCurrentVictim) { Unit* pCurrentTarget = pCurrentVictim->getTarget(); MANGOS_ASSERT(pCurrentTarget); if (pAttacker->IsSecondChoiceTarget(pCurrentTarget, true)) { // CurrentVictim is invalid, so return CurrentRef found = true; break; } checkedCurrentVictim = true; } // list sorted and and we check current target, then this is best case if (pCurrentRef->getThreat() <= 1.1f * pCurrentVictim->getThreat()) { pCurrentRef = pCurrentVictim; found = true; break; } if (pCurrentRef->getThreat() > 1.3f * pCurrentVictim->getThreat() || (pCurrentRef->getThreat() > 1.1f * pCurrentVictim->getThreat() && pAttacker->CanReachWithMeleeAttack(pTarget))) { // implement 110% threat rule for targets in melee range found = true; // and 130% rule for targets in ranged distances break; // for selecting alive targets } } else // select any { found = true; break; } } ++iter; } if (!found) pCurrentRef = NULL; return pCurrentRef; }
SqlTransaction * Database::TransHelper::init() { MANGOS_ASSERT(!m_pTrans); //if we will get a nested transaction request - we MUST fix code!!! m_pTrans = new SqlTransaction; return m_pTrans; }
CreatureAI* selectAI(Creature* creature) { // Allow scripting AI for normal creatures and not controlled pets (guardians and mini-pets) if ((!creature->IsPet() || !((Pet*)creature)->isControlled()) && !creature->isCharmed()) { CreatureAI* scriptedAI = sScriptMgr.GetCreatureAI(creature); if (scriptedAI) return scriptedAI; } if (creature->IsVehicle() && creature->isCharmed() && creature->GetCharmer() && creature->GetCharmer()->GetTypeId() == TYPEID_PLAYER) return (new NullCreatureAI(creature)); CreatureAIRegistry& ai_registry(CreatureAIRepository::Instance()); const CreatureAICreator* ai_factory = NULL; std::string ainame = creature->GetAIName(); // select by NPC flags _first_ - otherwise EventAI might be choosen for pets/totems // excplicit check for isControlled() and owner type to allow guardian, mini-pets and pets controlled by NPCs to be scripted by EventAI Unit* owner = NULL; if ((creature->IsPet() && ((Pet*)creature)->isControlled() && ((owner = creature->GetOwner()) && owner->GetTypeId() == TYPEID_PLAYER)) || creature->isCharmed()) ai_factory = ai_registry.GetRegistryItem("PetAI"); else if (creature->IsTotem()) ai_factory = ai_registry.GetRegistryItem("TotemAI"); // select by script name if (!ai_factory && !ainame.empty()) ai_factory = ai_registry.GetRegistryItem(ainame.c_str()); if (!ai_factory && creature->IsGuard()) ai_factory = ai_registry.GetRegistryItem("GuardAI"); // select by permit check if (!ai_factory) { int best_val = PERMIT_BASE_NO; typedef CreatureAIRegistry::RegistryMapType RMT; RMT const& l = ai_registry.GetRegisteredItems(); for (RMT::const_iterator iter = l.begin(); iter != l.end(); ++iter) { const CreatureAICreator* factory = iter->second; const SelectableAI* p = dynamic_cast<const SelectableAI*>(factory); MANGOS_ASSERT(p != NULL); int val = p->Permit(creature); if (val > best_val) { best_val = val; ai_factory = p; } } } // select NullCreatureAI if not another cases ainame = (ai_factory == NULL) ? "NullCreatureAI" : ai_factory->key(); DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Creature %u used AI is %s.", creature->GetGUIDLow(), ainame.c_str()); return (ai_factory == NULL ? new NullCreatureAI(creature) : ai_factory->Create(creature)); }
uint8 BitStream::GetBit(uint32 bit) { MANGOS_ASSERT(_data.size() > bit); return _data[bit]; }
void WorldSession::HandleCalendarGetCalendar(WorldPacket& /*recv_data*/) { ObjectGuid guid = _player->GetObjectGuid(); DEBUG_LOG("WORLD: Received opcode CMSG_CALENDAR_GET_CALENDAR [%s]", guid.GetString().c_str()); time_t currTime = time(nullptr); WorldPacket data(SMSG_CALENDAR_SEND_CALENDAR); CalendarInvitesList invites; sCalendarMgr.GetPlayerInvitesList(guid, invites); data << uint32(invites.size()); DEBUG_FILTER_LOG(LOG_FILTER_CALENDAR, "Sending > %u invites", uint32(invites.size())); for (CalendarInvitesList::const_iterator itr = invites.begin(); itr != invites.end(); ++itr) { CalendarEvent const* event = (*itr)->GetCalendarEvent(); MANGOS_ASSERT(event); // TODO: be sure no way to have a null event data << uint64(event->EventId); data << uint64((*itr)->InviteId); data << uint8((*itr)->Status); data << uint8((*itr)->Rank); data << uint8(event->IsGuildEvent()); data << event->CreatorGuid.WriteAsPacked(); DEBUG_FILTER_LOG(LOG_FILTER_CALENDAR, "invite> EventId[" UI64FMTD "], InviteId[" UI64FMTD "], status[%u], rank[%u]", event->EventId, (*itr)->InviteId, uint32((*itr)->Status), uint32((*itr)->Rank)); } CalendarEventsList events; sCalendarMgr.GetPlayerEventsList(guid, events); data << uint32(events.size()); DEBUG_FILTER_LOG(LOG_FILTER_CALENDAR, "Sending > %u events", uint32(events.size())); for (CalendarEventsList::const_iterator itr = events.begin(); itr != events.end(); ++itr) { CalendarEvent const* event = *itr; data << uint64(event->EventId); data << event->Title; data << uint32(event->Type); data << secsToTimeBitFields(event->EventTime); data << uint32(event->Flags); data << int32(event->DungeonId); data << event->CreatorGuid.WriteAsPacked(); std::string timeStr = TimeToTimestampStr(event->EventTime); DEBUG_FILTER_LOG(LOG_FILTER_CALENDAR, "Events> EventId[" UI64FMTD "], Title[%s], Time[%s], Type[%u], Flag[%u], DungeonId[%d], CreatorGuid[%s]", event->EventId, event->Title.c_str(), timeStr.c_str(), uint32(event->Type), uint32(event->Flags), event->DungeonId, event->CreatorGuid.GetString().c_str()); } data << uint32(currTime); // server time data << secsToTimeBitFields(currTime); // zone time ?? ByteBuffer dataBuffer; uint32 boundCounter = 0; for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) { Player::BoundInstancesMap boundInstances = _player->GetBoundInstances(Difficulty(i)); for (Player::BoundInstancesMap::const_iterator itr = boundInstances.begin(); itr != boundInstances.end(); ++itr) { if (itr->second.perm) { DungeonPersistentState const* state = itr->second.state; dataBuffer << uint32(state->GetMapId()); dataBuffer << uint32(state->GetDifficulty()); dataBuffer << uint32(state->GetResetTime() - currTime); dataBuffer << uint64(state->GetInstanceId()); // instance save id as unique instance copy id ++boundCounter; } } } data << uint32(boundCounter); data.append(dataBuffer); data << uint32(1135753200); // Constant date, unk (28.12.2005 07:00) // Reuse variables boundCounter = 0; std::set<uint32> sentMaps; dataBuffer.clear(); for (MapDifficultyMap::const_iterator itr = sMapDifficultyMap.begin(); itr != sMapDifficultyMap.end(); ++itr) { uint32 map_diff_pair = itr->first; uint32 mapId = PAIR32_LOPART(map_diff_pair); Difficulty difficulty = Difficulty(PAIR32_HIPART(map_diff_pair)); MapDifficultyEntry const* mapDiff = itr->second; // skip mapDiff without global reset time if (!mapDiff->resetTime) continue; // skip non raid map MapEntry const* mapEntry = sMapStore.LookupEntry(mapId); if (!mapEntry || !mapEntry->IsRaid()) continue; // skip already sent map (not same difficulty?) if (sentMaps.find(mapId) != sentMaps.end()) continue; uint32 resetTime = sMapPersistentStateMgr.GetScheduler().GetMaxResetTimeFor(mapDiff); sentMaps.insert(mapId); dataBuffer << mapId; dataBuffer << resetTime; DEBUG_FILTER_LOG(LOG_FILTER_CALENDAR, "MapId [%u] -> Reset Time: %u", mapId, resetTime); dataBuffer << int32(0); // showed 68400 on map 509 must investigate more ++boundCounter; } DEBUG_FILTER_LOG(LOG_FILTER_CALENDAR, "Map sent [%u]", boundCounter); data << uint32(boundCounter); data.append(dataBuffer); // TODO: Fix this, how we do know how many and what holidays to send? uint32 holidayCount = 0; data << uint32(holidayCount); /*for (uint32 i = 0; i < holidayCount; ++i) { HolidaysEntry const* holiday = sHolidaysStore.LookupEntry(666); data << uint32(holiday->Id); // m_ID data << uint32(holiday->Region); // m_region, might be looping data << uint32(holiday->Looping); // m_looping, might be region data << uint32(holiday->Priority); // m_priority data << uint32(holiday->CalendarFilterType); // m_calendarFilterType for (uint8 j = 0; j < MAX_HOLIDAY_DATES; ++j) data << uint32(holiday->Date[j]); // 26 * m_date -- WritePackedTime ? for (uint8 j = 0; j < MAX_HOLIDAY_DURATIONS; ++j) data << uint32(holiday->Duration[j]); // 10 * m_duration for (uint8 j = 0; j < MAX_HOLIDAY_FLAGS; ++j) data << uint32(holiday->CalendarFlags[j]); // 10 * m_calendarFlags data << holiday->TextureFilename; // m_textureFilename (holiday name) }*/ SendPacket(&data); }
void BattleGroundAV::HandleQuestComplete(uint32 questid, Player* player) { if (GetStatus() != STATUS_IN_PROGRESS) return; BattleGroundAVTeamIndex teamIdx = GetAVTeamIndexByTeamId(player->GetBGTeam()); MANGOS_ASSERT(teamIdx != BG_AV_TEAM_NEUTRAL); uint32 reputation = 0; // reputation for the whole team (other reputation must be done in db) // TODO add events (including quest not available anymore, next quest availabe, go/npc de/spawning) sLog.outError("BattleGroundAV: Quest %i completed", questid); switch (questid) { case BG_AV_QUEST_A_SCRAPS1: case BG_AV_QUEST_A_SCRAPS2: case BG_AV_QUEST_H_SCRAPS1: case BG_AV_QUEST_H_SCRAPS2: m_Team_QuestStatus[teamIdx][0] += 20; reputation = 1; if (m_Team_QuestStatus[teamIdx][0] == 500 || m_Team_QuestStatus[teamIdx][0] == 1000 || m_Team_QuestStatus[teamIdx][0] == 1500) //25,50,75 turn ins { DEBUG_LOG("BattleGroundAV: Quest %i completed starting with unit upgrading..", questid); for (BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_FROSTWOLF_HUT; ++i) if (m_Nodes[i].Owner == teamIdx && m_Nodes[i].State == POINT_CONTROLLED) PopulateNode(i); } break; case BG_AV_QUEST_A_COMMANDER1: case BG_AV_QUEST_H_COMMANDER1: m_Team_QuestStatus[teamIdx][1]++; reputation = 1; if (m_Team_QuestStatus[teamIdx][1] == 120) DEBUG_LOG("BattleGroundAV: Quest %i completed (need to implement some events here", questid); break; case BG_AV_QUEST_A_COMMANDER2: case BG_AV_QUEST_H_COMMANDER2: m_Team_QuestStatus[teamIdx][2]++; reputation = 2; if (m_Team_QuestStatus[teamIdx][2] == 60) DEBUG_LOG("BattleGroundAV: Quest %i completed (need to implement some events here", questid); break; case BG_AV_QUEST_A_COMMANDER3: case BG_AV_QUEST_H_COMMANDER3: m_Team_QuestStatus[teamIdx][3]++; reputation = 5; if (m_Team_QuestStatus[teamIdx][1] == 30) DEBUG_LOG("BattleGroundAV: Quest %i completed (need to implement some events here", questid); break; case BG_AV_QUEST_A_BOSS1: case BG_AV_QUEST_H_BOSS1: m_Team_QuestStatus[teamIdx][4] += 4; // there are 2 quests where you can turn in 5 or 1 item.. ( + 4 cause +1 will be done some lines below) reputation = 4; case BG_AV_QUEST_A_BOSS2: case BG_AV_QUEST_H_BOSS2: m_Team_QuestStatus[teamIdx][4]++; reputation += 1; if (m_Team_QuestStatus[teamIdx][4] >= 200) DEBUG_LOG("BattleGroundAV: Quest %i completed (need to implement some events here", questid); break; case BG_AV_QUEST_A_NEAR_MINE: case BG_AV_QUEST_H_NEAR_MINE: m_Team_QuestStatus[teamIdx][5]++; reputation = 2; if (m_Team_QuestStatus[teamIdx][5] == 28) { DEBUG_LOG("BattleGroundAV: Quest %i completed (need to implement some events here", questid); if (m_Team_QuestStatus[teamIdx][6] == 7) DEBUG_LOG("BattleGroundAV: Quest %i completed (need to implement some events here - ground assault ready", questid); } break; case BG_AV_QUEST_A_OTHER_MINE: case BG_AV_QUEST_H_OTHER_MINE: m_Team_QuestStatus[teamIdx][6]++; reputation = 3; if (m_Team_QuestStatus[teamIdx][6] == 7) { DEBUG_LOG("BattleGroundAV: Quest %i completed (need to implement some events here", questid); if (m_Team_QuestStatus[teamIdx][5] == 20) DEBUG_LOG("BattleGroundAV: Quest %i completed (need to implement some events here - ground assault ready", questid); } break; case BG_AV_QUEST_A_RIDER_HIDE: case BG_AV_QUEST_H_RIDER_HIDE: m_Team_QuestStatus[teamIdx][7]++; reputation = 1; if (m_Team_QuestStatus[teamIdx][7] == 25) { DEBUG_LOG("BattleGroundAV: Quest %i completed (need to implement some events here", questid); if (m_Team_QuestStatus[teamIdx][8] == 25) DEBUG_LOG("BattleGroundAV: Quest %i completed (need to implement some events here - rider assault ready", questid); } break; case BG_AV_QUEST_A_RIDER_TAME: case BG_AV_QUEST_H_RIDER_TAME: m_Team_QuestStatus[teamIdx][8]++; reputation = 1; if (m_Team_QuestStatus[teamIdx][8] == 25) { DEBUG_LOG("BattleGroundAV: Quest %i completed (need to implement some events here", questid); if (m_Team_QuestStatus[teamIdx][7] == 25) DEBUG_LOG("BattleGroundAV: Quest %i completed (need to implement some events here - rider assault ready", questid); } break; default: DEBUG_LOG("BattleGroundAV: Quest %i completed but is not interesting for us", questid); return; break; } if (reputation) RewardReputationToTeam((player->GetBGTeam() == ALLIANCE) ? BG_AV_FACTION_A : BG_AV_FACTION_H, reputation, player->GetBGTeam()); }
void WaypointManager::Load() { Cleanup(); uint32 total_paths = 0; uint32 total_nodes = 0; uint32 total_behaviors = 0; std::set<uint32> movementScriptSet; for (ScriptMapMap::const_iterator itr = sCreatureMovementScripts.begin(); itr != sCreatureMovementScripts.end(); ++itr) movementScriptSet.insert(itr->first); // creature_movement QueryResult *result = WorldDatabase.Query("SELECT id, COUNT(point) FROM creature_movement GROUP BY id"); if (!result) { BarGoLink bar(1); bar.step(); sLog.outString(); sLog.outString(">> Loaded 0 paths. DB table `creature_movement` is empty."); } else { total_paths = (uint32)result->GetRowCount(); BarGoLink bar(total_paths); do { bar.step(); Field *fields = result->Fetch(); uint32 id = fields[0].GetUInt32(); uint32 count = fields[1].GetUInt32(); m_pathMap[id].resize(count); total_nodes += count; } while (result->NextRow()); sLog.outString(); sLog.outString(">> Paths loaded"); delete result; // 0 1 2 3 4 5 6 result = WorldDatabase.Query("SELECT id, point, position_x, position_y, position_z, waittime, script_id," // 7 8 9 10 11 12 13 14 15 16 "textid1, textid2, textid3, textid4, textid5, emote, spell, orientation, model1, model2 FROM creature_movement"); BarGoLink barRow((int)result->GetRowCount()); // error after load, we check if creature guid corresponding to the path id has proper MovementType std::set<uint32> creatureNoMoveType; do { barRow.step(); Field *fields = result->Fetch(); uint32 id = fields[0].GetUInt32(); uint32 point = fields[1].GetUInt32(); const CreatureData* cData = sObjectMgr.GetCreatureData(id); if (!cData) { sLog.outErrorDb("Table creature_movement contain path for creature guid %u, but this creature guid does not exist. Skipping.", id); continue; } if (cData->movementType != WAYPOINT_MOTION_TYPE) creatureNoMoveType.insert(id); WaypointPath &path = m_pathMap[id]; // the cleanup queries make sure the following is true MANGOS_ASSERT(point >= 1 && point <= path.size()); WaypointNode &node = path[point - 1]; node.x = fields[2].GetFloat(); node.y = fields[3].GetFloat(); node.z = fields[4].GetFloat(); node.orientation = fields[14].GetFloat(); node.delay = fields[5].GetUInt32(); node.script_id = fields[6].GetUInt32(); // prevent using invalid coordinates if (!MaNGOS::IsValidMapCoord(node.x, node.y, node.z, node.orientation)) { QueryResult *result1 = WorldDatabase.PQuery("SELECT id, map FROM creature WHERE guid = '%u'", id); if (result1) sLog.outErrorDb("Creature (guidlow %d, entry %d) have invalid coordinates in his waypoint %d (X: %f, Y: %f).", id, result1->Fetch()[0].GetUInt32(), point, node.x, node.y); else sLog.outErrorDb("Waypoint path %d, have invalid coordinates in his waypoint %d (X: %f, Y: %f).", id, point, node.x, node.y); MaNGOS::NormalizeMapCoord(node.x); MaNGOS::NormalizeMapCoord(node.y); if (result1) { node.z = sTerrainMgr.LoadTerrain(result1->Fetch()[1].GetUInt32())->GetHeightStatic(node.x, node.y, node.z); delete result1; } WorldDatabase.PExecute("UPDATE creature_movement SET position_x = '%f', position_y = '%f', position_z = '%f' WHERE id = '%u' AND point = '%u'", node.x, node.y, node.z, id, point); } if (node.script_id) { if (sCreatureMovementScripts.find(node.script_id) == sCreatureMovementScripts.end()) { sLog.outErrorDb("Table creature_movement for id %u, point %u have script_id %u that does not exist in `creature_movement_scripts`, ignoring", id, point, node.script_id); continue; } movementScriptSet.erase(node.script_id); } // WaypointBehavior can be dropped in time. Script_id added may 2010 and can handle all the below behavior. WaypointBehavior be; be.model1 = fields[15].GetUInt32(); be.model2 = fields[16].GetUInt32(); be.emote = fields[12].GetUInt32(); be.spell = fields[13].GetUInt32(); for (int i = 0; i < MAX_WAYPOINT_TEXT; ++i) { be.textid[i] = fields[7 + i].GetUInt32(); if (be.textid[i]) { if (be.textid[i] < MIN_DB_SCRIPT_STRING_ID || be.textid[i] >= MAX_DB_SCRIPT_STRING_ID) { sLog.outErrorDb("Table `db_script_string` not have string id %u", be.textid[i]); continue; } } } if (be.spell && ! sSpellMgr.GetSpellEntry(be.spell)) { sLog.outErrorDb("Table creature_movement references unknown spellid %u. Skipping id %u with point %u.", be.spell, id, point); be.spell = 0; } if (be.emote) { if (!sEmotesStore.LookupEntry(be.emote)) sLog.outErrorDb("Waypoint path %u (Point %u) are using emote %u, but emote does not exist.", id, point, be.emote); } // save memory by not storing empty behaviors if (!be.isEmpty()) { node.behavior = new WaypointBehavior(be); ++total_behaviors; } else node.behavior = NULL; } while (result->NextRow()); if (!creatureNoMoveType.empty()) { for (std::set<uint32>::const_iterator itr = creatureNoMoveType.begin(); itr != creatureNoMoveType.end(); ++itr) { const CreatureData* cData = sObjectMgr.GetCreatureData(*itr); const CreatureInfo* cInfo = ObjectMgr::GetCreatureTemplate(cData->id); sLog.outErrorDb("Table creature_movement has waypoint for creature guid %u (entry %u), but MovementType is not WAYPOINT_MOTION_TYPE(2). Creature will not use this path.", *itr, cData->id); if (cInfo->MovementType == WAYPOINT_MOTION_TYPE) sLog.outErrorDb(" creature_template for this entry has MovementType WAYPOINT_MOTION_TYPE(2), did you intend to use creature_movement_template ?"); } } sLog.outString(); sLog.outString(">> Waypoints and behaviors loaded"); sLog.outString(); sLog.outString(">>> Loaded %u paths, %u nodes and %u behaviors", total_paths, total_nodes, total_behaviors); delete result; } // creature_movement_template result = WorldDatabase.Query("SELECT entry, COUNT(point) FROM creature_movement_template GROUP BY entry"); if (!result) { BarGoLink bar(1); bar.step(); sLog.outString(); sLog.outString(">> Loaded 0 path templates. DB table `creature_movement_template` is empty."); } else { total_nodes = 0; total_behaviors = 0; total_paths = (uint32)result->GetRowCount(); BarGoLink barRow(total_paths); do { barRow.step(); Field *fields = result->Fetch(); uint32 entry = fields[0].GetUInt32(); uint32 count = fields[1].GetUInt32(); m_pathTemplateMap[entry].resize(count); total_nodes += count; } while (result->NextRow()); delete result; sLog.outString(); sLog.outString(">> Path templates loaded"); // 0 1 2 3 4 5 6 result = WorldDatabase.Query("SELECT entry, point, position_x, position_y, position_z, waittime, script_id," // 7 8 9 10 11 12 13 14 15 16 "textid1, textid2, textid3, textid4, textid5, emote, spell, orientation, model1, model2 FROM creature_movement_template"); BarGoLink bar(result->GetRowCount()); do { bar.step(); Field *fields = result->Fetch(); uint32 entry = fields[0].GetUInt32(); uint32 point = fields[1].GetUInt32(); const CreatureInfo* cInfo = ObjectMgr::GetCreatureTemplate(entry); if (!cInfo) { sLog.outErrorDb("Table creature_movement_template references unknown creature template %u. Skipping.", entry); continue; } WaypointPath &path = m_pathTemplateMap[entry]; // the cleanup queries make sure the following is true MANGOS_ASSERT(point >= 1 && point <= path.size()); WaypointNode &node = path[point - 1]; node.x = fields[2].GetFloat(); node.y = fields[3].GetFloat(); node.z = fields[4].GetFloat(); node.orientation = fields[14].GetFloat(); node.delay = fields[5].GetUInt32(); node.script_id = fields[6].GetUInt32(); // prevent using invalid coordinates if (!MaNGOS::IsValidMapCoord(node.x, node.y, node.z, node.orientation)) { sLog.outErrorDb("Table creature_movement_template for entry %u (point %u) are using invalid coordinates position_x: %f, position_y: %f)", entry, point, node.x, node.y); MaNGOS::NormalizeMapCoord(node.x); MaNGOS::NormalizeMapCoord(node.y); sLog.outErrorDb("Table creature_movement_template for entry %u (point %u) are auto corrected to normalized position_x=%f, position_y=%f", entry, point, node.x, node.y); WorldDatabase.PExecute("UPDATE creature_movement_template SET position_x = '%f', position_y = '%f' WHERE entry = %u AND point = %u", node.x, node.y, entry, point); } if (node.script_id) { if (sCreatureMovementScripts.find(node.script_id) == sCreatureMovementScripts.end()) { sLog.outErrorDb("Table creature_movement_template for entry %u, point %u have script_id %u that does not exist in `creature_movement_scripts`, ignoring", entry, point, node.script_id); continue; } movementScriptSet.erase(node.script_id); } WaypointBehavior be; be.model1 = fields[15].GetUInt32(); be.model2 = fields[16].GetUInt32(); be.emote = fields[12].GetUInt32(); be.spell = fields[13].GetUInt32(); for (int i = 0; i < MAX_WAYPOINT_TEXT; ++i) { be.textid[i] = fields[7 + i].GetUInt32(); if (be.textid[i]) { if (be.textid[i] < MIN_DB_SCRIPT_STRING_ID || be.textid[i] >= MAX_DB_SCRIPT_STRING_ID) { sLog.outErrorDb("Table `db_script_string` not have string id %u", be.textid[i]); continue; } } } if (be.spell && ! sSpellMgr.GetSpellEntry(be.spell)) { sLog.outErrorDb("Table creature_movement_template references unknown spellid %u. Skipping id %u with point %u.", be.spell, entry, point); be.spell = 0; } if (be.emote) { if (!sEmotesStore.LookupEntry(be.emote)) sLog.outErrorDb("Waypoint template path %u (point %u) are using emote %u, but emote does not exist.", entry, point, be.emote); } // save memory by not storing empty behaviors if (!be.isEmpty()) { node.behavior = new WaypointBehavior(be); ++total_behaviors; } else node.behavior = NULL; } while (result->NextRow()); delete result; sLog.outString(); sLog.outString(">> Waypoint templates loaded"); sLog.outString(); sLog.outString(">>> Loaded %u path templates with %u nodes and %u behaviors", total_paths, total_nodes, total_behaviors); } if (!movementScriptSet.empty()) { for (std::set<uint32>::const_iterator itr = movementScriptSet.begin(); itr != movementScriptSet.end(); ++itr) sLog.outErrorDb("Table `creature_movement_scripts` contain unused script, id %u.", *itr); } }
/** * This function will board a passenger onto a vehicle * * @param passenger MUST be provided. This Unit will be boarded onto the vehicles (if it checks out) * @param seat Seat to which the passenger will be boarded (if can, elsewise an alternative will be selected if possible) */ void VehicleInfo::Board(Unit* passenger, uint8 seat) { MANGOS_ASSERT(passenger); DEBUG_LOG("VehicleInfo(of %s)::Board: Try to board passenger %s to seat %u", m_owner->GetGuidStr().c_str(), passenger->GetGuidStr().c_str(), seat); // This check is also called in Spell::CheckCast() if (!CanBoard(passenger)) return; // Use the planned seat only if the seat is valid, possible to choose and empty if (!IsSeatAvailableFor(passenger, seat)) if (!GetUsableSeatFor(passenger, seat)) return; VehicleSeatEntry const* seatEntry = GetSeatEntry(seat); MANGOS_ASSERT(seatEntry); // ToDo: Unboard passenger from a MOTransport when they are properly implemented /*if (TransportInfo* transportInfo = passenger->GetTransportInfo()) { WorldObject* transporter = transportInfo->GetTransport(); // Must be a MO transporter MANGOS_ASSERT(transporter->GetObjectGuid().IsMOTransport()); ((Transport*)transporter)->UnBoardPassenger(passenger); }*/ DEBUG_LOG("VehicleInfo::Board: Board passenger: %s to seat %u", passenger->GetGuidStr().c_str(), seat); // Calculate passengers local position float lx, ly, lz, lo; CalculateBoardingPositionOf(passenger->GetPositionX(), passenger->GetPositionY(), passenger->GetPositionZ(), passenger->GetOrientation(), lx, ly, lz, lo); BoardPassenger(passenger, lx, ly, lz, lo, seat); // Use TransportBase to store the passenger // Set data for createobject packets passenger->m_movementInfo.AddMovementFlag(MOVEFLAG_ONTRANSPORT); passenger->m_movementInfo.SetTransportData(m_owner->GetObjectGuid(), lx, ly, lz, lo, 0, seat); if (passenger->GetTypeId() == TYPEID_PLAYER) { Player* pPlayer = (Player*)passenger; pPlayer->RemovePet(PET_SAVE_AS_CURRENT); WorldPacket data(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA); pPlayer->GetSession()->SendPacket(&data); // SMSG_BREAK_TARGET (?) } if (!passenger->IsRooted()) passenger->SetRoot(true); Movement::MoveSplineInit init(*passenger); init.MoveTo(0.0f, 0.0f, 0.0f); // ToDo: Set correct local coords init.SetFacing(0.0f); // local orientation ? ToDo: Set proper orientation! init.SetBoardVehicle(); init.Launch(); // Apply passenger modifications ApplySeatMods(passenger, seatEntry->m_flags); }
dtStatus PathInfo::findSmoothPath(const float* startPos, const float* endPos, const dtPolyRef* polyPath, const uint32 polyPathSize, float* smoothPath, int* smoothPathSize, bool &usedOffmesh, const uint32 maxSmoothPathSize) { MANGOS_ASSERT(polyPathSize <= MAX_PATH_LENGTH); *smoothPathSize = 0; uint32 nsmoothPath = 0; usedOffmesh = false; dtPolyRef polys[MAX_PATH_LENGTH]; memcpy(polys, polyPath, sizeof(dtPolyRef)*polyPathSize); uint32 npolys = polyPathSize; float iterPos[VERTEX_SIZE], targetPos[VERTEX_SIZE]; if(DT_SUCCESS != m_navMeshQuery->closestPointOnPolyBoundary(polys[0], startPos, iterPos)) return DT_FAILURE; if(DT_SUCCESS != m_navMeshQuery->closestPointOnPolyBoundary(polys[npolys-1], endPos, targetPos)) return DT_FAILURE; dtVcopy(&smoothPath[nsmoothPath*VERTEX_SIZE], iterPos); nsmoothPath++; // Move towards target a small advancement at a time until target reached or // when ran out of memory to store the path. while (npolys && nsmoothPath < maxSmoothPathSize) { // Find location to steer towards. float steerPos[VERTEX_SIZE]; unsigned char steerPosFlag; dtPolyRef steerPosRef = INVALID_POLYREF; if (!getSteerTarget(iterPos, targetPos, SMOOTH_PATH_SLOP, polys, npolys, steerPos, steerPosFlag, steerPosRef)) break; bool endOfPath = (steerPosFlag & DT_STRAIGHTPATH_END); bool offMeshConnection = (steerPosFlag & DT_STRAIGHTPATH_OFFMESH_CONNECTION); // Find movement delta. float delta[VERTEX_SIZE]; dtVsub(delta, steerPos, iterPos); float len = dtSqrt(dtVdot(delta,delta)); // If the steer target is end of path or off-mesh link, do not move past the location. if ((endOfPath || offMeshConnection) && len < SMOOTH_PATH_STEP_SIZE) len = 1.0f; else len = SMOOTH_PATH_STEP_SIZE / len; float moveTgt[VERTEX_SIZE]; dtVmad(moveTgt, iterPos, delta, len); // Move float result[VERTEX_SIZE]; const static uint32 MAX_VISIT_POLY = 16; dtPolyRef visited[MAX_VISIT_POLY]; uint32 nvisited = 0; m_navMeshQuery->moveAlongSurface(polys[0], iterPos, moveTgt, &m_filter, result, visited, (int*)&nvisited, MAX_VISIT_POLY); npolys = fixupCorridor(polys, npolys, MAX_PATH_LENGTH, visited, nvisited); m_navMeshQuery->getPolyHeight(polys[0], result, &result[1]); dtVcopy(iterPos, result); // Handle end of path and off-mesh links when close enough. if (endOfPath && inRangeYZX(iterPos, steerPos, SMOOTH_PATH_SLOP, 2.0f)) { // Reached end of path. dtVcopy(iterPos, targetPos); if (nsmoothPath < maxSmoothPathSize) { dtVcopy(&smoothPath[nsmoothPath*VERTEX_SIZE], iterPos); nsmoothPath++; } break; } else if (offMeshConnection && inRangeYZX(iterPos, steerPos, SMOOTH_PATH_SLOP, 2.0f)) { // Reached off-mesh connection. usedOffmesh = true; // Advance the path up to and over the off-mesh connection. dtPolyRef prevRef = INVALID_POLYREF; dtPolyRef polyRef = polys[0]; uint32 npos = 0; while (npos < npolys && polyRef != steerPosRef) { prevRef = polyRef; polyRef = polys[npos]; npos++; } for (uint32 i = npos; i < npolys; ++i) polys[i-npos] = polys[i]; npolys -= npos; // Handle the connection. float startPos[VERTEX_SIZE], endPos[VERTEX_SIZE]; if (DT_SUCCESS == m_navMesh->getOffMeshConnectionPolyEndPoints(prevRef, polyRef, startPos, endPos)) { if (nsmoothPath < maxSmoothPathSize) { dtVcopy(&smoothPath[nsmoothPath*VERTEX_SIZE], startPos); nsmoothPath++; } // Move position at the other side of the off-mesh link. dtVcopy(iterPos, endPos); m_navMeshQuery->getPolyHeight(polys[0], iterPos, &iterPos[1]); } } // Store results. if (nsmoothPath < maxSmoothPathSize) { dtVcopy(&smoothPath[nsmoothPath*VERTEX_SIZE], iterPos); nsmoothPath++; } } *smoothPathSize = nsmoothPath; // this is most likely loop return nsmoothPath < maxSmoothPathSize ? DT_SUCCESS : DT_FAILURE; }
/** * This function will Unboard a passenger * * @param passenger MUST be provided. This Unit will be unboarded from the vehicle * @param changeVehicle If set, the passenger is expected to be directly boarded to another vehicle, * and hence he will not be unboarded but only removed from this vehicle. */ void VehicleInfo::UnBoard(Unit* passenger, bool changeVehicle) { MANGOS_ASSERT(passenger); DEBUG_LOG("VehicleInfo::Unboard: passenger: %s", passenger->GetGuidStr().c_str()); PassengerMap::const_iterator itr = m_passengers.find(passenger); MANGOS_ASSERT(itr != m_passengers.end()); VehicleSeatEntry const* seatEntry = GetSeatEntry(itr->second->GetTransportSeat()); MANGOS_ASSERT(seatEntry); UnBoardPassenger(passenger); // Use TransportBase to remove the passenger from storage list if (!changeVehicle) // Send expected unboarding packages { // Update movementInfo passenger->m_movementInfo.RemoveMovementFlag(MOVEFLAG_ONTRANSPORT); passenger->m_movementInfo.ClearTransportData(); if (passenger->GetTypeId() == TYPEID_PLAYER) { Player* pPlayer = (Player*)passenger; pPlayer->ResummonPetTemporaryUnSummonedIfAny(); // SMSG_PET_DISMISS_SOUND (?) } if (passenger->IsRooted()) passenger->SetRoot(false); Movement::MoveSplineInit init(*passenger); // ToDo: Set proper unboard coordinates init.MoveTo(m_owner->GetPositionX(), m_owner->GetPositionY(), m_owner->GetPositionZ()); init.SetExitVehicle(); init.Launch(); // Despawn if passenger was accessory if (passenger->GetTypeId() == TYPEID_UNIT && m_accessoryGuids.find(passenger->GetObjectGuid()) != m_accessoryGuids.end()) { Creature* cPassenger = static_cast<Creature*>(passenger); // TODO Same TODO as in VehicleInfo::RemoveAccessoriesFromMap cPassenger->ForcedDespawn(5000); m_accessoryGuids.erase(passenger->GetObjectGuid()); } } // Remove passenger modifications RemoveSeatMods(passenger, seatEntry->m_flags); // Some creature vehicles get despawned after passenger unboarding if (m_owner->GetTypeId() == TYPEID_UNIT) { // TODO: Guesswork, but seems to be fairly near correct // Only if the passenger was on control seat? Also depending on some flags if ((seatEntry->m_flags & SEAT_FLAG_CAN_CONTROL) && !(m_vehicleEntry->m_flags & (VEHICLE_FLAG_UNK4 | VEHICLE_FLAG_UNK20))) { if (((Creature*)m_owner)->IsTemporarySummon()) ((Creature*)m_owner)->ForcedDespawn(1000); } } }
inline void LoadDBC(LocalData& localeData, BarGoLink& bar, StoreProblemList& errlist, DBCStorage<T>& storage, const std::string& dbc_path, const std::string& filename) { // compatibility format and C++ structure sizes MANGOS_ASSERT(DBCFileLoader::GetFormatRecordSize(storage.GetFormat()) == sizeof(T) || LoadDBC_assert_print(DBCFileLoader::GetFormatRecordSize(storage.GetFormat()),sizeof(T),filename)); std::string dbc_filename = dbc_path + filename; if(storage.Load(dbc_filename.c_str())) { bar.step(); for(uint8 i = 0; fullLocaleNameList[i].name; ++i) { if (!(localeData.availableDbcLocales & (1 << i))) continue; LocaleNameStr const* localStr = &fullLocaleNameList[i]; std::string dbc_dir_loc = dbc_path + localStr->name + "/"; if (!(localeData.checkedDbcLocaleBuilds & (1 << i))) { localeData.checkedDbcLocaleBuilds |= (1<<i);// mark as checked for speedup next checks uint32 build_loc = ReadDBCBuild(dbc_dir_loc,localStr); if(localeData.main_build != build_loc) { localeData.availableDbcLocales &= ~(1<<i); // mark as not available for speedup next checks // exist but wrong build if (build_loc) { std::string dbc_filename_loc = dbc_path + localStr->name + "/" + filename; char buf[200]; snprintf(buf,200," (exist, but DBC locale subdir %s have DBCs for build %u instead expected build %u, it and other DBC from subdir skipped)",localStr->name,build_loc,localeData.main_build); errlist.push_back(dbc_filename_loc + buf); } continue; } } std::string dbc_filename_loc = dbc_path + localStr->name + "/" + filename; if(!storage.LoadStringsFrom(dbc_filename_loc.c_str())) localeData.availableDbcLocales &= ~(1<<i); // mark as not available for speedup next checks } } else { // sort problematic dbc to (1) non compatible and (2) nonexistent FILE * f=fopen(dbc_filename.c_str(),"rb"); if(f) { char buf[100]; snprintf(buf,100," (exist, but have %d fields instead " SIZEFMTD ") Wrong client version DBC file?",storage.GetFieldCount(),strlen(storage.GetFormat())); errlist.push_back(dbc_filename + buf); fclose(f); } else errlist.push_back(dbc_filename); } }
TransportBase::~TransportBase() { MANGOS_ASSERT(m_passengers.size() == 0); }
/** * What - if any - kind of explanation mark or question-mark should a quest-giver display for a player * @param pPlayer - for whom * @param questgiver - from whom * @param defstatus - initial set status (usually it will be called with DIALOG_STATUS_NONE) - must not be DIALOG_STATUS_UNDEFINED */ uint32 WorldSession::getDialogStatus(Player* pPlayer, Object* questgiver, uint32 defstatus) { MANGOS_ASSERT(defstatus != DIALOG_STATUS_UNDEFINED); uint32 dialogStatus = defstatus; QuestRelationsMapBounds rbounds; // QuestRelations (quest-giver) QuestRelationsMapBounds irbounds; // InvolvedRelations (quest-finisher) switch (questgiver->GetTypeId()) { case TYPEID_UNIT: { rbounds = sObjectMgr.GetCreatureQuestRelationsMapBounds(questgiver->GetEntry()); irbounds = sObjectMgr.GetCreatureQuestInvolvedRelationsMapBounds(questgiver->GetEntry()); break; } case TYPEID_GAMEOBJECT: { rbounds = sObjectMgr.GetGOQuestRelationsMapBounds(questgiver->GetEntry()); irbounds = sObjectMgr.GetGOQuestInvolvedRelationsMapBounds(questgiver->GetEntry()); break; } default: // it's impossible, but check ^) sLog.outError("Warning: GetDialogStatus called for unexpected type %u", questgiver->GetTypeId()); return DIALOG_STATUS_NONE; } // Check markings for quest-finisher for (QuestRelationsMap::const_iterator itr = irbounds.first; itr != irbounds.second; ++itr) { uint32 dialogStatusNew = DIALOG_STATUS_NONE; uint32 quest_id = itr->second; Quest const* pQuest = sObjectMgr.GetQuestTemplate(quest_id); if (!pQuest || !pQuest->IsActive()) continue; QuestStatus status = pPlayer->GetQuestStatus(quest_id); if (status == QUEST_STATUS_COMPLETE && !pPlayer->GetQuestRewardStatus(quest_id)) dialogStatusNew = pQuest->IsRepeatable() ? DIALOG_STATUS_REWARD_REP : DIALOG_STATUS_REWARD; else if (pQuest->IsAutoComplete() && pPlayer->CanTakeQuest(pQuest, false)) dialogStatusNew = pQuest->IsRepeatable() ? DIALOG_STATUS_AVAILABLE_REP : DIALOG_STATUS_AVAILABLE; else if (status == QUEST_STATUS_INCOMPLETE) dialogStatusNew = DIALOG_STATUS_INCOMPLETE; if (dialogStatusNew > dialogStatus) dialogStatus = dialogStatusNew; } // check markings for quest-giver for (QuestRelationsMap::const_iterator itr = rbounds.first; itr != rbounds.second; ++itr) { uint32 dialogStatusNew = DIALOG_STATUS_NONE; uint32 quest_id = itr->second; Quest const* pQuest = sObjectMgr.GetQuestTemplate(quest_id); if (!pQuest || !pQuest->IsActive()) continue; QuestStatus status = pPlayer->GetQuestStatus(quest_id); if (status == QUEST_STATUS_NONE) // For all other cases the mark is handled either at some place else, or with involved-relations already { if (pPlayer->CanSeeStartQuest(pQuest)) { if (pPlayer->SatisfyQuestLevel(pQuest, false)) { int32 lowLevelDiff = sWorld.getConfig(CONFIG_INT32_QUEST_LOW_LEVEL_HIDE_DIFF); if (pQuest->IsAutoComplete() || (pQuest->IsRepeatable() && pPlayer->getQuestStatusMap()[quest_id].m_rewarded)) { dialogStatusNew = DIALOG_STATUS_REWARD_REP; } else if (lowLevelDiff < 0 || pPlayer->getLevel() <= pPlayer->GetQuestLevelForPlayer(pQuest) + uint32(lowLevelDiff)) { if (pQuest->HasQuestFlag(QUEST_FLAGS_DAILY) || pQuest->HasQuestFlag(QUEST_FLAGS_WEEKLY)) dialogStatusNew = DIALOG_STATUS_AVAILABLE_REP; else dialogStatusNew = DIALOG_STATUS_AVAILABLE; } else dialogStatusNew = DIALOG_STATUS_CHAT; } else dialogStatusNew = DIALOG_STATUS_UNAVAILABLE; } } if (dialogStatusNew > dialogStatus) dialogStatus = dialogStatusNew; } return dialogStatus; }
int WorldSocket::handle_input_missing_data(void) { char buf [4096]; ACE_Data_Block db(sizeof(buf), ACE_Message_Block::MB_DATA, buf, 0, 0, ACE_Message_Block::DONT_DELETE, 0); ACE_Message_Block message_block(&db, ACE_Message_Block::DONT_DELETE, 0); const size_t recv_size = message_block.space(); const ssize_t n = peer().recv(message_block.wr_ptr(), recv_size); if (n <= 0) return (int)n; message_block.wr_ptr(n); while (message_block.length() > 0) { if (m_Header.space() > 0) { // need to receive the header const size_t to_header = (message_block.length() > m_Header.space() ? m_Header.space() : message_block.length()); m_Header.copy(message_block.rd_ptr(), to_header); message_block.rd_ptr(to_header); if (m_Header.space() > 0) { // Couldn't receive the whole header this time. MANGOS_ASSERT(message_block.length() == 0); errno = EWOULDBLOCK; return -1; } // We just received nice new header if (handle_input_header() == -1) { MANGOS_ASSERT((errno != EWOULDBLOCK) && (errno != EAGAIN)); return -1; } } // Its possible on some error situations that this happens // for example on closing when epoll receives more chunked data and stuff // hope this is not hack ,as proper m_RecvWPct is asserted around if (!m_RecvWPct) { sLog.outError("Forcing close on input m_RecvWPct = NULL"); errno = EINVAL; return -1; } // We have full read header, now check the data payload if (m_RecvPct.space() > 0) { // need more data in the payload const size_t to_data = (message_block.length() > m_RecvPct.space() ? m_RecvPct.space() : message_block.length()); m_RecvPct.copy(message_block.rd_ptr(), to_data); message_block.rd_ptr(to_data); if (m_RecvPct.space() > 0) { // Couldn't receive the whole data this time. MANGOS_ASSERT(message_block.length() == 0); errno = EWOULDBLOCK; return -1; } } // just received fresh new payload if (handle_input_payload() == -1) { MANGOS_ASSERT((errno != EWOULDBLOCK) && (errno != EAGAIN)); return -1; } } return size_t(n) == recv_size ? 1 : 2; }
void PathFinder::BuildPolyPath(const Vector3& startPos, const Vector3& endPos) { // *** getting start/end poly logic *** float distToStartPoly, distToEndPoly; float startPoint[VERTEX_SIZE] = {startPos.y, startPos.z, startPos.x}; float endPoint[VERTEX_SIZE] = {endPos.y, endPos.z, endPos.x}; dtPolyRef startPoly = getPolyByLocation(startPoint, &distToStartPoly); dtPolyRef endPoly = getPolyByLocation(endPoint, &distToEndPoly); dtStatus dtResult; // we have a hole in our mesh // make shortcut path and mark it as NOPATH ( with flying exception ) // its up to caller how he will use this info if (startPoly == INVALID_POLYREF || endPoly == INVALID_POLYREF) { DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: (startPoly == 0 || endPoly == 0)\n"); BuildShortcut(); if (m_sourceUnit->GetTypeId() == TYPEID_UNIT) { // Check for swimming or flying shortcut if ((startPoly == INVALID_POLYREF && m_sourceUnit->GetTerrain()->IsUnderWater(startPos.x, startPos.y, startPos.z)) || (endPoly == INVALID_POLYREF && m_sourceUnit->GetTerrain()->IsUnderWater(endPos.x, endPos.y, endPos.z))) m_type = ((Creature*)m_sourceUnit)->CanSwim() ? PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH) : PATHFIND_NOPATH; else m_type = ((Creature*)m_sourceUnit)->CanFly() ? PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH) : PATHFIND_NOPATH; } else m_type = PATHFIND_NOPATH; return; } // we may need a better number here bool farFromPoly = (distToStartPoly > 7.0f || distToEndPoly > 7.0f); if (farFromPoly) { DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: farFromPoly distToStartPoly=%.3f distToEndPoly=%.3f\n", distToStartPoly, distToEndPoly); bool buildShotrcut = false; if (m_sourceUnit->GetTypeId() == TYPEID_UNIT) { Creature* owner = (Creature*)m_sourceUnit; Vector3 p = (distToStartPoly > 7.0f) ? startPos : endPos; if (m_sourceUnit->GetTerrain()->IsUnderWater(p.x, p.y, p.z)) { DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: underWater case\n"); if (owner->CanSwim()) buildShotrcut = true; } else { DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: flying case\n"); if (owner->CanFly()) buildShotrcut = true; } } if (buildShotrcut) { BuildShortcut(); m_type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH); return; } else { float closestPoint[VERTEX_SIZE]; // we may want to use closestPointOnPolyBoundary instead dtResult = m_navMeshQuery->closestPointOnPoly(endPoly, endPoint, closestPoint, nullptr); if (dtStatusSucceed(dtResult)) { dtVcopy(endPoint, closestPoint); setActualEndPosition(Vector3(endPoint[2], endPoint[0], endPoint[1])); } m_type = PATHFIND_INCOMPLETE; } } // *** poly path generating logic *** // start and end are on same polygon // just need to move in straight line if (startPoly == endPoly) { DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: (startPoly == endPoly)\n"); BuildShortcut(); m_pathPolyRefs[0] = startPoly; m_polyLength = 1; m_type = farFromPoly ? PATHFIND_INCOMPLETE : PATHFIND_NORMAL; DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: path type %d\n", m_type); return; } // look for startPoly/endPoly in current path // TODO: we can merge it with getPathPolyByPosition() loop bool startPolyFound = false; bool endPolyFound = false; uint32 pathStartIndex, pathEndIndex; if (m_polyLength) { for (pathStartIndex = 0; pathStartIndex < m_polyLength; ++pathStartIndex) { // here to catch few bugs MANGOS_ASSERT(m_pathPolyRefs[pathStartIndex] != INVALID_POLYREF || m_sourceUnit->PrintEntryError("PathFinder::BuildPolyPath")); if (m_pathPolyRefs[pathStartIndex] == startPoly) { startPolyFound = true; break; } } for (pathEndIndex = m_polyLength - 1; pathEndIndex > pathStartIndex; --pathEndIndex) if (m_pathPolyRefs[pathEndIndex] == endPoly) { endPolyFound = true; break; } } if (startPolyFound && endPolyFound) { DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: (startPolyFound && endPolyFound)\n"); // we moved along the path and the target did not move out of our old poly-path // our path is a simple subpath case, we have all the data we need // just "cut" it out m_polyLength = pathEndIndex - pathStartIndex + 1; memmove(m_pathPolyRefs, m_pathPolyRefs + pathStartIndex, m_polyLength * sizeof(dtPolyRef)); } else if (startPolyFound && !endPolyFound) { DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: (startPolyFound && !endPolyFound)\n"); // we are moving on the old path but target moved out // so we have atleast part of poly-path ready m_polyLength -= pathStartIndex; // try to adjust the suffix of the path instead of recalculating entire length // at given interval the target cannot get too far from its last location // thus we have less poly to cover // sub-path of optimal path is optimal // take ~80% of the original length // TODO : play with the values here uint32 prefixPolyLength = uint32(m_polyLength * 0.8f + 0.5f); memmove(m_pathPolyRefs, m_pathPolyRefs + pathStartIndex, prefixPolyLength * sizeof(dtPolyRef)); dtPolyRef suffixStartPoly = m_pathPolyRefs[prefixPolyLength - 1]; // we need any point on our suffix start poly to generate poly-path, so we need last poly in prefix data float suffixEndPoint[VERTEX_SIZE]; dtResult = m_navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint, nullptr); if (dtStatusFailed(dtResult)) { // we can hit offmesh connection as last poly - closestPointOnPoly() don't like that // try to recover by using prev polyref --prefixPolyLength; suffixStartPoly = m_pathPolyRefs[prefixPolyLength - 1]; dtResult = m_navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint, nullptr); if (dtStatusFailed(dtResult)) { // suffixStartPoly is still invalid, error state BuildShortcut(); m_type = PATHFIND_NOPATH; return; } } // generate suffix uint32 suffixPolyLength = 0; dtResult = m_navMeshQuery->findPath( suffixStartPoly, // start polygon endPoly, // end polygon suffixEndPoint, // start position endPoint, // end position &m_filter, // polygon search filter m_pathPolyRefs + prefixPolyLength - 1, // [out] path (int*)&suffixPolyLength, MAX_PATH_LENGTH - prefixPolyLength); // max number of polygons in output path if (!suffixPolyLength || dtStatusFailed(dtResult)) { // this is probably an error state, but we'll leave it // and hopefully recover on the next Update // we still need to copy our preffix sLog.outError("%u's Path Build failed: 0 length path", m_sourceUnit->GetGUIDLow()); } DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ m_polyLength=%u prefixPolyLength=%u suffixPolyLength=%u \n", m_polyLength, prefixPolyLength, suffixPolyLength); // new path = prefix + suffix - overlap m_polyLength = prefixPolyLength + suffixPolyLength - 1; } else { DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: (!startPolyFound && !endPolyFound)\n"); // either we have no path at all -> first run // or something went really wrong -> we aren't moving along the path to the target // just generate new path // free and invalidate old path data clear(); dtResult = m_navMeshQuery->findPath( startPoly, // start polygon endPoly, // end polygon startPoint, // start position endPoint, // end position &m_filter, // polygon search filter m_pathPolyRefs, // [out] path (int*)&m_polyLength, MAX_PATH_LENGTH); // max number of polygons in output path if (!m_polyLength || dtStatusFailed(dtResult)) { // only happens if we passed bad data to findPath(), or navmesh is messed up sLog.outError("%u's Path Build failed: 0 length path", m_sourceUnit->GetGUIDLow()); BuildShortcut(); m_type = PATHFIND_NOPATH; return; } } // by now we know what type of path we can get if (m_pathPolyRefs[m_polyLength - 1] == endPoly && !(m_type & PATHFIND_INCOMPLETE)) m_type = PATHFIND_NORMAL; else m_type = PATHFIND_INCOMPLETE; // generate the point-path out of our up-to-date poly-path BuildPointPath(startPoint, endPoint); }
int WorldSocket::ProcessIncoming(WorldPacket* new_pct) { MANGOS_ASSERT(new_pct); // manage memory ;) ACE_Auto_Ptr<WorldPacket> aptr(new_pct); const ACE_UINT16 opcode = new_pct->GetOpcode(); if (opcode >= NUM_MSG_TYPES) { sLog.outError("SESSION: received nonexistent opcode 0x%.4X", opcode); return -1; } if (closing_) return -1; // Dump received packet. sLog.outWorldPacketDump(uint32(get_handle()), new_pct->GetOpcode(), LookupOpcodeName(new_pct->GetOpcode()), new_pct, true); try { switch (opcode) { case CMSG_PING: return HandlePing(*new_pct); case CMSG_AUTH_SESSION: if (m_Session) { sLog.outError("WorldSocket::ProcessIncoming: Player send CMSG_AUTH_SESSION again"); return -1; } return HandleAuthSession(*new_pct); case CMSG_KEEP_ALIVE: DEBUG_LOG("CMSG_KEEP_ALIVE ,size: " SIZEFMTD " ", new_pct->size()); return 0; default: { ACE_GUARD_RETURN(LockType, Guard, m_SessionLock, -1); if (m_Session != NULL) { // OK ,give the packet to WorldSession aptr.release(); // WARNING here we call it with locks held. // Its possible to cause deadlock if QueuePacket calls back m_Session->QueuePacket(new_pct); return 0; } else { sLog.outError("WorldSocket::ProcessIncoming: Client not authed opcode = %u", uint32(opcode)); return -1; } } } } catch (ByteBufferException&) { sLog.outError("WorldSocket::ProcessIncoming ByteBufferException occured while parsing an instant handled packet (opcode: %u) from client %s, accountid=%i.", opcode, GetRemoteAddress().c_str(), m_Session ? m_Session->GetAccountId() : -1); if (sLog.HasLogLevelOrHigher(LOG_LVL_DEBUG)) { DEBUG_LOG("Dumping error-causing packet:"); new_pct->hexlike(); } if (sWorld.getConfig(CONFIG_BOOL_KICK_PLAYER_ON_BAD_PACKET)) { DETAIL_LOG("Disconnecting session [account id %i / address %s] for badly formatted packet.", m_Session ? m_Session->GetAccountId() : -1, GetRemoteAddress().c_str()); return -1; } else return 0; } ACE_NOTREACHED(return 0); }
/** * Creates a new MailReceiver object with a specified GUID. * * @param receiver The player receiving the mail. * @param receiver_lowguid The GUID to use instead of the receivers. */ MailReceiver::MailReceiver(Player* receiver, ObjectGuid receiver_guid) : m_receiver(receiver), m_receiver_guid(receiver_guid) { MANGOS_ASSERT(!receiver || receiver->GetObjectGuid() == receiver_guid); }
GuardianAI::GuardianAI(Creature* c) : CreatureEventAI(c) { Unit* owner = c->GetOwner(); MANGOS_ASSERT(owner); }
void AuctionHouseMgr::AddAItem(Item* it) { MANGOS_ASSERT(it); MANGOS_ASSERT(mAitems.find(it->GetGUIDLow()) == mAitems.end()); mAitems[it->GetGUIDLow()] = it; }
void HMACSHA1::Finalize() { uint32 length = 0; HMAC_Final(&m_ctx, (uint8*)m_digest, &length); MANGOS_ASSERT(length == SHA_DIGEST_LENGTH); }