/* * Ascent MMORPG Server * Copyright (C) 2005-2007 Ascent Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "StdAfx.h" initialiseSingleton( World ); time_t World::UNIXTIME = time(NULL); time_t World::MSTIME = getMSTime(); World::World() { m_playerLimit = 0; m_allowMovement = true; m_gmTicketSystem = true; reqGmClient = false; GmClientChannel = ""; m_UpdateDistance = 0.0f; m_StartTime = 0; eventholder = new EventableObjectHolder(-1); m_holder = eventholder; m_event_Instanceid = eventholder->GetInstanceID(); mQueueUpdateInterval = 10000; PeakSessionCount = 0; mInWorldPlayerCount = 0; mAcceptedConnections = 0; HordePlayers = 0; AlliancePlayers = 0; gm_skip_attunement = false; show_gm_in_who_list = true; map_unload_time=0; #ifndef CLUSTERING SocketSendBufSize = WORLDSOCKET_SENDBUF_SIZE; SocketRecvBufSize = WORLDSOCKET_RECVBUF_SIZE; #endif } World::~World() { sLog.outString(" Saving players to DB..."); for(SessionMap::iterator i=m_sessions.begin();i!=m_sessions.end();i++) { (i->second)->LogoutPlayer(true); } sLog.outString(" Deleting world packet logger..."); delete WorldLog::getSingletonPtr(); sLog.outString(" Deleting Social Manager..."); delete SocialMgr::getSingletonPtr(); sLog.outString(" Deleting Object Manager..."); delete ObjectMgr::getSingletonPtr(); sLog.outString(" Deleting Loot Manager..."); delete LootMgr::getSingletonPtr(); sLog.outString(" Deleting LFG Manager..."); delete LfgMgr::getSingletonPtr(); sLog.outString(" Deleting Channel Manager..."); delete ChannelMgr::getSingletonPtr(); sLog.outString(" Deleting Quest Manager..."); delete QuestMgr::getSingletonPtr(); sLog.outString(" Deleting Weather Manager..."); delete WeatherMgr::getSingletonPtr(); sLog.outString(" Deleting Taxi Manager..."); delete TaxiMgr::getSingletonPtr(); sLog.outString(" Deleting Battleground Manager..."); delete CBattlegroundManager::getSingletonPtr(); sLog.outString("Removing all objects and deleting WorldCreator...\n"); delete WorldCreator::getSingletonPtr(); sLog.outString("Deleting Thread Manager.."); delete ThreadMgr::getSingletonPtr(); sLog.outString("Deleting Instance Saving Management..."); delete InstanceSavingManagement::getSingletonPtr(); sLog.outString("Deleting Random Number Generator..."); delete MTRand::getSingletonPtr(); for( AreaTriggerMap::iterator i = m_AreaTrigger.begin( ); i != m_AreaTrigger.end( ); ++ i ) { delete i->second; } //eventholder = 0; delete eventholder; sLog.outString("\n Unloading DBC files..."); // Indexed stores, need to call correct destructor. delete ((FastIndexedDataStore*)EmoteStore::getSingletonPtr()); delete ((FastIndexedDataStore*)SpellStore::getSingletonPtr()); delete ((FastIndexedDataStore*)LockStore::getSingletonPtr()); delete ((FastIndexedDataStore*)RangeStore::getSingletonPtr()); delete ((FastIndexedDataStore*)CastTimeStore::getSingletonPtr()); delete ((FastIndexedDataStore*)DurationStore::getSingletonPtr()); delete ((FastIndexedDataStore*)RadiusStore::getSingletonPtr()); delete ((FastIndexedDataStore*)FactionTmpStore::getSingletonPtr()); delete ((FastIndexedDataStore*)FactionStore::getSingletonPtr()); delete ((FastIndexedDataStore*)EnchantStore::getSingletonPtr()); delete ((FastIndexedDataStore*)WorldMapAreaStore::getSingletonPtr()); delete ((FastIndexedDataStore*)AreaStore::getSingletonPtr()); delete ((FastIndexedDataStore*)SkillLineStore::getSingletonPtr()); delete ((FastIndexedDataStore*)RandomPropStore::getSingletonPtr()); delete ((FastIndexedDataStore*)ItemSetStore::getSingletonPtr()); delete ((FastIndexedDataStore*)TransportAnimationStore::getSingletonPtr()); delete ((FastIndexedDataStore*)AuctionHouseStore::getSingletonPtr()); delete ((FastIndexedDataStore*)CreatureSpellDataStore::getSingletonPtr()); delete ((FastIndexedDataStore*)ItemExtendedCostStore::getSingletonPtr()); delete ((FastIndexedDataStore*)CreatureFamilyStore::getSingletonPtr()); delete ((FastIndexedDataStore*)CharClassStore::getSingletonPtr()); delete ((FastIndexedDataStore*)CharRaceStore::getSingletonPtr()); delete ((FastIndexedDataStore*)MapStore::getSingletonPtr()); delete ((FastIndexedDataStore*)GemPropertiesStore::getSingletonPtr()); // Non-Indexed stores delete WorldMapOverlayStore::getSingletonPtr(); delete SkillStore::getSingletonPtr(); delete TaxiPathStore::getSingletonPtr(); delete TaxiNodeStore::getSingletonPtr(); delete TaxiPathNodeStore::getSingletonPtr(); delete WorldSafeLocsStore::getSingletonPtr(); delete NameGenStore::getSingletonPtr(); delete TalentStore::getSingletonPtr(); sLog.outString(" DBC files unloaded.\n"); Storage_Cleanup(); for(list::iterator itr = dummyspells.begin(); itr != dummyspells.end(); ++itr) delete *itr; } WorldSession* World::FindSession(uint32 id) { m_sessionlock.AcquireReadLock(); WorldSession * ret = 0; SessionMap::const_iterator itr = m_sessions.find(id); if(itr != m_sessions.end()) ret = itr->second; m_sessionlock.ReleaseReadLock(); return ret; } void World::RemoveSession(uint32 id) { m_sessionlock.AcquireWriteLock(); SessionMap::iterator itr = m_sessions.find(id); if(itr != m_sessions.end()) { delete itr->second; m_sessions.erase(itr); } m_sessionlock.ReleaseWriteLock(); } void World::AddSession(WorldSession* s) { m_sessionlock.AcquireWriteLock(); ASSERT(s); m_sessions[s->GetAccountId()] = s; if(m_sessions.size() > PeakSessionCount) PeakSessionCount = m_sessions.size(); m_sessionlock.ReleaseWriteLock(); } void World::AddGlobalSession(WorldSession *session) { SessionsMutex.Acquire(); Sessions.insert(session); SessionsMutex.Release(); } void World::RemoveGlobalSession(WorldSession *session) { SessionsMutex.Acquire(); Sessions.erase(session); SessionsMutex.Release(); } void BasicTaskExecutor::run() { /* Set thread priority, this is a bitch for multiplatform :P */ #ifdef WIN32 switch(priority) { case BTE_PRIORITY_LOW: ::SetThreadPriority( ::GetCurrentThread(), THREAD_PRIORITY_LOWEST ); break; case BTW_PRIORITY_HIGH: ::SetThreadPriority( ::GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL ); break; default: // BTW_PRIORITY_MED ::SetThreadPriority( ::GetCurrentThread(), THREAD_PRIORITY_NORMAL ); break; } #else struct sched_param param; switch(priority) { case BTE_PRIORITY_LOW: param.sched_priority = 0; break; case BTW_PRIORITY_HIGH: param.sched_priority = 10; break; default: // BTW_PRIORITY_MED param.sched_priority = 5; break; } pthread_setschedparam(pthread_self(), SCHED_OTHER, ¶m); #endif // Execute the task in our new context. cb->execute(); } void CreateDummySpell(uint32 id) { const char * name = "Dummy Trigger"; SpellEntry * sp = new SpellEntry; memset(sp, 0, sizeof(SpellEntry)); sp->Id = id; sp->Attributes = 384; sp->AttributesEx = 268435456; sp->Flags3 = 4; sp->CastingTimeIndex=1; sp->procChance=75; sp->rangeIndex=13; sp->EquippedItemClass=uint32(-1); sp->Effect[0]=3; sp->EffectImplicitTargetA[0]=25; sp->buffdescflags=4128828; sp->NameHash=crc32((const unsigned char*)name, strlen(name)); sp->dmg_multiplier[0]=1.0f; sp->FH=-1; static_cast*>(SpellStore::getSingletonPtr())->SetRow(id,sp); sWorld.dummyspells.push_back(sp); } void World::SetInitialWorldSettings() { CharacterDatabase.Execute("UPDATE characters SET online = 0 WHERE online = 1"); m_lastTick = time(NULL); // TODO: clean this time_t tiempo; char hour[3]; char minute[3]; char second[3]; struct tm *tmPtr; tiempo = time(NULL); tmPtr = localtime(&tiempo); strftime( hour, 3, "%H", tmPtr ); strftime( minute, 3, "%M", tmPtr ); strftime( second, 3, "%S", tmPtr ); m_gameTime = (3600*atoi(hour))+(atoi(minute)*60)+(atoi(second)); // server starts at noon // TODO: clean this // fill in emotes table // it appears not every emote has an animation mPrices[1] = 10; mPrices[4] = 80; mPrices[6] = 150; mPrices[8] = 200; mPrices[10] = 300; mPrices[12] = 800; mPrices[14] = 900; mPrices[16] = 1800; mPrices[18] = 2200; mPrices[20] = 2300; mPrices[22] = 3600; mPrices[24] = 4200; mPrices[26] = 6700; mPrices[28] = 7200; mPrices[30] = 8000; mPrices[32] = 11000; mPrices[34] = 14000; mPrices[36] = 16000; mPrices[38] = 18000; mPrices[40] = 20000; mPrices[42] = 27000; mPrices[44] = 32000; mPrices[46] = 37000; mPrices[48] = 42000; mPrices[50] = 47000; mPrices[52] = 52000; mPrices[54] = 57000; mPrices[56] = 62000; mPrices[58] = 67000; mPrices[60] = 72000; uint32 start_time = getMSTime(); Log.Notice("World", "Loading DBC files..."); new GemPropertiesStore("DBC/GemProperties.dbc"); new SpellStore("DBC/Spell.dbc"); new LockStore("DBC/Lock.dbc"); new SkillStore("DBC/SkillLineAbility.dbc"); new EmoteStore("DBC/EmotesText.dbc"); new RangeStore("DBC/SpellRange.dbc"); new CastTimeStore("DBC/SpellCastTimes.dbc"); new DurationStore("DBC/SpellDuration.dbc"); new RadiusStore("DBC/SpellRadius.dbc"); new FactionTmpStore("DBC/FactionTemplate.dbc"); new FactionStore("DBC/Faction.dbc"); new EnchantStore("DBC/SpellItemEnchantment.dbc"); new WorldMapAreaStore("DBC/WorldMapArea.dbc"); new WorldMapOverlayStore("DBC/WorldMapOverlay.dbc"); new AreaStore("DBC/AreaTable.dbc"); new SkillLineStore("DBC/SkillLine.dbc"); new RandomPropStore("DBC/ItemRandomProperties.dbc"); new TaxiPathStore("DBC/TaxiPath.dbc"); new TaxiNodeStore("DBC/TaxiNodes.dbc"); new TaxiPathNodeStore("DBC/TaxiPathNode.dbc"); new ItemSetStore("DBC/ItemSet.dbc"); new WorldSafeLocsStore("DBC/WorldSafeLocs.dbc"); new TransportAnimationStore("DBC/TransportAnimation.dbc"); new AuctionHouseStore("DBC/AuctionHouse.dbc"); new NameGenStore("DBC/NameGen.dbc"); new TalentStore("DBC/Talent.dbc"); new CreatureSpellDataStore("DBC/CreatureSpellData.dbc"); new CreatureFamilyStore("DBC/CreatureFamily.dbc"); new CharClassStore("DBC/ChrClasses.dbc"); new CharRaceStore("DBC/ChrRaces.dbc"); new MapStore("DBC/Map.dbc"); new ItemExtendedCostStore("DBC/ItemExtendedCost.dbc"); /*{ DBCFile moo; moo.open("DBC/FactionTemplate.dbc"); set > fs; set known; for(uint32 i = 0; i < moo.getRecordCount(); ++i) { fs.insert(make_pair(moo.getRecord(i).getUInt(0), moo.getRecord(i).getUInt(1))); known.insert(moo.getRecord(i).getUInt(0)); } QueryResult * result = sDatabase.Query("SELECT entry, faction FROM creature_proto"); uint32 e, f; do { e = result->Fetch()[0].GetUInt32(); f = result->Fetch()[1].GetUInt32(); FactionDBC * d; if(known.find(f) == known.end()) { printf("Bad faction %u!", f); //d = sFactionStore.LookupEntryForced(f); d = ((FastIndexedDataStore*)FactionStore::getSingletonPtr())->LookupEntryForced(f); if(!d) printf(".. REALLY bad faction\n"); else { // find a faction template that matches.. meh ;p set >::iterator itr = fs.begin(); for(; itr != fs.end(); ++itr) { if(itr->second == f) { printf(" replaced with %u (%s)\n", itr->first, sFactionStore.LookupString(d->Name)); sDatabase.WaitExecute("UPDATE creature_proto SET faction = %u WHERE entry = %u", e, itr->second); sDatabase.WaitExecute("UPDATE creature_spawns SET factionid = %u WHERE entry = %u", e, itr->second); break; } } } } } while(result->NextRow()); }*/ /* Convert area table ids/flags */ DBCFile area; area.open("DBC/AreaTable.dbc"); uint32 flag_, area_, zone_; for(uint32 i = 0; i < area.getRecordCount(); ++i) { area_ = area.getRecord(i).getUInt(0); flag_ = area.getRecord(i).getUInt(3); zone_ = area.getRecord(i).getUInt(2); mAreaIDToTable[flag_] = sAreaStore.LookupEntry(area_); if(mZoneIDToTable.find(zone_) != mZoneIDToTable.end()) { if(mZoneIDToTable[zone_]->AreaFlags != 312 && mAreaIDToTable[flag_]->AreaFlags == 312) { // over ride. mZoneIDToTable[zone_] = mAreaIDToTable[flag_]; } } else { mZoneIDToTable[zone_] = mAreaIDToTable[flag_]; } } new ObjectMgr; new QuestMgr; new LootMgr; new LfgMgr; new WeatherMgr; new TaxiMgr; new AddonMgr; new SocialMgr; new WorldLog; // grep: this only has to be done once between version updates // to re-fill the table. /*sLog.outString("Filling spell replacements table..."); FillSpellReplacementsTable(); sLog.outString("");*/ #define MAKE_TASK(sp, ptr) tl.AddTask(new Task(new CallbackP0(sp::getSingletonPtr(), &sp::ptr))) // Fill the task list with jobs to do. TaskList tl; MAKE_TASK(ObjectMgr, LoadPlayerCreateInfo); MAKE_TASK(ObjectMgr, LoadPlayersInfo); Storage_FillTaskList(tl); // spawn worker threads (2 * number of cpus) tl.spawn(); /* storage stuff has to be loaded first */ tl.wait(); MAKE_TASK(ObjectMgr, LoadCreatureWaypoints); MAKE_TASK(ObjectMgr, LoadTrainers); MAKE_TASK(ObjectMgr, LoadTotemSpells); MAKE_TASK(ObjectMgr, LoadSpellSkills); MAKE_TASK(ObjectMgr, LoadSpellFixes); MAKE_TASK(ObjectMgr, LoadSpellOverride); MAKE_TASK(ObjectMgr, LoadVendors); MAKE_TASK(ObjectMgr, LoadAIThreatToSpellId); MAKE_TASK(ObjectMgr, LoadDefaultPetSpells); MAKE_TASK(ObjectMgr, LoadPetSpellCooldowns); MAKE_TASK(ObjectMgr, LoadGuildCharters); MAKE_TASK(ObjectMgr, LoadGMTickets); MAKE_TASK(SocialMgr, LoadFromDB); MAKE_TASK(AddonMgr, LoadFromDB); MAKE_TASK(ObjectMgr, SetHighestGuids); MAKE_TASK(ObjectMgr, LoadReputationModifiers); MAKE_TASK(ObjectMgr, LoadMonsterSay); MAKE_TASK(WeatherMgr, LoadFromDB); MAKE_TASK(ObjectMgr,LoadGroups); MAKE_TASK(ObjectMgr, LoadExtraCreatureProtoStuff); MAKE_TASK(ObjectMgr, LoadExtraItemStuff); MAKE_TASK(QuestMgr, LoadExtraQuestStuff); #undef MAKE_TASK // wait for all loading to complete. tl.wait(); CommandTableStorage::getSingleton().Load(); sLog.outString(""); Log.Notice("World", "Database loaded in %ums.", getMSTime() - start_time); sLog.outString(""); // calling this puts all maps into our task list. new WorldCreator(&tl); // wait for the events to complete. tl.wait(); // wait for them to exit, now. tl.kill(); tl.waitForThreadsToExit(); sLog.outString(""); new InstanceSavingManagement; sInstanceSavingManager.LoadSavedInstances(); //Updating spell.dbc--this is slow like hell due to we cant read string fields //dbc method will be changed in future DBCFile dbc; dbc.open("DBC/Spell.dbc"); Log.Notice("World", "Processing %u spells...", dbc.getRecordCount()); uint32 cnt = dbc.getRecordCount(); uint32 effect; /* char nametext[500]; uint32 namehash; strcpy(nametext,"Backstab"); namehash = crc32((const unsigned char*)nametext, strlen(nametext)); printf("spellname %s, namehash %u\n",nametext,namehash); */ for(uint32 x=0; x < cnt; x++) { uint32 result = 0; // SpellID uint32 spellid = dbc.getRecord(x).getUInt(0); // Description field char* desc = (char*)dbc.getRecord(x).getString(157); const char* ranktext = dbc.getRecord(x).getString(140); const char* nametext = dbc.getRecord(x).getString(123); uint32 rank = 0; uint32 type = 0; uint32 namehash = 0; // get spellentry SpellEntry * sp = sSpellStore.LookupEntry(spellid); for(uint32 b=0;b<3;++b) { if(sp->EffectTriggerSpell[b] != 0 && static_cast*>(SpellStore::getSingletonPtr())->LookupEntryForced( sp->EffectTriggerSpell[b]) == NULL) { /* proc spell referencing non-existant spell. create a dummy spell for use w/ it. */ CreateDummySpell(sp->EffectTriggerSpell[b]); } } sp->proc_interval = 0;//trigger at each event // parse rank text if(!sscanf(ranktext, "Rank %d", (unsigned int*)&rank)) rank = 0; // hash the name //!!!!!!! representing all strings on 32 bits is dangerous. There is a chance to get same hash for a lot of strings ;) namehash = crc32((const unsigned char*)nametext, strlen(nametext)); //these mostly do not mix so we can use else // look for seal, etc in name if(strstr(nametext, "Seal")) type |= SPELL_TYPE_SEAL; else if(strstr(nametext, "Blessing")) type |= SPELL_TYPE_BLESSING; else if(strstr(nametext, "Curse")) type |= SPELL_TYPE_CURSE; else if(strstr(nametext, "Aspect")) type |= SPELL_TYPE_ASPECT; else if(strstr(nametext, "Sting") || strstr(nametext, "sting")) type |= SPELL_TYPE_STING; // don't break armor items! else if(strcmp(nametext, "Armor") && strstr(nametext, "Armor") || strstr(nametext, "Demon Skin")) type |= SPELL_TYPE_ARMOR; else if(strstr(nametext, "Aura")) type |= SPELL_TYPE_AURA; else if(strstr(nametext, "Track")==nametext) type |= SPELL_TYPE_TRACK; // else if(strstr(nametext, "Gift of the Wild") || strstr(nametext, "Mark of the Wild")) else if(namehash==0xF77CAB47 || namehash==0x202F1D74) type |= SPELL_TYPE_MARK_GIFT; // else if(strstr(nametext, "Immolation Trap") || strstr(nametext, "Freezing Trap") || strstr(nametext, "Frost Trap") || strstr(nametext, "Explosive Trap") || strstr(nametext, "Snake Trap")) else if(namehash==0x238FEAF2 || namehash==0x593D7EC7 || namehash==0xF7318BD7 || namehash==0x54B6F3EE || namehash==0xF57361BB) type |= SPELL_TYPE_HUNTER_TRAP; // else if(strstr(nametext, "Arcane Intellect") || strstr(nametext, "Arcane Brilliance")) else if(namehash==0x2F7018BA || namehash==0x9CA89B04) type |= SPELL_TYPE_MAGE_INTEL; // else if(strstr(nametext, "Amplify Magic") || strstr(nametext, "Dampen Magic")) else if(namehash==0x75E2ACFF || namehash==0x3C4E2404) type |= SPELL_TYPE_MAGE_MAGI; // else if(strstr(nametext, "Fire Ward") || strstr(nametext, "Frost Ward")) else if(namehash==0xC83A99CB || namehash==0x80D1ACFF) type |= SPELL_TYPE_MAGE_WARDS; // else if(strstr(nametext, "Shadow Protection") || strstr(nametext, "Prayer of Shadow Protection")) else if(namehash==0xD9948728 || namehash==0xBDA6C77C) type |= SPELL_TYPE_PRIEST_SH_PPROT; // else if(strstr(nametext, "Water Shield") || strstr(nametext, "Earth Shield") || strstr(nametext, "Lightning Shield")) else if(namehash==0xB9DAC27E || namehash==0x0227BA8B || namehash==0x2123CF1E) type |= SPELL_TYPE_SHIELD; // else if(strstr(nametext, "Power Word: Fortitude") || strstr(nametext, "Prayer of Fortitude")) else if(namehash==0x9056D252 || namehash==0x519F97B3) type |= SPELL_TYPE_FORTITUDE; // else if(strstr(nametext, "Divine Spirit") || strstr(nametext, "Prayer of Spirit")) else if(namehash==0xB1792C31 || namehash==0xC8F56DAF) type |= SPELL_TYPE_SPIRIT; // else if(strstr(nametext, "Curse of Weakness") || strstr(nametext, "Curse of Agony") || strstr(nametext, "Curse of Recklessness") || strstr(nametext, "Curse of Tongues") || strstr(nametext, "Curse of the Elements") || strstr(nametext, "Curse of Idiocy") || strstr(nametext, "Curse of Shadow") || strstr(nametext, "Curse of Doom")) // else if(namehash==4129426293 || namehash==885131426 || namehash==626036062 || namehash==3551228837 || namehash==2784647472 || namehash==776142553 || namehash==3407058720 || namehash==202747424) // else if(strstr(nametext, "Curse of ")) // type |= SPELL_TYPE_WARLOCK_CURSES; else if(strstr(nametext, "Immolate") || strstr(nametext, "Conflagrate")) type |= SPELL_TYPE_WARLOCK_IMMOLATE; else if(strstr(nametext, "Amplify Magic") || strstr(nametext, "Dampen Magic")) type |= SPELL_TYPE_MAGE_AMPL_DUMP; else if(strstr(desc, "Finishing move")==desc) type |= SPELL_TYPE_FINISHING_MOVE; /*FILE * f = fopen("C:\\spells.txt", "a"); fprintf(f, "case 0x%08X: // %s\n", namehash, nametext); fclose(f);*/ // find diminishing status sp->DiminishStatus = GetDiminishingGroup(namehash); // HACK FIX: Break roots/fear on damage.. this needs to be fixed properly! if(!(sp->AuraInterruptFlags & AURA_INTERRUPT_ON_ANY_DAMAGE_TAKEN)) { for(uint32 z = 0; z < 3; ++z) { if(sp->EffectApplyAuraName[z] == SPELL_AURA_MOD_FEAR || sp->EffectApplyAuraName[z] == SPELL_AURA_MOD_ROOT) { sp->AuraInterruptFlags |= AURA_INTERRUPT_ON_UNUSED2; break; } } } // set extra properties sp->buffType = type; sp->NameHash = namehash; sp->RankNumber = rank; uint32 pr=sp->procFlags; for(uint32 y=0;y < 3; y++) { // get the effect number from the spell effect = dbc.getRecord(x).getUInt(64 + y); // spelleffect[0] = 64 // 2.0.1 //spell group /*if(effect==SPELL_EFFECT_SUMMON_TOTEM_SLOT1||effect==SPELL_EFFECT_SUMMON_TOTEM_SLOT2|| effect==SPELL_EFFECT_SUMMON_TOTEM_SLOT3||effect==SPELL_EFFECT_SUMMON_TOTEM_SLOT4) { const char *p=desc; while(p=strstr(p,"$")) { p++; //got $ -> check if spell if(*p>='0' && *p <='9') {//woot this is spell id uint32 tmp=atoi(p); SpellEntry*s=sSpellStore.LookupEntry(tmp); bool ch=false; for(uint32 i=0;i<3;i++) if(s->EffectTriggerSpell[i]) { ch=true; result=tmp; break; } if(ch)break; result=tmp; } } }else*/ /*if(effect==SPELL_EFFECT_ENCHANT_ITEM)//add inventory type check { result=0; //136--desc field //dirty code if(strstr(desc,"head")) result|=(1< check if spell if(*p>='0' && *p <='9') {//woot this is spell id result=atoi(p); } } pr=0; int len = strlen(desc); for(int i = 0; i < len; ++i) desc[i] = tolower(desc[i]); //dirty code for procs, if any1 got any better idea-> u are welcome //139944 --- some magic number, it will trigger on all hits etc //for seems to be smth like custom check if(strstr(desc,"takes damage")) pr|=PROC_ON_ANY_DAMAGE_VICTIM; if(strstr(desc,"attackers when hit")) pr|=PROC_ON_MELEE_ATTACK_VICTIM; if(strstr(desc,"character strikes an enemy")) pr|=PROC_ON_MELEE_ATTACK; if(strstr(desc,"strike you with a melee attack")) pr|=PROC_ON_MELEE_ATTACK_VICTIM; if(strstr(desc,"target casts a spell")) pr|=PROC_ON_CAST_SPELL; if(strstr(desc,"any damage caused")) pr|=PROC_ON_ANY_DAMAGE_VICTIM; if(strstr(desc,"the next melee attack against the caster")) pr|=PROC_ON_MELEE_ATTACK_VICTIM; if(strstr(desc,"when successfully hit")) pr|=PROC_ON_MELEE_ATTACK ; if(strstr(desc,"an enemy on hit")) pr|=PROC_ON_MELEE_ATTACK; if(strstr(desc,"when it hits")) pr|=PROC_ON_MELEE_ATTACK; if(strstr(desc,"when successfully hit")) pr|=PROC_ON_MELEE_ATTACK; if(strstr(desc,"on a successful hit")) pr|=PROC_ON_MELEE_ATTACK; if(strstr(desc,"damage to attacker on hit")) pr|=PROC_ON_MELEE_ATTACK_VICTIM; if(strstr(desc,"on a hit")) pr|=PROC_ON_MELEE_ATTACK; if(strstr(desc,"strikes you with a melee attack")) pr|=PROC_ON_MELEE_ATTACK_VICTIM; if(strstr(desc,"when caster takes damage")) pr|=PROC_ON_ANY_DAMAGE_VICTIM; if(strstr(desc,"when the caster is using melee attacks")) pr|=PROC_ON_MELEE_ATTACK; if(strstr(desc,"when struck in combat")) pr|=PROC_ON_MELEE_ATTACK_VICTIM; if(strstr(desc,"successful melee attack")) pr|=PROC_ON_MELEE_ATTACK; if(strstr(desc,"chance per attack")) pr|=PROC_ON_MELEE_ATTACK; if(strstr(desc,"chance per hit")) pr|=PROC_ON_MELEE_ATTACK; if(strstr(desc,"that strikes a party member")) pr|=PROC_ON_MELEE_ATTACK_VICTIM; if(strstr(desc,"when hit by a melee attack")) pr|=PROC_ON_MELEE_ATTACK_VICTIM; if(strstr(desc,"your critical strikes")) pr|=PROC_ON_CRIT_ATTACK; if(strstr(desc,"whenever you deal ranged damage")) pr|=PROC_ON_RANGED_ATTACK; // if(strstr(desc,"whenever you deal melee damage")) if(strstr(desc,"you deal melee damage")) pr|=PROC_ON_MELEE_ATTACK; if(strstr(desc,"your melee attacks")) pr|=PROC_ON_MELEE_ATTACK; if(strstr(desc,"damage with your Sword")) pr|=PROC_ON_MELEE_ATTACK; if(strstr(desc,"when struck in melee combat")) pr|=PROC_ON_MELEE_ATTACK_VICTIM; if(strstr(desc,"any successful spell cast against the priest")) pr|=PROC_ON_SPELL_HIT_VICTIM; if(strstr(desc,"the next melee attack on the caster")) pr|=PROC_ON_MELEE_ATTACK_VICTIM; if(strstr(desc,"striking melee or ranged attackers")) pr|=PROC_ON_MELEE_ATTACK_VICTIM|PROC_ON_RANGED_ATTACK_VICTIM; if(strstr(desc,"when damaging an enemy in melee")) pr|=PROC_ON_MELEE_ATTACK; if(strstr(desc,"victim of a critical strike")) pr|=PROC_ON_CRIT_HIT_VICTIM; if(strstr(desc,"on successful melee or ranged attack")) pr|=PROC_ON_MELEE_ATTACK|PROC_ON_RANGED_ATTACK; if(strstr(desc,"enemy that strikes you in melee")) pr|=PROC_ON_MELEE_ATTACK_VICTIM; if(strstr(desc,"after getting a critical strike")) pr|=PROC_ON_CRIT_ATTACK; if(strstr(desc,"whenever damage is dealt to you")) pr|=PROC_ON_ANY_DAMAGE_VICTIM; if(strstr(desc,"when ranged or melee damage is dealt")) pr|=PROC_ON_MELEE_ATTACK|PROC_ON_RANGED_ATTACK; if(strstr(desc,"damaging melee attacks")) pr|=PROC_ON_MELEE_ATTACK; if(strstr(desc,"on melee or ranged attack")) pr|=PROC_ON_MELEE_ATTACK|PROC_ON_RANGED_ATTACK; if(strstr(desc,"on a melee swing")) pr|=PROC_ON_MELEE_ATTACK; if(strstr(desc,"Chance on melee")) pr|=PROC_ON_MELEE_ATTACK; if(strstr(desc,"spell criticals against you")) pr|=PROC_ON_SPELL_CRIT_HIT_VICTIM; if(strstr(desc,"after being struck by a melee or ranged critical hit")) pr|=PROC_ON_CRIT_HIT_VICTIM; // if(strstr(desc,"on a critical hit")) if(strstr(desc,"critical hit")) pr|=PROC_ON_CRIT_ATTACK; if(strstr(desc,"strikes the caster")) pr|=PROC_ON_MELEE_ATTACK_VICTIM; if(strstr(desc,"a spell, melee or ranged attack hits the caster")) pr|=PROC_ON_ANY_DAMAGE_VICTIM; if(strstr(desc,"after dealing a critical strike")) pr|=PROC_ON_CRIT_ATTACK; if(strstr(desc,"each melee or ranged damage hit against the priest")) pr|=PROC_ON_MELEE_ATTACK_VICTIM|PROC_ON_RANGED_ATTACK_VICTIM; if(strstr(desc, "a chance to deal additional")) pr|=PROC_ON_MELEE_ATTACK; if(strstr(desc, "chance to get an extra attack")) pr|=PROC_ON_MELEE_ATTACK; if(strstr(desc, "gives your")) { if(strstr(desc, "melee")) pr|=PROC_ON_MELEE_ATTACK; else if(strstr(desc,"sinister strike, backstab, gouge and shiv")) pr|=PROC_ON_CAST_SPELL; else if(strstr(desc,"chance to daze the target")) pr|=PROC_ON_CAST_SPELL; else if(strstr(desc,"finishing moves")) pr|=PROC_ON_CAST_SPELL; // else if(strstr(desc,"shadow bolt, shadowburn, soul fire, incinerate, searing pain and conflagrate")) // pr|=PROC_ON_CAST_SPELL|PROC_TAGRGET_SELF; //we should find that specific spell (or group) on what we will trigger else pr|=PROC_ON_CAST_SPECIFIC_SPELL; } if(strstr(desc, "chance to add an additional combo")) pr|=PROC_ON_CAST_SPELL; if(strstr(desc, "victim of a melee or ranged critical strike")) pr|=PROC_ON_CRIT_HIT_VICTIM; if(strstr(desc, "getting a critical effect from")) pr|=PROC_ON_SPELL_CRIT_HIT_VICTIM; if(strstr(desc, "damaging attack is taken")) pr|=PROC_ON_ANY_DAMAGE_VICTIM; if(strstr(desc, "struck by a Stun or Immobilize")) pr|=PROC_ON_SPELL_HIT_VICTIM; if(strstr(desc, "melee critical strike")) pr|=PROC_ON_CRIT_ATTACK; if(strstr(nametext, "Bloodthirst")) pr|=PROC_ON_MELEE_ATTACK | PROC_TAGRGET_SELF; if(strstr(desc, "experience or honor")) pr|=PROC_ON_GAIN_EXPIERIENCE; if(strstr(desc,"your next offensive ability")) pr|=PROC_ON_CAST_SPELL; if(strstr(desc,"hit by a melee or ranged attack")) pr|=PROC_ON_MELEE_ATTACK_VICTIM | PROC_ON_RANGED_ATTACK_VICTIM; if(strstr(desc,"enemy strikes the caster")) pr|=PROC_ON_MELEE_ATTACK_VICTIM; if(strstr(desc,"melee and ranged attacks against you")) pr|=PROC_ON_MELEE_ATTACK_VICTIM | PROC_ON_RANGED_ATTACK_VICTIM; if(strstr(desc,"when a block occurs")) pr|=PROC_ON_BLOCK_VICTIM; if(strstr(desc,"dealing a critical strike from a weapon swing, spell, or ability")) pr|=PROC_ON_CRIT_ATTACK|PROC_ON_SPELL_CRIT_HIT; if(strstr(desc,"dealing a critical strike from a weapon swing, spell, or ability")) pr|=PROC_ON_CRIT_ATTACK|PROC_ON_SPELL_CRIT_HIT; if(strstr(desc,"shadow bolt critical strikes increase shadow damage")) pr|=PROC_ON_SPELL_CRIT_HIT; if(strstr(desc,"next offensive ability")) pr|=PROC_ON_CAST_SPELL; if(strstr(desc,"after being hit with a shadow or fire spell")) pr|=PROC_ON_SPELL_HIT_VICTIM; if(strstr(desc,"giving each melee attack")) pr|=PROC_ON_MELEE_ATTACK; if(strstr(desc,"each strike has")) pr|=PROC_ON_MELEE_ATTACK; if(strstr(desc,"your Fire damage spell hits")) pr|=PROC_ON_CAST_SPELL; //this happens only on hit ;) if(strstr(desc,"corruption, curse of agony, siphon life and seed of corruption spells also cause")) pr|=PROC_ON_CAST_SPELL; if(strstr(desc,"pain, mind flay and vampiric touch spells also cause")) pr|=PROC_ON_CAST_SPELL; if(strstr(desc,"shadow damage spells have")) pr|=PROC_ON_CAST_SPELL; if(strstr(desc,"your spell criticals have")) pr|=PROC_ON_SPELL_CRIT_HIT | PROC_ON_SPELL_CRIT_HIT_VICTIM; if(strstr(desc,"after dodging their attack")) { pr|=PROC_ON_DODGE_VICTIM; if(strstr(desc,"add a combo point")) pr|=PROC_TAGRGET_SELF; } if(strstr(desc,"fully resisting")) pr|=PROC_ON_RESIST_VICTIM; // if(strstr(desc,"chill effect to your Blizzard")) // pr|=PROC_ON_CAST_SPELL; ////////////////////////////////////////////////// //proc dmg flags ////////////////////////////////////////////////// if(strstr(desc,"each attack blocked")) pr|=PROC_ON_BLOCK_VICTIM; if(strstr(desc,"into flame, causing an additional")) pr|=PROC_ON_MELEE_ATTACK; if(strstr(desc,"victim of a critical melee strike")) pr|=PROC_ON_CRIT_HIT_VICTIM; if(strstr(desc,"damage to melee attackers")) pr|=PROC_ON_MELEE_ATTACK; if(strstr(desc,"target blocks a melee attack")) pr|=PROC_ON_BLOCK_VICTIM; if(strstr(desc,"ranged and melee attacks to deal")) pr|=PROC_ON_MELEE_ATTACK_VICTIM | PROC_ON_RANGED_ATTACK_VICTIM; if(strstr(desc,"damage on hit")) pr|=PROC_ON_ANY_DAMAGE_VICTIM; if(strstr(desc,"after being hit by any damaging attack")) pr|=PROC_ON_ANY_DAMAGE_VICTIM; if(strstr(desc,"striking melee or ranged attackers")) pr|=PROC_ON_MELEE_ATTACK_VICTIM | PROC_ON_RANGED_ATTACK_VICTIM; if(strstr(desc,"damage to attackers when hit")) pr|=PROC_ON_MELEE_ATTACK_VICTIM; if(strstr(desc,"striking melee attackers")) pr|=PROC_ON_MELEE_ATTACK_VICTIM; if(strstr(desc,"whenever the caster takes damage")) pr|=PROC_ON_ANY_DAMAGE_VICTIM; if(strstr(desc,"damage on every attack")) pr|=PROC_ON_MELEE_ATTACK | PROC_ON_RANGED_ATTACK; if(strstr(desc,"chance to reflect Fire spells")) pr|=PROC_ON_SPELL_HIT_VICTIM; if(strstr(desc,"hunter takes on the aspects of a hawk")) pr|=PROC_TAGRGET_SELF | PROC_ON_RANGED_ATTACK; if(strstr(desc,"successful auto shot attacks")) pr|=PROC_ON_AUTO_SHOT_HIT; if(strstr(desc,"after getting a critical effect from your")) pr=PROC_ON_SPELL_CRIT_HIT; // if(strstr(desc,"Your critical strikes from Fire damage")) // pr|=PROC_ON_SPELL_CRIT_HIT; }//end "if procspellaura" //dirty fix to remove auras that should expire on event and they are not // else if(sp->procCharges>0) // { //there are at least 185 spells that should loose charge uppon some event.Be prepared to add more here ! // ! watch it cause this might conflict with our custom modified spells like : lighning shield ! //spells like : Presence of Mind,Nature's Swiftness, Inner Focus,Amplify Curse,Coup de Grace //SELECT * FROM dbc_spell where proc_charges!=0 and (effect_aura_1=108 or effect_aura_2=108 and effect_aura_3=108) and description!="" // if(aura == SPELL_AURA_ADD_PCT_MODIFIER) // sp->AuraInterruptFlags |= AURA_INTERRUPT_ON_CAST_SPELL; //most of them probably already have these flags...not sure if we should add to all of them without checking /* if(strstr(desc, "melee")) sp->AuraInterruptFlags |= AURA_INTERRUPT_ON_START_ATTACK; if(strstr(desc, "ranged")) sp->AuraInterruptFlags |= AURA_INTERRUPT_ON_START_ATTACK;*/ // } }//end "if aura" }//end "for each effect" sp->procFlags=pr; if (strstr(desc, "Must remain seated")) { sp->RecoveryTime = 1000; sp->CategoryRecoveryTime = 1000; } ////////////////////////////////////////////////////////////////////////////////////////////////////// // procintervals ////////////////////////////////////////////////////////////////////////////////////////////////////// //omg lighning shield trigger spell id's are all wrong ? //if you are bored you could make thiese by hand but i guess we might find other spells with this problem..and this way it's safe if(strstr(nametext, "Lightning Shield") && sp->EffectTriggerSpell[0]) { //check if we can find in the desription char *startofid=strstr(desc, "for $"); if(startofid) { startofid += strlen("for $"); sp->EffectTriggerSpell[0]=atoi(startofid); //get new lightning shield trigger id } sp->proc_interval = 3000; //few seconds } //mage ignite talent should proc only on some chances else if(strstr(nametext, "Ignite") && sp->Id>=11119 && sp->Id<=12848 && sp->EffectApplyAuraName[0]==4) { //check if we can find in the desription char *startofid=strstr(desc, "an additional "); if(startofid) { startofid += strlen("an additional "); sp->EffectBasePoints[0]=atoi(startofid); //get new chance. This is actually level*8 ;) } sp->Effect[0] = 6; //aura sp->EffectApplyAuraName[0] = 42; //force him to use procspell effect sp->EffectTriggerSpell[0] = 12654; //evil , but this is good for us :D sp->procFlags = PROC_ON_SPELL_CRIT_HIT; //add procflag here since this was not processed with the others ! } // Winter's Chill handled by frost school else if(strstr(nametext, "Winter's Chill")) { sp->School = 4; } // Blackout handled by Shadow school else if(strstr(nametext, "Blackout")) { sp->School = 5; } // Shadow Weaving else if(strstr(nametext, "Shadow Weaving")) { sp->School = 5; sp->EffectApplyAuraName[0] = 42; sp->procChance = sp->EffectBasePoints[0] + 1; sp->procFlags = PROC_ON_CAST_SPECIFIC_SPELL; } //Improved Aspect of the Hawk else if(strstr(nametext, "Improved Aspect of the Hawk")) sp->EffectSpellGroupRelation[1] = 0x100000; //more triggered spell ids are wrong. I think blizz is trying to outsmart us :S else if( strstr(nametext, "Nature's Guardian")) { sp->EffectTriggerSpell[0]=31616; sp->proc_interval = 5000; } //this starts to be an issue for trigger spell id : Deep Wounds else if(strstr(nametext, "Deep Wounds") && sp->EffectTriggerSpell[0]) { //check if we can find in the desription char *startofid=strstr(desc, "over $"); if(startofid) { startofid += strlen("over $"); sp->EffectTriggerSpell[0]=atoi(startofid); } } else if(strstr(nametext, "Holy Shock")) { //check if we can find in the desription char *startofid=strstr(desc, "causing $"); if(startofid) { startofid += strlen("causing $"); sp->EffectTriggerSpell[0]=atoi(startofid); } //check if we can find in the desription startofid=strstr(desc, " or $"); if(startofid) { startofid += strlen(" or $"); sp->EffectTriggerSpell[1]=atoi(startofid); } } else if(strstr(nametext, "Touch of Weakness")) { //check if we can find in the desription char *startofid=strstr(desc, "cause $"); if(startofid) { startofid += strlen("cause $"); sp->EffectTriggerSpell[0]=atoi(startofid); sp->EffectTriggerSpell[1]=sp->EffectTriggerSpell[0]; //later versions of this spell changed to eff[1] the aura sp->procFlags = uint32(PROC_ON_MELEE_ATTACK_VICTIM | PROC_TAGRGET_SELF); } } //some procs trigger at intervals else if(strstr(nametext, "Water Shield")) { sp->proc_interval = 3000; //few seconds sp->procFlags |= PROC_TAGRGET_SELF; } else if(strstr(nametext, "Earth Shield")) sp->proc_interval = 3000; //few seconds else if(strstr(nametext, "Shadowguard")) sp->proc_interval = 3000; //few seconds else if(strstr(nametext, "Poison Shield")) sp->proc_interval = 3000; //few seconds else if(strstr(nametext, "Infused Mushroom")) sp->proc_interval = 10000; //10 seconds else if(strstr(nametext, "Aviana's Purpose")) sp->proc_interval = 10000; //10 seconds // else if(strstr(nametext, "Illumination")) // sp->EffectTriggerSpell[0]=20272; //sp->dummy=result; /* //if there is a proc spell and has 0 as charges then it's probably going to triger infinite times. Better not save these if(sp->procCharges==0) sp->procCharges=-1;*/ if(sp->proc_interval!=0) sp->procFlags |= PROC_REMOVEONUSE; /* Seal of Command - Proc Chance */ if(sp->NameHash == 0xC5C30B39) sp->procChance = 25; /* Seal of Jusice - Proc Chance */ if(sp->NameHash == 0xCC6D4182) sp->procChance = 25; /* Decapitate */ if(sp->NameHash == 0xB6C3243C) sp->procChance = 30; //junk code to get me has :P //if(sp->Id==11267 || sp->Id==11289 || sp->Id==6409) // printf("!!!!!!! name %s , id %u , hash %u \n",nametext,sp->Id, namehash); } //this is so lame : shamanistic rage triggers a new spell which borrows it's stats from parent spell :S SpellEntry * parentsp = sSpellStore.LookupEntry(30823); SpellEntry * triggersp = sSpellStore.LookupEntry(30824); if(parentsp && triggersp) triggersp->EffectBasePoints[0] = parentsp->EffectBasePoints[0]; SpellEntry * sp = sSpellStore.LookupEntry(16164); if(sp && sp->Id==16164) sp->procFlags=PROC_ON_SPELL_CRIT_HIT_VICTIM; sp = sSpellStore.LookupEntry(17364); //remove stormstrike effect 0 if(sp && sp->Id==17364) sp->Effect[0]=0; //fix for the right Enchant ID for Enchant Cloak - Major Resistance sp = sSpellStore.LookupEntry(27962); if(sp) sp->EffectMiscValue[0] = 2998; sp = sSpellStore.LookupEntry(36285); if(sp) sp->EffectMiscValue[0] = 2998; //muhaha, rewriting Retaliation spell as old one :D sp = sSpellStore.LookupEntry(20230); if(sp) { sp->Effect[0] = 6; //aura sp->EffectApplyAuraName[0] = 42; //force him to use procspell effect sp->EffectTriggerSpell[0] = 22858; //evil , but this is good for us :D sp->procFlags = PROC_ON_MELEE_ATTACK_VICTIM; //add procflag here since this was not processed with the others ! } //"bloodthirst" new version is ok but old version is wrong from now on :( sp = sSpellStore.LookupEntry(23881); if(sp) { sp->Effect[1] = 64; //cast on us, it is good sp->EffectTriggerSpell[1] = 23885; //evil , but this is good for us :D } sp = sSpellStore.LookupEntry(23892); if(sp) { sp->Effect[1] = 64; sp->EffectTriggerSpell[1] = 23886; //evil , but this is good for us :D } sp = sSpellStore.LookupEntry(23893); if(sp) { sp->Effect[1] = 64; // sp->EffectTriggerSpell[1] = 23887; //evil , but this is good for us :D } sp = sSpellStore.LookupEntry(23894); if(sp) { sp->Effect[1] = 64; // sp->EffectTriggerSpell[1] = 23888; //evil , but this is good for us :D } sp = sSpellStore.LookupEntry(25251); if(sp) { sp->Effect[1] = 64; //aura sp->EffectTriggerSpell[1] = 25252; //evil , but this is good for us :D } sp = sSpellStore.LookupEntry(30335); if(sp) { sp->Effect[1] = 64; //aura sp->EffectTriggerSpell[1] = 30339; //evil , but this is good for us :D } //Warrior:Improved Berserker sp = sSpellStore.LookupEntry(20500); if(sp) sp->procFlags=PROC_ON_CAST_SPELL; sp = sSpellStore.LookupEntry(20501); if(sp) sp->procFlags=PROC_ON_CAST_SPELL; //Druid:Intensity sp = sSpellStore.LookupEntry(17106); if(sp) { sp->EffectApplyAuraName[1] = 42; sp->procFlags=PROC_ON_CAST_SPELL; } sp = sSpellStore.LookupEntry(17107); if(sp) { sp->EffectApplyAuraName[1] = 42; sp->procFlags=PROC_ON_CAST_SPELL; } sp = sSpellStore.LookupEntry(17108); if(sp) { sp->EffectApplyAuraName[1] = 42; sp->procFlags=PROC_ON_CAST_SPELL; } //Improved Sprint sp = sSpellStore.LookupEntry(13743); if(sp) { sp->EffectApplyAuraName[0] = 42; sp->procFlags=PROC_ON_CAST_SPELL; sp->procChance = 50; } sp = sSpellStore.LookupEntry(13875); if(sp) { sp->EffectApplyAuraName[0] = 42; sp->procFlags=PROC_ON_CAST_SPELL; } //warlock: Shadow Mastery for (uint32 i=0;i<5;i++) { sp = sSpellStore.LookupEntry(18271+i); if (sp) { sp->EffectSpellGroupRelation[0]=33562624; sp->EffectSpellGroupRelation[1]=8421376; } } //mage: Arcane Power sp = sSpellStore.LookupEntry(12042); if (sp) { sp->EffectSpellGroupRelation[0]=5775504; sp->EffectSpellGroupRelation[1]=10518528; } //mage: Fire Power sp = sSpellStore.LookupEntry(11124); if (sp) { sp->EffectSpellGroupRelation[0]=868; sp->EffectSpellGroupRelation[1]=868; } sp = sSpellStore.LookupEntry(12398); if (sp) { sp->EffectSpellGroupRelation[0]=868; sp->EffectSpellGroupRelation[1]=868; } sp = sSpellStore.LookupEntry(12399); if (sp) { sp->EffectSpellGroupRelation[0]=868; sp->EffectSpellGroupRelation[1]=868; } sp = sSpellStore.LookupEntry(12400); if (sp) { sp->EffectSpellGroupRelation[0]=868; sp->EffectSpellGroupRelation[1]=868; } sp = sSpellStore.LookupEntry(12378); if (sp) { sp->EffectSpellGroupRelation[0]=868; sp->EffectSpellGroupRelation[1]=868; } ////mage: Spell Power //sp = sSpellStore.LookupEntry(35581); //if(sp) //{ // sp->EffectSpellGroupRelation[0]=5775504; //} //sp = sSpellStore.LookupEntry(35578); //if(sp) //{ // sp->EffectSpellGroupRelation[0]=5775504; //} //mage: Blazing Speed sp = sSpellStore.LookupEntry(31641); if(sp) sp->EffectTriggerSpell[0]=31643; sp = sSpellStore.LookupEntry(31642); if(sp) sp->EffectTriggerSpell[0]=31643; //mage talent "frostbyte". we make it to be dummy sp = sSpellStore.LookupEntry(11071); if(sp) sp->EffectApplyAuraName[0]=4; sp = sSpellStore.LookupEntry(12496); if(sp) sp->EffectApplyAuraName[0]=4; sp = sSpellStore.LookupEntry(12497); if(sp) sp->EffectApplyAuraName[0]=4; //rogue-shiv -> add 1 combo point sp = sSpellStore.LookupEntry(5938); if(sp) sp->Effect[1]=80; //warlock - soul leech sp = sSpellStore.LookupEntry(30293); if(sp) { sp->Effect[0] = 6; //aura sp->EffectApplyAuraName[0] = 42; sp->EffectTriggerSpell[0] = 30294; sp->procFlags=uint32(PROC_ON_CAST_SPELL|PROC_TAGRGET_SELF); } sp = sSpellStore.LookupEntry(30295); if(sp) { sp->Effect[0] = 6; //aura sp->EffectApplyAuraName[0] = 42; sp->EffectTriggerSpell[0] = 30294; sp->procFlags=uint32(PROC_ON_CAST_SPELL|PROC_TAGRGET_SELF); } sp = sSpellStore.LookupEntry(30296); if(sp) { sp->Effect[0] = 6; //aura sp->EffectApplyAuraName[0] = 42; sp->EffectTriggerSpell[0] = 30294; sp->procFlags=uint32(PROC_ON_CAST_SPELL|PROC_TAGRGET_SELF); } //warlock - Pyroclasm sp = sSpellStore.LookupEntry(18073); if(sp) { sp->Effect[0] = 0; //delete this owerride effect :P sp->EffectTriggerSpell[1] = 18093; //trigger spell was wrong :P sp->procFlags=PROC_ON_CAST_SPELL; sp->procChance = 13; //god, save us from fixed values ! } sp = sSpellStore.LookupEntry(18096); if(sp) { sp->Effect[0] = 0; //delete this owerride effect :P sp->EffectTriggerSpell[1] = 18093; //trigger spell was wrong :P sp->procFlags=PROC_ON_CAST_SPELL; sp->procChance = 26; //god, save us from fixed values ! } //improved scorch sp = sSpellStore.LookupEntry(11095); if(sp) { sp->EffectApplyAuraName[0] = 42; sp->procFlags=PROC_ON_CAST_SPELL; } sp = sSpellStore.LookupEntry(12872); if(sp) { sp->EffectApplyAuraName[0] = 42; sp->procFlags=PROC_ON_CAST_SPELL; } sp = sSpellStore.LookupEntry(12873); if(sp) { sp->EffectApplyAuraName[0] = 42; sp->procFlags=PROC_ON_CAST_SPELL; } //Nature's Grasp sp = sSpellStore.LookupEntry(16689); if(sp) { sp->Effect[0] = 6; sp->EffectApplyAuraName[0] = 42; sp->EffectTriggerSpell[0] = 339; sp->Effect[1] = 0; sp->procFlags = PROC_ON_MELEE_ATTACK_VICTIM | PROC_REMOVEONUSE; sp->AuraInterruptFlags = 0; //we remove it on proc or timeout } sp = sSpellStore.LookupEntry(16810); if(sp) { sp->Effect[0] = 6; sp->EffectApplyAuraName[0] = 42; sp->EffectTriggerSpell[0] = 1062; sp->Effect[1] = 0; sp->procFlags = PROC_ON_MELEE_ATTACK_VICTIM | PROC_REMOVEONUSE; sp->AuraInterruptFlags = 0; //we remove it on proc or timeout } sp = sSpellStore.LookupEntry(16811); if(sp) { sp->Effect[0] = 6; sp->EffectApplyAuraName[0] = 42; sp->EffectTriggerSpell[0] = 5195; sp->Effect[1] = 0; sp->procFlags = PROC_ON_MELEE_ATTACK_VICTIM | PROC_REMOVEONUSE; sp->AuraInterruptFlags = 0; //we remove it on proc or timeout } sp = sSpellStore.LookupEntry(16812); if(sp) { sp->Effect[0] = 6; sp->EffectApplyAuraName[0] = 42; sp->EffectTriggerSpell[0] = 5196; sp->Effect[1] = 0; sp->procFlags = PROC_ON_MELEE_ATTACK_VICTIM | PROC_REMOVEONUSE; sp->AuraInterruptFlags = 0; //we remove it on proc or timeout } sp = sSpellStore.LookupEntry(16813); if(sp) { sp->Effect[0] = 6; sp->EffectApplyAuraName[0] = 42; sp->EffectTriggerSpell[0] = 9852; sp->Effect[1] = 0; sp->procFlags = PROC_ON_MELEE_ATTACK_VICTIM | PROC_REMOVEONUSE; sp->AuraInterruptFlags = 0; //we remove it on proc or timeout } sp = sSpellStore.LookupEntry(17329); if(sp) { sp->Effect[0] = 6; sp->EffectApplyAuraName[0] = 42; sp->EffectTriggerSpell[0] = 9853; sp->Effect[1] = 0; sp->procFlags = PROC_ON_MELEE_ATTACK_VICTIM | PROC_REMOVEONUSE; sp->AuraInterruptFlags = 0; //we remove it on proc or timeout } sp = sSpellStore.LookupEntry(27009); if(sp) { sp->Effect[0] = 6; sp->EffectApplyAuraName[0] = 42; sp->EffectTriggerSpell[0] = 26989; sp->Effect[1] = 0; sp->procFlags = PROC_ON_MELEE_ATTACK_VICTIM | PROC_REMOVEONUSE; sp->AuraInterruptFlags = 0; //we remove it on proc or timeout } //wrath of air totem targets sorounding creatures instead of us sp = sSpellStore.LookupEntry(2895); if(sp) { sp->EffectImplicitTargetA[0]=1; sp->EffectImplicitTargetA[1]=1; sp->EffectImplicitTargetA[2]=0; sp->EffectImplicitTargetB[0]=0; sp->EffectImplicitTargetB[1]=0; sp->EffectImplicitTargetB[2]=0; } //Relentless Strikes sp = sSpellStore.LookupEntry(14179); if(sp) { sp->EffectApplyAuraName[0]=42;//proc spell sp->procFlags = PROC_ON_CAST_SPELL; sp->EffectBasePoints[1] = 20; //client showes 20% chance but whe do not have it ? :O } //priest - surge of light sp = sSpellStore.LookupEntry(33150); if(sp) sp->procFlags = uint32(PROC_ON_SPELL_CRIT_HIT_VICTIM | PROC_TAGRGET_SELF); sp = sSpellStore.LookupEntry(33154); if(sp) sp->procFlags = uint32(PROC_ON_SPELL_CRIT_HIT_VICTIM | PROC_TAGRGET_SELF); sp = sSpellStore.LookupEntry(33151); if(sp) { sp->EffectSpellGroupRelation[0]=128; sp->EffectSpellGroupRelation[1]=128; sp->EffectSpellGroupRelation[2]=128; sp->AuraInterruptFlags = AURA_INTERRUPT_ON_CAST_SPELL; } //Seal of Justice -lowered proc chance (experimental values !) sp = sSpellStore.LookupEntry(20164); if(sp) sp->procChance = 20; sp = sSpellStore.LookupEntry(31895); if(sp) sp->procChance = 20; //make Berserking a simple spell sp = sSpellStore.LookupEntry(20554); if(sp) { sp->Effect[0] = SPELL_EFFECT_TRIGGER_SPELL; sp->EffectTriggerSpell[0] = 26635; } sp = sSpellStore.LookupEntry(26296); if(sp) { sp->Effect[0] = SPELL_EFFECT_TRIGGER_SPELL; sp->EffectTriggerSpell[0] = 26635; } sp = sSpellStore.LookupEntry(26297); if(sp) { sp->Effect[0] = SPELL_EFFECT_TRIGGER_SPELL; sp->EffectTriggerSpell[0] = 26635; } //rogue - intiative sp = sSpellStore.LookupEntry(13976); if(sp) { sp->EffectApplyAuraName[0] = 42; sp->procFlags=uint32(PROC_ON_CAST_SPELL|PROC_TAGRGET_SELF); } sp = sSpellStore.LookupEntry(13979); if(sp) { sp->EffectApplyAuraName[0] = 42; sp->procFlags=uint32(PROC_ON_CAST_SPELL|PROC_TAGRGET_SELF); } sp = sSpellStore.LookupEntry(13980); if(sp) { sp->EffectApplyAuraName[0] = 42; sp->procFlags=uint32(PROC_ON_CAST_SPELL|PROC_TAGRGET_SELF); } //winfury weapon changes. Start to hate these day by day EnchantEntry * Enchantment = sEnchantStore.LookupEntry(283); if(Enchantment) { Enchantment->spell[0] = 33757; //this is actually good sp = sSpellStore.LookupEntry(33757); if(sp) { sp->EffectApplyAuraName[0] = 42; //who needs dummys anyway ? sp->procFlags = PROC_ON_MELEE_ATTACK; //we do not need proc on spell ;) sp->EffectTriggerSpell[0] = 8232; //for the logs and rest } } Enchantment = sEnchantStore.LookupEntry(284); if(Enchantment) { Enchantment->spell[0] = 33756; sp = sSpellStore.LookupEntry(33756); if(sp) { sp->EffectApplyAuraName[0] = 42; //who needs dummys anyway ? sp->procFlags = PROC_ON_MELEE_ATTACK; //we do not need proc on spell ;) sp->EffectTriggerSpell[0] = 8235; //for the logs and rest } } Enchantment = sEnchantStore.LookupEntry(525); if(Enchantment) { Enchantment->spell[0] = 33755; sp = sSpellStore.LookupEntry(33755); if(sp) { sp->EffectApplyAuraName[0] = 42; //who needs dummys anyway ? sp->procFlags = PROC_ON_MELEE_ATTACK; //we do not need proc on spell ;) sp->EffectTriggerSpell[0] = 10486; //for the logs and rest } } Enchantment = sEnchantStore.LookupEntry(1669); if(Enchantment) { Enchantment->spell[0] = 33754; sp = sSpellStore.LookupEntry(33754); if(sp) { sp->EffectApplyAuraName[0] = 42; //who needs dummys anyway ? sp->procFlags = PROC_ON_MELEE_ATTACK; //we do not need proc on spell ;) sp->EffectTriggerSpell[0] = 16362; //for the logs and rest } } Enchantment = sEnchantStore.LookupEntry(2636); if(Enchantment) { Enchantment->spell[0] = 33727; sp = sSpellStore.LookupEntry(33727); if(sp) { sp->EffectApplyAuraName[0] = 42; //who needs dummys anyway ? sp->procFlags = PROC_ON_MELEE_ATTACK; //we do not need proc on spell ;) sp->EffectTriggerSpell[0] = 25505; //for the logs and rest } } //for test only sp = sSpellStore.LookupEntry(16498); if(sp) { // printf("!!!!!!hash %u \n",sp->NameHash); // sp->procChance=100; // SpellDuration *sd=sSpellDuration.LookupEntry(sp->DurationIndex); //printf("iterruptflag %u, duration %u",sp->AuraInterruptFlags,GetDuration(sd)); } //improoved berserker stance should be triggered on berserker stance use // sp = sSpellStore.LookupEntry(12704); // if(sp) sp->procFlags=PROC_ON_CAST_SPECIFIC_SPELL; // sp = sSpellStore.LookupEntry(16280); // if(sp) printf("!!Interrupt flags %u interval %u charges %u\n",sp->AuraInterruptFlags,sp->proc_interval,sp->procCharges); // sp = sSpellStore.LookupEntry(16284); // if(sp) printf("Interrupt flags %u\n",sp->AuraInterruptFlags); //fix for Predatory Strikes uint32 mm=(1<<(FORM_BEAR-1))|(1<<(FORM_DIREBEAR-1))|(1<<(FORM_MOONKIN-1))|(1<<(FORM_CAT-1)); sSpellStore.LookupEntry(16972)->RequiredShapeShift = mm; sSpellStore.LookupEntry(16974)->RequiredShapeShift = mm; sSpellStore.LookupEntry(16975)->RequiredShapeShift = mm; sSpellStore.LookupEntry(20134)->procChance = 50; /* aspect of the pack - change to AA */ sSpellStore.LookupEntry(13159)->Effect[0] = SPELL_EFFECT_APPLY_AREA_AURA; sSpellStore.LookupEntry(13159)->Effect[1] = SPELL_EFFECT_APPLY_AREA_AURA; /* shadowstep - change proc flags */ sSpellStore.LookupEntry(36563)->procFlags = 0; Log.Notice("World","Starting Transport System..."); objmgr.LoadTransporters(); // start mail system MailSystem::getSingleton().StartMailSystem(); Log.Notice("World", "Starting Auction System..."); new AuctionMgr; sAuctionMgr.LoadAuctionHouses(); HonorHandler::PerformStartupTasks(); m_queueUpdateTimer = mQueueUpdateInterval; if(Config.MainConfig.GetBoolDefault("Startup", "Preloading", false)) { // Load all data on each map. sWorldCreator.GetInstance(0, uint32(0))->LoadAllCells(); sWorldCreator.GetInstance(1, uint32(0))->LoadAllCells(); sWorldCreator.GetInstance(530, uint32(0))->LoadAllCells(); } launch_thread(new WorldRunnable); if(Config.MainConfig.GetBoolDefault("Startup", "BackgroundLootLoading", true)) { Log.Notice("World", "Backgrounding loot loading..."); // loot background loading in a lower priority thread. launch_thread(new BasicTaskExecutor(new CallbackP0(LootMgr::getSingletonPtr(), &LootMgr::LoadLoot), BTE_PRIORITY_LOW)); } else { Log.Notice("World", "Loading loot in foreground..."); lootmgr.LoadLoot(); } Log.Notice("BattlegroundManager", "Starting..."); new CBattlegroundManager; } void World::Update(time_t diff) { eventholder->Update(diff); sAuctionMgr.Update(); _UpdateGameTime(); /* since time() is an expensive system call, we only update it once per server loop */ World::UNIXTIME = time(NULL); World::MSTIME = getMSTime(); } void World::SendGlobalMessage(WorldPacket *packet, WorldSession *self) { m_sessionlock.AcquireReadLock(); SessionMap::iterator itr; for (itr = m_sessions.begin(); itr != m_sessions.end(); itr++) { if (itr->second->GetPlayer() && itr->second->GetPlayer()->IsInWorld() && itr->second != self) // dont send to self! { itr->second->SendPacket(packet); } } m_sessionlock.ReleaseReadLock(); } void World::SendFactionMessage(WorldPacket *packet, uint8 teamId) { m_sessionlock.AcquireReadLock(); SessionMap::iterator itr; Player * plr; for(itr = m_sessions.begin(); itr != m_sessions.end(); itr++) { plr = itr->second->GetPlayer(); if(!plr || !plr->IsInWorld()) continue; if(plr->GetTeam() == teamId) itr->second->SendPacket(packet); } m_sessionlock.ReleaseReadLock(); } void World::SendZoneMessage(WorldPacket *packet, uint32 zoneid, WorldSession *self) { m_sessionlock.AcquireReadLock(); SessionMap::iterator itr; for (itr = m_sessions.begin(); itr != m_sessions.end(); itr++) { if (itr->second->GetPlayer() && itr->second->GetPlayer()->IsInWorld() && itr->second != self) // dont send to self! { if (itr->second->GetPlayer()->GetZoneId() == zoneid) itr->second->SendPacket(packet); } } m_sessionlock.ReleaseReadLock(); } void World::SendWorldText(const char* text, WorldSession *self) { uint32 textLen = strlen((char*)text) + 1; WorldPacket data(textLen + 40); data.Initialize(SMSG_MESSAGECHAT); data << uint8(CHAT_MSG_SYSTEM); data << uint32(LANG_UNIVERSAL); data << (uint64)0; // Who cares about guid when there's no nickname displayed heh ? data << (uint32)0; data << (uint64)0; data << textLen; data << text; data << uint8(0); SendGlobalMessage(&data, self); sLog.outString("> %s", text); } void World::SendWorldWideScreenText(const char *text, WorldSession *self) { WorldPacket data(256); data.Initialize(SMSG_AREA_TRIGGER_MESSAGE); data << (uint32)0 << text << (uint8)0x00; SendGlobalMessage(&data, self); } void World::UpdateSessions(uint32 diff) { SessionSet::iterator itr, it2; WorldSession *session; int result; for(itr = Sessions.begin(); itr != Sessions.end();) { session = (*itr); it2 = itr; ++itr; if(!session || session->GetInstance() != 0) { Sessions.erase(it2); continue; } if((result = session->Update(0))) { if(result == 1) { // complete deletion DeleteSession(session); } Sessions.erase(it2); } } } std::string World::GenerateName(uint32 type) { uint32 maxval = NameGenStore::getSingleton().GetNumRows(); uint32 entry = rand()%(maxval+1); // we don't want 1.. NameGenEntry* ne = NameGenStore::getSingleton().LookupEntry(entry); if(!ne) { sLog.outError("ERROR: Couldn't find NameGenStore Entry!"); return "ERR"; } const char *name = NameGenStore::getSingleton().LookupString((const uint32)ne->offsetindex); if(name) return name; else return "ERR"; } void World::DeleteSession(WorldSession *session) { m_sessionlock.AcquireWriteLock(); // remove from big map m_sessions.erase(session->GetAccountId()); m_sessionlock.ReleaseWriteLock(); // delete us delete session; } uint32 World::GetNonGmSessionCount() { m_sessionlock.AcquireReadLock(); uint32 total = m_sessions.size(); SessionMap::const_iterator itr = m_sessions.begin(); for( ; itr != m_sessions.end(); itr++ ) { if( (itr->second)->HasGMPermissions() ) total--; } m_sessionlock.ReleaseReadLock(); return total; } uint32 World::AddQueuedSocket(WorldSocket* Socket) { // Since we have multiple socket threads, better guard for this one, // we don't want heap corruption ;) queueMutex.Acquire(); // Add socket to list mQueuedSessions.push_back(Socket); queueMutex.Release(); // Return queue position return mQueuedSessions.size(); } void World::RemoveQueuedSocket(WorldSocket* Socket) { // Since we have multiple socket threads, better guard for this one, // we don't want heap corruption ;) queueMutex.Acquire(); // Find socket in list QueueSet::iterator iter = mQueuedSessions.begin(); for(; iter != mQueuedSessions.end(); ++iter) { if((*iter) == Socket) { // Remove from the queue and abort. // This will be slow (Removing from middle of a vector!) but it won't // get called very much, so it's not really a big deal. mQueuedSessions.erase(iter); queueMutex.Release(); return; } } queueMutex.Release(); } uint32 World::GetQueuePos(WorldSocket* Socket) { // Since we have multiple socket threads, better guard for this one, // we don't want heap corruption ;) queueMutex.Acquire(); // Find socket in list QueueSet::iterator iter = mQueuedSessions.begin(); uint32 QueuePos = 1; for(; iter != mQueuedSessions.end(); ++iter, ++QueuePos) { if((*iter) == Socket) { queueMutex.Release(); // Return our queue position. return QueuePos; } } queueMutex.Release(); // We shouldn't get here.. return 1; } void World::UpdateQueuedSessions(uint32 diff) { #ifndef CLUSTERING if(diff >= m_queueUpdateTimer) { m_queueUpdateTimer = mQueueUpdateInterval; queueMutex.Acquire(); if(mQueuedSessions.size() == 0) { queueMutex.Release(); return; } if(m_sessions.size() < m_playerLimit) { // Yay. We can let another player in now. // Grab the first fucker from the queue, but guard of course, since // this is in a different thread again. QueueSet::iterator iter = mQueuedSessions.begin(); WorldSocket * QueuedSocket = *iter; mQueuedSessions.erase(iter); // Welcome, sucker. if(QueuedSocket->GetSession()) { QueuedSocket->GetSession()->deleteMutex.Acquire(); QueuedSocket->Authenticate(); } } if(mQueuedSessions.size() == 0) { queueMutex.Release(); return; } // Update the remaining queue members. QueueSet::iterator iter = mQueuedSessions.begin(); uint32 Position = 1; for(; iter != mQueuedSessions.end(); ++iter, ++Position) { (*iter)->UpdateQueuePosition(Position); } queueMutex.Release(); } else { m_queueUpdateTimer -= diff; } #endif } void World::SaveAllPlayers() { if(!(ObjectMgr::getSingletonPtr() && WorldCreator::getSingletonPtr())) return; sLog.outString("Saving all players to database..."); uint32 count = 0; PlayerStorageMap::const_iterator itr; // Servers started and obviously runing. lets save all players. uint32 mt; objmgr._playerslock.AcquireReadLock(); for (itr = objmgr._players.begin(); itr != objmgr._players.end(); itr++) { if(itr->second->GetSession()) { mt = getMSTime(); itr->second->SaveToDB(false); sLog.outString("Saved player `%s` (level %u) in %ums.", itr->second->GetName(), itr->second->GetUInt32Value(UNIT_FIELD_LEVEL), getMSTime() - mt); ++count; } } objmgr._playerslock.ReleaseReadLock(); sLog.outString("Saved %u players.", count); } WorldSession* World::FindSessionByName(const char * Name)//case insensetive { m_sessionlock.AcquireReadLock(); // loop sessions, see if we can find him SessionMap::iterator itr = m_sessions.begin(); for(; itr != m_sessions.end(); ++itr) { if(!stricmp(itr->second->GetAccountName().c_str(),Name)) { m_sessionlock.ReleaseReadLock(); return itr->second; } } m_sessionlock.ReleaseReadLock(); return 0; } void World::BroadcastExtendedMessage(WorldSession * self, const char* str, ...) { va_list ap; va_start(ap, str); char msg[1024]; vsnprintf(msg, 1024, str, ap); va_end(ap); SessionSet::iterator itr = mExtendedSessions.begin(); WorldSession * s; for(; itr != mExtendedSessions.end(); ) { s = *itr; ++itr; if(s->GetPlayer() /*&& s != this*/) s->GetPlayer()->BroadcastMessage(msg); } } void World::ShutdownClasses() { sThreadMgr.Shutdown(); sLog.outString("Deleting Addon Manager..."); sAddonMgr.SaveToDB(); delete AddonMgr::getSingletonPtr(); sLog.outString("\nDeleting Auction Manager..."); delete AuctionMgr::getSingletonPtr(); sLog.outString("Deleting Loot Manager..."); delete LootMgr::getSingletonPtr(); sMailSystem.ShutdownMailSystem(); delete MailSystem::getSingletonPtr(); delete WorldCreator::getSingletonPtr(); } void World::EventDeleteBattleground(Battleground * BG) { // remove the instance //sWorldCreator.DestroyBattlegroundInstance(BG); //sBattlegroundMgr.RemoveBattleground(BG->GetID()); } void World::GetStats(uint32 * GMCount, float * AverageLatency) { int gm = 0; int count = 0; int avg = 0; PlayerStorageMap::const_iterator itr; objmgr._playerslock.AcquireReadLock(); for (itr = objmgr._players.begin(); itr != objmgr._players.end(); itr++) { if(itr->second->GetSession()) { count++; avg += itr->second->GetSession()->GetLatency(); if(itr->second->GetSession()->GetPermissionCount()) gm++; } } objmgr._playerslock.ReleaseReadLock(); *AverageLatency = count ? (float)((float)avg / (float)count) : 0; *GMCount = gm; } void TaskList::AddTask(Task * task) { queueLock.Acquire(); tasks.insert(task); queueLock.Release(); } Task * TaskList::GetTask() { queueLock.Acquire(); Task* t = 0; for(set::iterator itr = tasks.begin(); itr != tasks.end(); ++itr) { if(!(*itr)->in_progress) { t = (*itr); t->in_progress = true; break; } } queueLock.Release(); return t; } void TaskList::spawn() { running = true; thread_count = 0; uint32 threadcount; if(Config.MainConfig.GetBoolDefault("Startup", "EnableMultithreadedLoading", true)) { // get processor count #ifndef WIN32 #if UNIX_FLAVOUR == UNIX_FLAVOUR_LINUX long affmask; sched_getaffinity(0, 4, (cpu_set_t*)&affmask); threadcount = (BitCount8(affmask)) * 2; if(threadcount > 8) threadcount = 8; else if(threadcount <= 0) threadcount = 1; #else threadcount = 2; #endif #else SYSTEM_INFO s; GetSystemInfo(&s); threadcount = s.dwNumberOfProcessors * 2; #endif } else threadcount = 1; Log.Line(); Log.Notice("World", "Beginning %s server startup with %u threads.", (threadcount == 1) ? "progressive" : "parallel", threadcount); Log.Line(); for(uint32 x = 0; x < threadcount; ++x) launch_thread(new TaskExecutor(this)); } void TaskList::wait() { bool has_tasks = true; while(has_tasks) { queueLock.Acquire(); has_tasks = false; for(set::iterator itr = tasks.begin(); itr != tasks.end(); ++itr) { if(!(*itr)->completed) { has_tasks = true; break; } } queueLock.Release(); Sleep(20); } } void TaskList::kill() { running = false; } void Task::execute() { _cb->execute(); } void TaskExecutor::run() { Task * t; while(starter->running) { t = starter->GetTask(); if(t) { t->execute(); t->completed = true; starter->RemoveTask(t); delete t; } else Sleep(20); } } void TaskList::waitForThreadsToExit() { while(thread_count) { Sleep(20); } } void World::DeleteObject(Object * obj) { delete obj; } void World::Rehash(bool load) { if(load) Config.MainConfig.SetSource("ascent.conf", true); if(!ChannelMgr::getSingletonPtr()) new ChannelMgr; if(!MailSystem::getSingletonPtr()) new MailSystem; channelmgr.seperatechannels = Config.MainConfig.GetBoolDefault("Server", "SeperateChatChannels", false); sendRevisionOnJoin = Config.MainConfig.GetBoolDefault("Server", "SendBuildOnJoin", false); MapPath = Config.MainConfig.GetStringDefault("Terrain", "MapPath", "maps"); UnloadMapFiles = Config.MainConfig.GetBoolDefault("Terrain", "UnloadMapFiles", true); BreathingEnabled = Config.MainConfig.GetBoolDefault("Server", "EnableBreathing", true); SpeedhackProtection = Config.MainConfig.GetBoolDefault("Server", "SpeedhackProtection", false); SendStatsOnJoin = Config.MainConfig.GetBoolDefault("Server", "SendStatsOnJoin", true); compression_threshold = Config.MainConfig.GetIntDefault("Server", "CompressionThreshold", 1000); LevelCap = Config.MainConfig.GetIntDefault("Server", "LevelCap", 60); Expansion1LevelCap = Config.MainConfig.GetIntDefault("Server", "Expansion1LevelCap", 70); // load regeneration rates. setRate(RATE_HEALTH,Config.MainConfig.GetFloatDefault("Rates", "Health",1)); setRate(RATE_POWER1,Config.MainConfig.GetFloatDefault("Rates", "Power1",1)); setRate(RATE_POWER2,Config.MainConfig.GetFloatDefault("Rates", "Power2",1)); setRate(RATE_POWER3,Config.MainConfig.GetFloatDefault("Rates", "Power4",1)); setRate(RATE_DROP0,Config.MainConfig.GetFloatDefault("Rates", "DropGrey",1)); setRate(RATE_DROP1,Config.MainConfig.GetFloatDefault("Rates", "DropWhite",1)); setRate(RATE_DROP2,Config.MainConfig.GetFloatDefault("Rates", "DropGreen",1)); setRate(RATE_DROP3,Config.MainConfig.GetFloatDefault("Rates", "DropBlue",1)); setRate(RATE_DROP4,Config.MainConfig.GetFloatDefault("Rates", "DropPurple",1)); setRate(RATE_DROP5,Config.MainConfig.GetFloatDefault("Rates", "DropOrange",1)); setRate(RATE_DROP6,Config.MainConfig.GetFloatDefault("Rates", "DropArtifact",1)); setRate(RATE_XP,Config.MainConfig.GetFloatDefault("Rates", "XP",1)); setRate(RATE_RESTXP,Config.MainConfig.GetFloatDefault("Rates", "RestXP", 1)); setRate(RATE_QUESTXP,Config.MainConfig.GetFloatDefault("Rates", "QuestXP", 1)); setIntRate(INTRATE_SAVE, Config.MainConfig.GetIntDefault("Rates", "Save", 1)); setRate(RATE_MONEY, Config.MainConfig.GetFloatDefault("Rates", "DropMoney", 1.0f)); setRate(RATE_QUESTREPUTATION, Config.MainConfig.GetFloatDefault("Rates", "QuestReputation", 1.0f)); setRate(RATE_KILLREPUTATION, Config.MainConfig.GetFloatDefault("Rates", "KillReputation", 1.0f)); setRate(RATE_HONOR, Config.MainConfig.GetFloatDefault("Rates", "Honor", 1.0f)); setRate(RATE_SKILLCHANCE, Config.MainConfig.GetFloatDefault("Rates", "SkillChance", 1.0f)); setRate(RATE_SKILLRATE, Config.MainConfig.GetFloatDefault("Rates", "SkillRate", 1.0f)); setIntRate(INTRATE_COMPRESSION, Config.MainConfig.GetIntDefault("Rates", "Compression", 1)); setIntRate(INTRATE_PVPTIMER, Config.MainConfig.GetIntDefault("Rates", "PvPTimer", 300000)); SetPlayerLimit(Config.MainConfig.GetIntDefault("Server", "PlayerLimit", 1000)); SetMotd(Config.MainConfig.GetStringDefault("Server", "Motd", "Ascent Default MOTD").c_str()); SetUpdateDistance( Config.MainConfig.GetFloatDefault("Server", "PlrUpdateDistance", 79.1f) ); mQueueUpdateInterval = Config.MainConfig.GetIntDefault("Server", "QueueUpdateInterval", 5000); SetKickAFKPlayerTime(Config.MainConfig.GetIntDefault("Server", "KickAFKPlayers", 0)); sLog.SetScreenLoggingLevel(Config.MainConfig.GetIntDefault("LogLevel", "Screen", 1)); sLog.SetFileLoggingLevel(Config.MainConfig.GetIntDefault("LogLevel", "File", -1)); gm_skip_attunement = Config.MainConfig.GetBoolDefault("Server", "SkipAttunementsForGM", true); #ifndef CLUSTERING SocketRecvBufSize = Config.MainConfig.GetIntDefault("WorldSocket", "RecvBufSize", WORLDSOCKET_RECVBUF_SIZE); SocketSendBufSize = Config.MainConfig.GetIntDefault("WorldSocket", "SendBufSize", WORLDSOCKET_SENDBUF_SIZE); #endif bool log_enabled = Config.MainConfig.GetBoolDefault("Log", "Cheaters", false); if(Anticheat_Log->IsOpen()) { if(!log_enabled) Anticheat_Log->Close(); } else if(log_enabled) Anticheat_Log->Open(); log_enabled = Config.MainConfig.GetBoolDefault("Log", "GMCommands", false); if(GMCommand_Log->IsOpen()) { if(!log_enabled) GMCommand_Log->Close(); } else if(log_enabled) GMCommand_Log->Open(); #ifdef WIN32 DWORD current_priority_class = GetPriorityClass(GetCurrentProcess()); bool high = Config.MainConfig.GetBoolDefault("Server", "AdjustPriority", false); if(current_priority_class == HIGH_PRIORITY_CLASS && !high) SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); else if(current_priority_class != HIGH_PRIORITY_CLASS && high) SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); #endif reqGmClient = Config.MainConfig.GetBoolDefault("GMClient", "ReqGmClient", false); if(!Config.MainConfig.GetString("GMClient", "GmClientChannel", &GmClientChannel)) { GmClientChannel = ""; } realmtype = Config.MainConfig.GetBoolDefault("Server", "RealmType", false); TimeOut= uint32(1000* Config.MainConfig.GetIntDefault("Server", "ConnectionTimeout", 180) ); uint32 config_flags = 0; if(Config.MainConfig.GetBoolDefault("Mail", "DisablePostageCostsForGM", true)) config_flags |= MAIL_FLAG_NO_COST_FOR_GM; if(Config.MainConfig.GetBoolDefault("Mail", "DisablePostageCosts", false)) config_flags |= MAIL_FLAG_DISABLE_POSTAGE_COSTS; if(Config.MainConfig.GetBoolDefault("Mail", "DisablePostageDelayItems", true)) config_flags |= MAIL_FLAG_DISABLE_HOUR_DELAY_FOR_ITEMS; if(Config.MainConfig.GetBoolDefault("Mail", "DisableMessageExpiry", false)) config_flags |= MAIL_FLAG_NO_EXPIRY; if(Config.MainConfig.GetBoolDefault("Mail", "EnableInterfactionMail", true)) config_flags |= MAIL_FLAG_CAN_SEND_TO_OPPOSITE_FACTION; if(Config.MainConfig.GetBoolDefault("Mail", "EnableInterfactionForGM", true)) config_flags |= MAIL_FLAG_CAN_SEND_TO_OPPOSITE_FACTION_GM; sMailSystem.config_flags = config_flags; flood_lines = Config.MainConfig.GetIntDefault("FloodProtection", "Lines", 0); flood_seconds = Config.MainConfig.GetIntDefault("FloodProtection", "Seconds", 0); flood_message = Config.MainConfig.GetBoolDefault("FloodProtection", "SendMessage", false); show_gm_in_who_list = Config.MainConfig.GetBoolDefault("Server", "ShowGMInWhoList", true); if(!flood_lines || !flood_seconds) flood_lines = flood_seconds = 0; map_unload_time=Config.MainConfig.GetIntDefault("Server", "MapUnloadTime", 0); antihack_teleport = Config.MainConfig.GetBoolDefault("AntiHack", "Teleport", true); antihack_speed = Config.MainConfig.GetBoolDefault("AntiHack", "Speed", true); antihack_falldmg = Config.MainConfig.GetBoolDefault("AntiHack", "FallDamage", true); antihack_flight = Config.MainConfig.GetBoolDefault("AntiHack", "Flight", true); no_antihack_on_gm = Config.MainConfig.GetBoolDefault("AntiHack", "DisableOnGM", false); }