diff --git a/zone/client.cpp b/zone/client.cpp index 12105109f..1f1ab10b9 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -10013,4 +10013,124 @@ void Client::Fling(float value, float target_x, float target_y, float target_z, outapp_fling->priority = 6; FastQueuePacket(&outapp_fling); } -} \ No newline at end of file +} + +std::vector Client::GetLearnableDisciplines(uint8 min_level, uint8 max_level) { + bool SpellGlobalRule = RuleB(Spells, EnableSpellGlobals); + bool SpellBucketRule = RuleB(Spells, EnableSpellBuckets); + bool SpellGlobalCheckResult = false; + bool SpellBucketCheckResult = false; + std::vector learnable_disciplines; + for (int spell_id = 0; spell_id < SPDAT_RECORDS; ++spell_id) { + bool learnable = false; + if (!IsValidSpell(spell_id)) + continue; + if (!IsDiscipline(spell_id)) + continue; + if (spells[spell_id].classes[WARRIOR] == 0) + continue; + if (max_level > 0 && spells[spell_id].classes[m_pp.class_ - 1] > max_level) + continue; + if (min_level > 1 && spells[spell_id].classes[m_pp.class_ - 1] < min_level) + continue; + if (spells[spell_id].skill == 52) + continue; + if (RuleB(Spells, UseCHAScribeHack) && spells[spell_id].effectid[EFFECT_COUNT - 1] == 10) + continue; + if (HasDisciplineLearned(spell_id)) + continue; + + if (SpellGlobalRule) { + SpellGlobalCheckResult = SpellGlobalCheck(spell_id, CharacterID()); + if (SpellGlobalCheckResult) { + learnable = true; + } + } else if (SpellBucketRule) { + SpellBucketCheckResult = SpellBucketCheck(spell_id, CharacterID()); + if (SpellBucketCheckResult) { + learnable = true; + } + } else { + learnable = true; + } + + if (learnable) { + learnable_disciplines.push_back(spell_id); + } + } + return learnable_disciplines; +} + +std::vector Client::GetLearnedDisciplines() { + std::vector learned_disciplines; + for (int index = 0; index < MAX_PP_DISCIPLINES; index++) { + if (IsValidSpell(m_pp.disciplines.values[index])) { + learned_disciplines.push_back(m_pp.disciplines.values[index]); + } + } + return learned_disciplines; +} + +std::vector Client::GetMemmedSpells() { + std::vector memmed_spells; + for (int index = 0; index < EQ::spells::SPELL_GEM_COUNT; index++) { + if (IsValidSpell(m_pp.mem_spells[index])) { + memmed_spells.push_back(m_pp.mem_spells[index]); + } + } + return memmed_spells; +} + +std::vector Client::GetScribeableSpells(uint8 min_level, uint8 max_level) { + bool SpellGlobalRule = RuleB(Spells, EnableSpellGlobals); + bool SpellBucketRule = RuleB(Spells, EnableSpellBuckets); + bool SpellGlobalCheckResult = false; + bool SpellBucketCheckResult = false; + std::vector scribeable_spells; + for (int spell_id = 0; spell_id < SPDAT_RECORDS; ++spell_id) { + bool scribeable = false; + if (!IsValidSpell(spell_id)) + continue; + if (spells[spell_id].classes[WARRIOR] == 0) + continue; + if (max_level > 0 && spells[spell_id].classes[m_pp.class_ - 1] > max_level) + continue; + if (min_level > 1 && spells[spell_id].classes[m_pp.class_ - 1] < min_level) + continue; + if (spells[spell_id].skill == 52) + continue; + if (RuleB(Spells, UseCHAScribeHack) && spells[spell_id].effectid[EFFECT_COUNT - 1] == 10) + continue; + if (HasSpellScribed(spell_id)) + continue; + + if (SpellGlobalRule) { + SpellGlobalCheckResult = SpellGlobalCheck(spell_id, CharacterID()); + if (SpellGlobalCheckResult) { + scribeable = true; + } + } else if (SpellBucketRule) { + SpellBucketCheckResult = SpellBucketCheck(spell_id, CharacterID()); + if (SpellBucketCheckResult) { + scribeable = true; + } + } else { + scribeable = true; + } + + if (scribeable) { + scribeable_spells.push_back(spell_id); + } + } + return scribeable_spells; +} + +std::vector Client::GetScribedSpells() { + std::vector scribed_spells; + for(int index = 0; index < EQ::spells::SPELLBOOK_SIZE; index++) { + if (IsValidSpell(m_pp.spell_book[index])) { + scribed_spells.push_back(m_pp.spell_book[index]); + } + } + return scribed_spells; +} diff --git a/zone/client.h b/zone/client.h index 2b0693779..cc461bc22 100644 --- a/zone/client.h +++ b/zone/client.h @@ -784,6 +784,11 @@ public: void UnmemSpellAll(bool update_client = true); uint16 FindMemmedSpellBySlot(int slot); int MemmedCount(); + std::vector GetLearnableDisciplines(uint8 min_level = 1, uint8 max_level = 0); + std::vector GetLearnedDisciplines(); + std::vector GetMemmedSpells(); + std::vector GetScribeableSpells(uint8 min_level = 1, uint8 max_level = 0); + std::vector GetScribedSpells(); void ScribeSpell(uint16 spell_id, int slot, bool update_client = true); void UnscribeSpell(int slot, bool update_client = true); void UnscribeSpellAll(bool update_client = true); diff --git a/zone/lua_client.cpp b/zone/lua_client.cpp index fbe9bebdb..41d082cf3 100644 --- a/zone/lua_client.cpp +++ b/zone/lua_client.cpp @@ -634,6 +634,132 @@ int Lua_Client::MemmedCount() { return self->MemmedCount(); } +luabind::object Lua_Client::GetLearnableDisciplines(lua_State* L) { + auto lua_table = luabind::newtable(L); + if (d_) { + auto self = reinterpret_cast(d_); + auto learnable_disciplines = self->GetLearnableDisciplines(); + int index = 0; + for (auto spell_id : learnable_disciplines) { + lua_table[index] = spell_id; + index++; + } + } + return lua_table; +} + +luabind::object Lua_Client::GetLearnableDisciplines(lua_State* L, uint8 min_level) { + auto lua_table = luabind::newtable(L); + if (d_) { + auto self = reinterpret_cast(d_); + auto learnable_disciplines = self->GetLearnableDisciplines(min_level); + int index = 0; + for (auto spell_id : learnable_disciplines) { + lua_table[index] = spell_id; + index++; + } + } + return lua_table; +} + +luabind::object Lua_Client::GetLearnableDisciplines(lua_State* L, uint8 min_level, uint8 max_level) { + auto lua_table = luabind::newtable(L); + if (d_) { + auto self = reinterpret_cast(d_); + auto learnable_disciplines = self->GetLearnableDisciplines(min_level, max_level); + int index = 0; + for (auto spell_id : learnable_disciplines) { + lua_table[index] = spell_id; + index++; + } + } + return lua_table; +} + +luabind::object Lua_Client::GetLearnedDisciplines(lua_State* L) { + auto lua_table = luabind::newtable(L); + if (d_) { + auto self = reinterpret_cast(d_); + auto learned_disciplines = self->GetLearnedDisciplines(); + int index = 0; + for (auto spell_id : learned_disciplines) { + lua_table[index] = spell_id; + index++; + } + } + return lua_table; +} + +luabind::object Lua_Client::GetMemmedSpells(lua_State* L) { + auto lua_table = luabind::newtable(L); + if (d_) { + auto self = reinterpret_cast(d_); + auto memmed_spells = self->GetMemmedSpells(); + int index = 0; + for (auto spell_id : memmed_spells) { + lua_table[index] = spell_id; + index++; + } + } + return lua_table; +} + +luabind::object Lua_Client::GetScribeableSpells(lua_State* L) { + auto lua_table = luabind::newtable(L); + if (d_) { + auto self = reinterpret_cast(d_); + auto scribeable_spells = self->GetScribeableSpells(); + int index = 0; + for (auto spell_id : scribeable_spells) { + lua_table[index] = spell_id; + index++; + } + } + return lua_table; +} + +luabind::object Lua_Client::GetScribeableSpells(lua_State* L, uint8 min_level) { + auto lua_table = luabind::newtable(L); + if (d_) { + auto self = reinterpret_cast(d_); + auto scribeable_spells = self->GetScribeableSpells(min_level); + int index = 0; + for (auto spell_id : scribeable_spells) { + lua_table[index] = spell_id; + index++; + } + } + return lua_table; +} + +luabind::object Lua_Client::GetScribeableSpells(lua_State* L, uint8 min_level, uint8 max_level) { + auto lua_table = luabind::newtable(L); + if (d_) { + auto self = reinterpret_cast(d_); + auto scribeable_spells = self->GetScribeableSpells(min_level, max_level); + int index = 0; + for (auto spell_id : scribeable_spells) { + lua_table[index] = spell_id; + index++; + } + } + return lua_table; +} + +luabind::object Lua_Client::GetScribedSpells(lua_State* L) { + auto lua_table = luabind::newtable(L); + if (d_) { + auto self = reinterpret_cast(d_); + auto scribed_spells = self->GetScribedSpells(); + int index = 0; + for (auto spell_id : scribed_spells) { + lua_table[index] = spell_id; + index++; + } + } + return lua_table; +} + void Lua_Client::ScribeSpell(int spell_id, int slot) { Lua_Safe_Call_Void(); self->ScribeSpell(spell_id, slot); @@ -2050,6 +2176,15 @@ luabind::scope lua_register_client() { .def("UnmemSpellAll", (void(Lua_Client::*)(bool))&Lua_Client::UnmemSpellAll) .def("FindMemmedSpellBySlot", (uint16(Lua_Client::*)(int))&Lua_Client::FindMemmedSpellBySlot) .def("MemmedCount", (int(Lua_Client::*)(void))&Lua_Client::MemmedCount) + .def("GetLearnableDisciplines", (luabind::object(Lua_Client::*)(lua_State* L))&Lua_Client::GetLearnableDisciplines) + .def("GetLearnableDisciplines", (luabind::object(Lua_Client::*)(lua_State* L,uint8))&Lua_Client::GetLearnableDisciplines) + .def("GetLearnableDisciplines", (luabind::object(Lua_Client::*)(lua_State* L,uint8,uint8))&Lua_Client::GetLearnableDisciplines) + .def("GetLearnedDisciplines", (luabind::object(Lua_Client::*)(lua_State* L))&Lua_Client::GetLearnedDisciplines) + .def("GetMemmedSpells", (luabind::object(Lua_Client::*)(lua_State* L))&Lua_Client::GetMemmedSpells) + .def("GetScribedSpells", (luabind::object(Lua_Client::*)(lua_State* L))&Lua_Client::GetScribedSpells) + .def("GetScribeableSpells", (luabind::object(Lua_Client::*)(lua_State* L))&Lua_Client::GetScribeableSpells) + .def("GetScribeableSpells", (luabind::object(Lua_Client::*)(lua_State* L,uint8))&Lua_Client::GetScribeableSpells) + .def("GetScribeableSpells", (luabind::object(Lua_Client::*)(lua_State* L,uint8,uint8))&Lua_Client::GetScribeableSpells) .def("ScribeSpell", (void(Lua_Client::*)(int,int))&Lua_Client::ScribeSpell) .def("ScribeSpell", (void(Lua_Client::*)(int,int,bool))&Lua_Client::ScribeSpell) .def("UnscribeSpell", (void(Lua_Client::*)(int))&Lua_Client::UnscribeSpell) diff --git a/zone/lua_client.h b/zone/lua_client.h index fda6f08ee..90c15c065 100644 --- a/zone/lua_client.h +++ b/zone/lua_client.h @@ -152,6 +152,15 @@ public: void UnmemSpellAll(bool update_client); uint16 FindMemmedSpellBySlot(int slot); int MemmedCount(); + luabind::object GetLearnableDisciplines(lua_State* L); + luabind::object GetLearnableDisciplines(lua_State* L, uint8 min_level); + luabind::object GetLearnableDisciplines(lua_State* L, uint8 min_level, uint8 max_level); + luabind::object GetLearnedDisciplines(lua_State* L); + luabind::object GetMemmedSpells(lua_State* L); + luabind::object GetScribedSpells(lua_State* L); + luabind::object GetScribeableSpells(lua_State* L); + luabind::object GetScribeableSpells(lua_State* L, uint8 min_level); + luabind::object GetScribeableSpells(lua_State* L, uint8 min_level, uint8 max_level); void ScribeSpell(int spell_id, int slot); void ScribeSpell(int spell_id, int slot, bool update_client); void UnscribeSpell(int slot); diff --git a/zone/perl_client.cpp b/zone/perl_client.cpp index cf695d3a8..a1113601e 100644 --- a/zone/perl_client.cpp +++ b/zone/perl_client.cpp @@ -7164,6 +7164,130 @@ XS(XS_Client_GetRaceBitmask) { XSRETURN(1); } +XS(XS_Client_GetLearnableDisciplines); +XS(XS_Client_GetLearnableDisciplines) { + dXSARGS; + if (items < 1 || items > 3) + Perl_croak(aTHX_ "Usage: Client::GetLearnableDisciplines(THIS, [uint8 min_level, uint8 max_level])"); + + uint8 min_level = 1; + uint8 max_level = 0; + if (items > 1) + min_level = (uint8)SvUV(ST(1)); + if (items > 2) + max_level = (uint8)SvUV(ST(2)); + + Client* THIS; + VALIDATE_THIS_IS_CLIENT; + auto learnable_disciplines = THIS->GetLearnableDisciplines(min_level, max_level); + auto learnable_size = learnable_disciplines.size(); + if (learnable_size > 0) { + EXTEND(sp, learnable_size); + for (int index = 0; index < learnable_size; ++index) { + ST(index) = sv_2mortal(newSVuv(learnable_disciplines[index])); + } + XSRETURN(learnable_size); + } + SV* return_value = &PL_sv_undef; + ST(0) = return_value; + XSRETURN(1); +} + +XS(XS_Client_GetLearnedDisciplines); +XS(XS_Client_GetLearnedDisciplines) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Client::GetLearnedDisciplines(THIS)"); + + Client* THIS; + VALIDATE_THIS_IS_CLIENT; + auto learned_disciplines = THIS->GetLearnedDisciplines(); + auto learned_size = learned_disciplines.size(); + if (learned_size > 0) { + EXTEND(sp, learned_size); + for (int index = 0; index < learned_size; ++index) { + ST(index) = sv_2mortal(newSVuv(learned_disciplines[index])); + } + XSRETURN(learned_size); + } + SV* return_value = &PL_sv_undef; + ST(0) = return_value; + XSRETURN(1); +} + +XS(XS_Client_GetMemmedSpells); +XS(XS_Client_GetMemmedSpells) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Client::GetMemmedSpells(THIS)"); + + Client* THIS; + VALIDATE_THIS_IS_CLIENT; + auto memmed_spells = THIS->GetMemmedSpells(); + auto memmed_size = memmed_spells.size(); + if (memmed_size > 0) { + EXTEND(sp, memmed_size); + for (int index = 0; index < memmed_size; ++index) { + ST(index) = sv_2mortal(newSVuv(memmed_spells[index])); + } + XSRETURN(memmed_size); + } + SV* return_value = &PL_sv_undef; + ST(0) = return_value; + XSRETURN(1); +} + +XS(XS_Client_GetScribeableSpells); +XS(XS_Client_GetScribeableSpells) { + dXSARGS; + if (items < 1 || items > 3) + Perl_croak(aTHX_ "Usage: Client::GetScribeableSpells(THIS, [uint8 min_level, uint8 max_level])"); + + uint8 min_level = 1; + uint8 max_level = 0; + if (items > 1) + min_level = (uint8)SvUV(ST(1)); + if (items > 2) + max_level = (uint8)SvUV(ST(2)); + + Client* THIS; + VALIDATE_THIS_IS_CLIENT; + auto scribeable_spells = THIS->GetScribeableSpells(min_level, max_level); + auto scribeable_size = scribeable_spells.size(); + if (scribeable_size > 0) { + EXTEND(sp, scribeable_size); + for (int index = 0; index < scribeable_size; ++index) { + ST(index) = sv_2mortal(newSVuv(scribeable_spells[index])); + } + XSRETURN(scribeable_size); + } + SV* return_value = &PL_sv_undef; + ST(0) = return_value; + XSRETURN(1); +} + +XS(XS_Client_GetScribedSpells); +XS(XS_Client_GetScribedSpells) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Client::GetScribedSpells(THIS)"); + + Client* THIS; + VALIDATE_THIS_IS_CLIENT; + auto scribed_spells = THIS->GetScribedSpells(); + auto scribed_size = scribed_spells.size(); + if (scribed_size > 0) { + EXTEND(sp, scribed_size); + for (int index = 0; index < scribed_size; ++index) { + ST(index) = sv_2mortal(newSVuv(scribed_spells[index])); + } + XSRETURN(scribed_size); + } + SV* return_value = &PL_sv_undef; + ST(0) = return_value; + XSRETURN(1); +} + #ifdef __cplusplus extern "C" #endif @@ -7291,8 +7415,11 @@ XS(boot_Client) { newXSproto(strcpy(buf, "GetLDoNPointsTheme"), XS_Client_GetLDoNPointsTheme, file, "$"); newXSproto(strcpy(buf, "GetLDoNWins"), XS_Client_GetLDoNWins, file, "$"); newXSproto(strcpy(buf, "GetLDoNWinsTheme"), XS_Client_GetLDoNWinsTheme, file, "$$"); + newXSproto(strcpy(buf, "GetLearnableDisciplines"), XS_Client_GetLearnableDisciplines, file, "$;$$"); + newXSproto(strcpy(buf, "GetLearnedDisciplines"), XS_Client_GetLearnedDisciplines, file, "$"); newXSproto(strcpy(buf, "GetLockoutExpeditionUUID"), XS_Client_GetLockoutExpeditionUUID, file, "$$$"); newXSproto(strcpy(buf, "GetMaxEndurance"), XS_Client_GetMaxEndurance, file, "$"); + newXSproto(strcpy(buf, "GetMemmedSpells"), XS_Client_GetMemmedSpells, file, "$"); newXSproto(strcpy(buf, "GetModCharacterFactionLevel"), XS_Client_GetModCharacterFactionLevel, file, "$$"); newXSproto(strcpy(buf, "GetMoney"), XS_Client_GetMoney, file, "$$$"); newXSproto(strcpy(buf, "GetPVP"), XS_Client_GetPVP, file, "$"); @@ -7303,6 +7430,8 @@ XS(boot_Client) { newXSproto(strcpy(buf, "GetRaidPoints"), XS_Client_GetRaidPoints, file, "$"); newXSproto(strcpy(buf, "GetRawItemAC"), XS_Client_GetRawItemAC, file, "$"); newXSproto(strcpy(buf, "GetRawSkill"), XS_Client_GetRawSkill, file, "$$"); + newXSproto(strcpy(buf, "GetScribeableSpells"), XS_Client_GetScribeableSpells, file, "$;$$"); + newXSproto(strcpy(buf, "GetScribedSpells"), XS_Client_GetScribedSpells, file, "$"); newXSproto(strcpy(buf, "GetSkillPoints"), XS_Client_GetSkillPoints, file, "$"); newXSproto(strcpy(buf, "GetSpellBookSlotBySpellID"), XS_Client_GetSpellBookSlotBySpellID, file, "$$"); newXSproto(strcpy(buf, "GetSpellIDByBookSlot"), XS_Client_GetSpellIDByBookSlot, file, "$$"); diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index e75fa0a01..3c4522630 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -1088,174 +1088,47 @@ void QuestManager::permagender(int gender_id) { uint16 QuestManager::scribespells(uint8 max_level, uint8 min_level) { QuestManagerCurrentQuestVars(); int book_slot = initiator->GetNextAvailableSpellBookSlot(); - int spell_id = 0; - int count = 0; - - uint32 char_id = initiator->CharacterID(); - bool SpellGlobalRule = RuleB(Spells, EnableSpellGlobals); - bool SpellBucketRule = RuleB(Spells, EnableSpellBuckets); - bool SpellGlobalCheckResult = false; - bool SpellBucketCheckResult = false; - - for ( ; spell_id < SPDAT_RECORDS && book_slot < EQ::spells::SPELLBOOK_SIZE; ++spell_id) { - if (book_slot == -1) { - initiator->Message( - 13, - "Unable to scribe spell %s (%i) to spellbook: no more spell book slots available.", - ((spell_id >= 0 && spell_id < SPDAT_RECORDS) ? spells[spell_id].name : "Out-of-range"), - spell_id - ); - - break; - } - if (spell_id < 0 || spell_id >= SPDAT_RECORDS) { - initiator->Message(Chat::Red, "FATAL ERROR: Spell id out-of-range (id: %i, min: 0, max: %i)", spell_id, SPDAT_RECORDS); - return count; - } - if (book_slot < 0 || book_slot >= EQ::spells::SPELLBOOK_SIZE) { - initiator->Message(Chat::Red, "FATAL ERROR: Book slot out-of-range (slot: %i, min: 0, max: %i)", book_slot, EQ::spells::SPELLBOOK_SIZE); - return count; - } - - while (true) { - if (spells[spell_id].classes[WARRIOR] == 0) // check if spell exists + std::vector spell_ids = initiator->GetScribeableSpells(min_level, max_level); + int spell_count = spell_ids.size(); + if (spell_count > 0) { + for (auto spell_id : spell_ids) { + if (book_slot == -1) { + initiator->Message( + Chat::Red, + "Unable to scribe spell %s (%i) to Spell Book: Spell Book is Full.", spells[spell_id].name, spell_id + ); break; - if (spells[spell_id].classes[initiator->GetPP().class_ - 1] > max_level) // maximum level - break; - if (spells[spell_id].classes[initiator->GetPP().class_ - 1] < min_level) // minimum level - break; - if (spells[spell_id].skill == 52) - break; - if (spells[spell_id].effectid[EFFECT_COUNT - 1] == 10) - break; - - uint16 spell_id_ = (uint16)spell_id; - if ((spell_id_ != spell_id) || (spell_id != spell_id_)) { - initiator->Message(Chat::Red, "FATAL ERROR: Type conversion data loss with spell_id (%i != %u)", spell_id, spell_id_); - return count; } - - if (!IsDiscipline(spell_id_) && !initiator->HasSpellScribed(spell_id)) { // isn't a discipline & we don't already have it scribed - if (SpellGlobalRule) { - // bool to see if the character has the required QGlobal to scribe it if one exists in the Spell_Globals table - SpellGlobalCheckResult = initiator->SpellGlobalCheck(spell_id_, char_id); - if (SpellGlobalCheckResult) { - initiator->ScribeSpell(spell_id_, book_slot); - ++count; - } - } - else if (SpellBucketRule) { - // bool to see if the character has the required bucket to train it if one exists in the spell_buckets table - SpellBucketCheckResult = initiator->SpellBucketCheck(spell_id_, char_id); - if (SpellBucketCheckResult) { - initiator->ScribeSpell(spell_id_, book_slot); - ++count; - } - } - else { - initiator->ScribeSpell(spell_id_, book_slot); - ++count; - } - } - - break; + initiator->ScribeSpell(spell_id, book_slot); + book_slot = initiator->GetNextAvailableSpellBookSlot(book_slot); } - - book_slot = initiator->GetNextAvailableSpellBookSlot(book_slot); } - - return count; // how many spells were scribed successfully + return spell_count; } uint16 QuestManager::traindiscs(uint8 max_level, uint8 min_level) { QuestManagerCurrentQuestVars(); - int spell_id = 0; - int count = 0; - - uint32 char_id = initiator->CharacterID(); - bool SpellGlobalRule = RuleB(Spells, EnableSpellGlobals); - bool SpellBucketRule = RuleB(Spells, EnableSpellBuckets); - bool SpellGlobalCheckResult = false; - bool SpellBucketCheckResult = false; - - bool change = false; - - for( ; spell_id < SPDAT_RECORDS; ++spell_id) { - if (spell_id < 0 || spell_id >= SPDAT_RECORDS) { - initiator->Message(Chat::Red, "FATAL ERROR: Spell id out-of-range (id: %i, min: 0, max: %i)", spell_id, SPDAT_RECORDS); - return count; - } - - while (true) { - if (spells[spell_id].classes[WARRIOR] == 0) // check if spell exists - break; - if (spells[spell_id].classes[initiator->GetPP().class_ - 1] > max_level) // maximum level - break; - if (spells[spell_id].classes[initiator->GetPP().class_ - 1] < min_level) // minimum level - break; - if (spells[spell_id].skill == 52) - break; - if (RuleB(Spells, UseCHAScribeHack) && spells[spell_id].effectid[EFFECT_COUNT - 1] == 10) - break; - - uint16 spell_id_ = (uint16)spell_id; - if ((spell_id_ != spell_id) || (spell_id != spell_id_)) { - initiator->Message(Chat::Red, "FATAL ERROR: Type conversion data loss with spell_id (%i != %u)", spell_id, spell_id_); - return count; - } - - if (!IsDiscipline(spell_id_)) - break; - - for (uint32 r = 0; r < MAX_PP_DISCIPLINES; r++) { - if (initiator->GetPP().disciplines.values[r] == spell_id_) { - initiator->Message(Chat::Red, "You already know this discipline."); - break; // continue the 1st loop - } - else if (initiator->GetPP().disciplines.values[r] == 0) { - if (SpellGlobalRule) { - // bool to see if the character has the required QGlobal to train it if one exists in the Spell_Globals table - SpellGlobalCheckResult = initiator->SpellGlobalCheck(spell_id_, char_id); - if (SpellGlobalCheckResult) { - initiator->GetPP().disciplines.values[r] = spell_id_; - database.SaveCharacterDisc(char_id, r, spell_id_); - change = true; - initiator->Message(Chat::White, "You have learned a new discipline!"); - ++count; // success counter - } - break; // continue the 1st loop - } - else if (SpellBucketRule) { - // bool to see if the character has the required bucket to train it if one exists in the spell_buckets table - SpellBucketCheckResult = initiator->SpellBucketCheck(spell_id_, char_id); - if (SpellBucketCheckResult) { - initiator->GetPP().disciplines.values[r] = spell_id_; - database.SaveCharacterDisc(char_id, r, spell_id_); - change = true; - initiator->Message(Chat::White, "You have learned a new discipline!"); - ++count; - } - break; - } - else { - initiator->GetPP().disciplines.values[r] = spell_id_; - database.SaveCharacterDisc(char_id, r, spell_id_); - change = true;; - initiator->Message(Chat::White, "You have learned a new discipline!"); - ++count; // success counter - break; // continue the 1st loop - } + int character_id = initiator->CharacterID(); + std::vector spell_ids = initiator->GetLearnableDisciplines(min_level, max_level); + int discipline_count = spell_ids.size(); + bool discipline_learned = false; + if (discipline_count > 0) { + for (auto spell_id : spell_ids) { + for (uint32 index = 0; index < MAX_PP_DISCIPLINES; index++) { + if (initiator->GetPP().disciplines.values[index] == 0) { + initiator->GetPP().disciplines.values[index] = spell_id; + database.SaveCharacterDisc(character_id, index, spell_id); + initiator->Message(Chat::White, "You have learned a new discipline!"); + discipline_learned = true; } } - - break; } } - if (change) + if (discipline_learned) initiator->SendDisciplineUpdate(); - return count; // how many disciplines were learned successfully + return discipline_count; } void QuestManager::unscribespells() {