diff --git a/source/WorldServer/Bots/Bot.cpp b/source/WorldServer/Bots/Bot.cpp index 630b873..5035052 100644 --- a/source/WorldServer/Bots/Bot.cpp +++ b/source/WorldServer/Bots/Bot.cpp @@ -154,9 +154,9 @@ void Bot::MessageGroup(string msg) { void Bot::GetNewSpells() { vector spells; - vector* spells1 = master_spell_list.GetSpellListByAdventureClass(GetAdventureClass(), GetLevel(), 1); - vector* spells2 = master_spell_list.GetSpellListByAdventureClass(classes.GetBaseClass(GetAdventureClass()), GetLevel(), 1); - vector* spells3 = master_spell_list.GetSpellListByAdventureClass(classes.GetSecondaryBaseClass(GetAdventureClass()), GetLevel(), 1); + vector* spells1 = master_spell_list.GetSpellListByAdventureClass(GetAdventureClass(), (double)GetLevel(), 1); + vector* spells2 = master_spell_list.GetSpellListByAdventureClass(classes.GetBaseClass(GetAdventureClass()), (double)GetLevel(), 1); + vector* spells3 = master_spell_list.GetSpellListByAdventureClass(classes.GetSecondaryBaseClass(GetAdventureClass()), (double)GetLevel(), 1); spells.insert(spells.end(), spells1->begin(), spells1->end()); spells.insert(spells.end(), spells2->begin(), spells2->end()); diff --git a/source/WorldServer/Entity.cpp b/source/WorldServer/Entity.cpp index 76d646a..bd3554d 100644 --- a/source/WorldServer/Entity.cpp +++ b/source/WorldServer/Entity.cpp @@ -2505,8 +2505,11 @@ void Entity::CureDetrimentByType(int8 cure_count, int8 det_type, string cure_nam bool has_level_checks = false; for (int32 x = 0; x < levels->size(); x++){ has_level_checks = true; + int8 use_classic_lvls = rule_manager.GetGlobalRule(R_Spells, UseClassicSpellLevel)->GetInt8(); + if(levels->at(x)->classic_spell_level == 0.0f) + use_classic_lvls = 0; // class checks are worthless we can't guarantee the caster is that class - if (!cure_level || cure_level >= (levels->at(x)->spell_level / 10)){ + if (!cure_level || (use_classic_lvls && cure_level >= std::floor(levels->at(x)->classic_spell_level)) || (!use_classic_lvls && cure_level >= (levels->at(x)->spell_level / 10))){ pass_level_check = true; break; } @@ -2555,7 +2558,10 @@ void Entity::CureDetrimentByControlEffect(int8 cure_count, int8 control_type, st info_struct = det->caster->GetInfoStruct(); pass_level_check = false; for (int32 x = 0; x < levels->size(); x++){ - if (!cure_level || cure_level >= (levels->at(x)->spell_level / 10)){ + int8 use_classic_lvls = rule_manager.GetGlobalRule(R_Spells, UseClassicSpellLevel)->GetInt8(); + if(levels->at(x)->classic_spell_level == 0.0f) + use_classic_lvls = 0; + if (!cure_level || (use_classic_lvls && cure_level >= std::floor(levels->at(x)->classic_spell_level)) || (!use_classic_lvls && cure_level >= (levels->at(x)->spell_level / 10))){ pass_level_check = true; break; } diff --git a/source/WorldServer/Player.cpp b/source/WorldServer/Player.cpp index 3d9e227..738ceca 100644 --- a/source/WorldServer/Player.cpp +++ b/source/WorldServer/Player.cpp @@ -4490,6 +4490,8 @@ bool Player::AddXP(int32 xp_amount){ GetPlayerInfo()->CalculateXPPercentages(); current_xp_percent = ((float)GetXP()/(float)GetNeededXP())*100; if(current_xp_percent >= miniding_min_percent){ + if(GetClient() && rule_manager.GetGlobalRule(R_Spells, UseClassicSpellLevel)->GetInt8()) + GetClient()->SendNewAdventureSpells(); // mini ding involves checking spells again in classic level settings SetHP(GetTotalHP()); SetPower(GetTotalPower()); GetZone()->SendCastSpellPacket(332, this, this); //send mini level up spell effect diff --git a/source/WorldServer/Rules/Rules.cpp b/source/WorldServer/Rules/Rules.cpp index a8f04e6..5e87bfd 100644 --- a/source/WorldServer/Rules/Rules.cpp +++ b/source/WorldServer/Rules/Rules.cpp @@ -394,6 +394,7 @@ void RuleManager::Init() RULE_INIT(R_Spells, MinistrationPowerReductionMax, "15.0"); // max percentage of power reduction for spells with ministration mastery skill (default is 15.0 for 15%) RULE_INIT(R_Spells, MinistrationPowerReductionSkill, "25"); // divides by integer value to establish how much skill req for higher power reduction RULE_INIT(R_Spells, MasterSkillReduceSpellResist, "25"); // divides by integer value to establish how much skill bonus for reducing spell resistance on target + RULE_INIT(R_Spells, UseClassicSpellLevel, "0"); // Uses fractional spell levels (eg. you gain spells inbetween levels). RULE_INIT(R_Expansion, GlobalExpansionFlag, "0"); RULE_INIT(R_Expansion, GlobalHolidayFlag, "0"); diff --git a/source/WorldServer/Rules/Rules.h b/source/WorldServer/Rules/Rules.h index 83eaf1e..e55e0ad 100644 --- a/source/WorldServer/Rules/Rules.h +++ b/source/WorldServer/Rules/Rules.h @@ -240,6 +240,7 @@ enum RuleType { MinistrationPowerReductionMax, MinistrationPowerReductionSkill, MasterSkillReduceSpellResist, + UseClassicSpellLevel, /* ZONE TIMERS */ RegenTimer, diff --git a/source/WorldServer/Spells.cpp b/source/WorldServer/Spells.cpp index 3b4cbc1..2db5541 100644 --- a/source/WorldServer/Spells.cpp +++ b/source/WorldServer/Spells.cpp @@ -167,7 +167,7 @@ Spell::Spell(Spell* host_spell, bool unique_spell) for (itr = host_spell->levels.begin(); itr != host_spell->levels.end(); itr++) { LevelArray* lvlArray = *itr; - AddSpellLevel(lvlArray->adventure_class, lvlArray->tradeskill_class, lvlArray->spell_level); + AddSpellLevel(lvlArray->adventure_class, lvlArray->tradeskill_class, lvlArray->spell_level, lvlArray->classic_spell_level); } std::vector::iterator sdeitr; @@ -295,7 +295,10 @@ int16 Spell::GetLevelRequired(Player* player){ for(itr = levels.begin(); itr != levels.end(); itr++){ level = *itr; if(level && level->adventure_class == player->GetAdventureClass()){ - ret = level->spell_level/10; + if(rule_manager.GetGlobalRule(R_Spells, UseClassicSpellLevel)->GetInt8() && level->classic_spell_level > 0.0f) + ret = std::floor(level->classic_spell_level); + else + ret = level->spell_level/10; break; } } @@ -722,7 +725,12 @@ void Spell::AppendLevelInformation(PacketStruct* packet) { LevelArray* levelData = tmpArray->at(i); packet->setArrayDataByName("adventure_class", levelData->adventure_class, i); packet->setArrayDataByName("tradeskill_class", levelData->tradeskill_class, i); - packet->setArrayDataByName("spell_level", levelData->spell_level, i); + if(rule_manager.GetGlobalRule(R_Spells, UseClassicSpellLevel)->GetInt8() && levelData->classic_spell_level) { + packet->setArrayDataByName("spell_level", (int16)(levelData->classic_spell_level * 10.0f), i); + } + else { + packet->setArrayDataByName("spell_level", levelData->spell_level, i); + } } } @@ -1270,12 +1278,13 @@ const char* Spell::GetDescription(){ return spell->description.data.c_str(); } -void Spell::AddSpellLevel(int8 adventure_class, int8 tradeskill_class, int16 level){ +void Spell::AddSpellLevel(int8 adventure_class, int8 tradeskill_class, int16 level, float classic_spell_level){ std::unique_lock lock(MSpellInfo); LevelArray* lvl = new LevelArray; lvl->adventure_class = adventure_class; lvl->tradeskill_class = tradeskill_class; lvl->spell_level = level; + lvl->classic_spell_level = classic_spell_level; levels.push_back(lvl); } @@ -2169,14 +2178,15 @@ vector * Spell::GetSpellLevels(){ bool Spell::ScribeAllowed(Player* player){ std::shared_lock lock(MSpellInfo); bool ret = false; + double current_xp_percent = ((double)player->GetXP()/(double)player->GetNeededXP())*100; if(player){ for(int32 i=0;!ret && iGetLevel(); - int16 spelllevels = levels[i]->spell_level; - bool advlev = player->GetAdventureClass() == levels[i]->adventure_class; - bool tslev = player->GetTradeskillClass() == levels[i]->tradeskill_class; - bool levelmatch = player->GetLevel() >= levels[i]->spell_level; - if((player->GetAdventureClass() == levels[i]->adventure_class || player->GetTradeskillClass() == levels[i]->tradeskill_class) && player->GetLevel() >= levels[i]->spell_level/10) + bool classiclevelmatch = ((double)player->GetLevel()+current_xp_percent) >= levels[i]->classic_spell_level; + bool classic_match_only = false; + if(levels[i]->classic_spell_level > 0.0f && rule_manager.GetGlobalRule(R_Spells, UseClassicSpellLevel)->GetInt8()) { + classic_match_only = true; + } + if((player->GetAdventureClass() == levels[i]->adventure_class || player->GetTradeskillClass() == levels[i]->tradeskill_class) && ((!classic_match_only && player->GetLevel() >= levels[i]->spell_level/10) || (classic_match_only && classiclevelmatch))) ret = true; } } @@ -2332,12 +2342,13 @@ EQ2Packet* MasterSpellList::GetSpecialSpellPacket(int32 id, int8 tier, Client* c return 0; } -vector* MasterSpellList::GetSpellListByAdventureClass(int8 class_id, int16 max_level, int8 max_tier){ +vector* MasterSpellList::GetSpellListByAdventureClass(int8 class_id, double max_level_classic, int8 max_tier){ vector* ret = new vector; if(class_id >= MAX_CLASSES) { return ret; } + int8 use_classic_levels = rule_manager.GetGlobalRule(R_Spells, UseClassicSpellLevel)->GetInt8(); Spell* spell = 0; vector* levels = 0; LevelArray* level = 0; @@ -2345,7 +2356,7 @@ vector* MasterSpellList::GetSpellListByAdventureClass(int8 class_id, int MMasterSpellList.lock(); map >::iterator iter; map::iterator iter2; - max_level *= 10; //convert to client level format, which is 10 times higher + int16 max_level = std::floor(max_level_classic) * 10; //convert to client level format, which is 10 times higher for(iter = class_spell_list[class_id].begin();iter != class_spell_list[class_id].end(); iter++){ for(iter2 = iter->second.begin();iter2 != iter->second.end(); iter2++){ spell = iter2->second; @@ -2354,9 +2365,15 @@ vector* MasterSpellList::GetSpellListByAdventureClass(int8 class_id, int levels = spell->GetSpellLevels(); for(level_itr = levels->begin(); level_itr != levels->end(); level_itr++){ level = *level_itr; - if(level->spell_level <= max_level && level->adventure_class == class_id){ - ret->push_back(spell); - break; + if(level->adventure_class == class_id){ + if((!use_classic_levels || level->classic_spell_level == 0.0f) && level->spell_level <= max_level) { + ret->push_back(spell); + break; + } + else if(use_classic_levels && level->classic_spell_level <= max_level_classic) { + ret->push_back(spell); + break; + } } } } diff --git a/source/WorldServer/Spells.h b/source/WorldServer/Spells.h index a3b2af8..8a86cf4 100644 --- a/source/WorldServer/Spells.h +++ b/source/WorldServer/Spells.h @@ -218,6 +218,7 @@ struct LevelArray{ int8 adventure_class; int8 tradeskill_class; int16 spell_level; + float classic_spell_level; }; struct SpellDisplayEffect{ int8 percentage; @@ -328,7 +329,7 @@ public: EQ2Packet* SerializeSpell(Client* client, bool display, bool trait_display = false, int8 packet_type = 0, int8 sub_packet_type = 0, const char* struct_name = 0, bool send_partial_packet = false); EQ2Packet* SerializeSpecialSpell(Client* client, bool display, int8 packet_type = 0, int8 sub_packet_type = 0); EQ2Packet* SerializeAASpell(Client* client,int8 tier, AltAdvanceData* data, bool display, bool trait_display = false, int8 packet_type = 0, int8 sub_packet_type = 0, const char* struct_name = 0); - void AddSpellLevel(int8 adventure_class, int8 tradeskill_class, int16 level); + void AddSpellLevel(int8 adventure_class, int8 tradeskill_class, int16 level, float classic_spell_level); void AddSpellEffect(int8 percentage, int8 subbullet, string description); void AddSpellLuaData(int8 type, int int_value, int int_value2, float float_value, float float_value2, bool bool_value, string string_value,string string_value2, string helper); void AddSpellLuaDataInt(int value, int value2, string helper); @@ -402,7 +403,7 @@ public: map > class_spell_list[MAX_CLASSES]; map spell_soecrc_map; Spell* GetSpell(int32 id, int8 tier); - vector* GetSpellListByAdventureClass(int8 class_id, int16 max_level, int8 max_tier); + vector* GetSpellListByAdventureClass(int8 class_id, double max_level, int8 max_tier); vector* GetSpellListByTradeskillClass(int8 class_id, int16 max_level, int8 max_tier); Spell* GetSpellByName(const char* name); Spell* GetSpellByCRC(int32 spell_crc); diff --git a/source/WorldServer/WorldDatabase.cpp b/source/WorldServer/WorldDatabase.cpp index a5bfae0..a26a7c3 100644 --- a/source/WorldServer/WorldDatabase.cpp +++ b/source/WorldServer/WorldDatabase.cpp @@ -4872,7 +4872,7 @@ void WorldDatabase::SaveQuickBar(int32 char_id, vector* quickbar_ map >* WorldDatabase::LoadSpellClasses(){ map >* ret = new map >(); Query query; - MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT spell_id, adventure_class_id, tradeskill_class_id, level FROM spell_classes"); + MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT spell_id, adventure_class_id, tradeskill_class_id, level, classic_level FROM spell_classes"); MYSQL_ROW row; LevelArray* level = 0; while(result && (row = mysql_fetch_row(result))){ @@ -4880,6 +4880,7 @@ map >* WorldDatabase::LoadSpellClasses(){ level->adventure_class = atoi(row[1]); level->tradeskill_class = atoi(row[2]); level->spell_level = atoi(row[3]); + level->classic_spell_level = atof(row[4]); (*ret)[atoul(row[0])].push_back(level); } return ret; @@ -5101,7 +5102,7 @@ void WorldDatabase::LoadSpells() for(int8 i=0; isize(); i++) { - spell->AddSpellLevel(level_array->at(i)->adventure_class, level_array->at(i)->tradeskill_class, level_array->at(i)->spell_level*10); + spell->AddSpellLevel(level_array->at(i)->adventure_class, level_array->at(i)->tradeskill_class, level_array->at(i)->spell_level*10, level_array->at(i)->classic_spell_level); } } diff --git a/source/WorldServer/client.cpp b/source/WorldServer/client.cpp index 4aa5c92..e6e9e79 100644 --- a/source/WorldServer/client.cpp +++ b/source/WorldServer/client.cpp @@ -10167,8 +10167,9 @@ void Client::ProcessTeleportLocation(EQApplicationPacket* app) { } void Client::SendNewSpells(int8 class_id) { - if (class_id > 0) { - vector* spells = master_spell_list.GetSpellListByAdventureClass(class_id, player->GetLevel(), 1); + if (class_id > 0 && player) { + double current_xp_percent = ((double)player->GetXP()/(double)player->GetNeededXP())*100; + vector* spells = master_spell_list.GetSpellListByAdventureClass(class_id, (double)player->GetLevel()+current_xp_percent, 1); AddSendNewSpells(spells); safe_delete(spells); }