[Spells] Adds a rule to allow right-click memorize from spell scrolls. (#1377)

* [Spells] Adds a rule to allow right-click memorize from spell scrolls.

* Typo.
This commit is contained in:
Alex 2021-06-11 14:41:08 -04:00 committed by GitHub
parent ebdb8e5d90
commit d54cd08560
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 90 additions and 2 deletions

View File

@ -373,6 +373,7 @@ RULE_BOOL(Spells, NPCSpellPush, false, "Enable spell push on NPCs")
RULE_BOOL(Spells, July242002PetResists, true, "Enable Pets using PCs resist change from July 24 2002") RULE_BOOL(Spells, July242002PetResists, true, "Enable Pets using PCs resist change from July 24 2002")
RULE_INT(Spells, AOEMaxTargets, 0, "Max number of targets a Targeted AOE spell can cast on. Set to 0 for no limit.") RULE_INT(Spells, AOEMaxTargets, 0, "Max number of targets a Targeted AOE spell can cast on. Set to 0 for no limit.")
RULE_BOOL(Spells, AllowDoubleInvis, false, "Allows you to cast invisibility spells on a player that is already invisible") RULE_BOOL(Spells, AllowDoubleInvis, false, "Allows you to cast invisibility spells on a player that is already invisible")
RULE_BOOL(Spells, AllowSpellMemorizeFromItem, false, "Allows players to memorize spells by right-clicking spell scrolls")
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(Combat) RULE_CATEGORY(Combat)

View File

@ -10102,7 +10102,7 @@ std::vector<int> Client::GetScribedSpells() {
if (IsValidSpell(m_pp.spell_book[index])) { if (IsValidSpell(m_pp.spell_book[index])) {
scribed_spells.push_back(m_pp.spell_book[index]); scribed_spells.push_back(m_pp.spell_book[index]);
} }
} }
return scribed_spells; return scribed_spells;
} }

View File

@ -982,6 +982,7 @@ public:
void ResetTrade(); void ResetTrade();
void DropInst(const EQ::ItemInstance* inst); void DropInst(const EQ::ItemInstance* inst);
bool TrainDiscipline(uint32 itemid); bool TrainDiscipline(uint32 itemid);
bool MemorizeSpellFromItem(uint32 item_id);
void TrainDiscBySpellID(int32 spell_id); void TrainDiscBySpellID(int32 spell_id);
uint32 GetDisciplineTimer(uint32 timer_id); uint32 GetDisciplineTimer(uint32 timer_id);
int GetDiscSlotBySpellID(int32 spellid); int GetDiscSlotBySpellID(int32 spellid);

View File

@ -8876,7 +8876,12 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app)
} }
else if (item->ItemType == EQ::item::ItemTypeSpell) else if (item->ItemType == EQ::item::ItemTypeSpell)
{ {
return; if (RuleB(Spells, AllowSpellMemorizeFromItem)) {
DeleteItemInInventory(slot_id, 1, true);
MemorizeSpellFromItem(item->ID);
} else {
return;
}
} }
else if ((item->Click.Type == EQ::item::ItemEffectClick) || (item->Click.Type == EQ::item::ItemEffectExpendable) || (item->Click.Type == EQ::item::ItemEffectEquipClick) || (item->Click.Type == EQ::item::ItemEffectClick2)) else if ((item->Click.Type == EQ::item::ItemEffectClick) || (item->Click.Type == EQ::item::ItemEffectExpendable) || (item->Click.Type == EQ::item::ItemEffectEquipClick) || (item->Click.Type == EQ::item::ItemEffectClick2))
{ {

View File

@ -509,6 +509,87 @@ bool Client::TrainDiscipline(uint32 itemid) {
return(false); return(false);
} }
bool Client::MemorizeSpellFromItem(uint32 item_id) {
const EQ::ItemData *item = database.GetItem(item_id);
if(item == nullptr) {
Message(Chat::Red, "Unable to find the scroll!");
LogError("Unable to find scroll id [{}]\n", (unsigned long)item_id);
return false;
}
if (!item->IsClassCommon() || item->ItemType != EQ::item::ItemTypeSpell) {
Message(Chat::Red, "Invalid item type, you cannot learn from this item.");
SummonItem(item_id);
return false;
}
if(!(
item->Name[0] == 'S' &&
item->Name[1] == 'p' &&
item->Name[2] == 'e' &&
item->Name[3] == 'l' &&
item->Name[4] == 'l' &&
item->Name[5] == ':' &&
item->Name[6] == ' '
)) {
Message(Chat::Red, "This item is not a scroll.");
SummonItem(item_id);
return false;
}
int player_class = GetClass();
uint32 cbit = 1 << (player_class - 1);
if(!(item->Classes & cbit)) {
Message(Chat::Red, "Your class cannot learn from this scroll.");
SummonItem(item_id);
return false;
}
uint32 spell_id = item->Scroll.Effect;
if(!IsValidSpell(spell_id)) {
Message(Chat::Red, "This scroll contains invalid knowledge.");
return false;
}
const SPDat_Spell_Struct &spell = spells[spell_id];
uint8 level_to_use = spell.classes[player_class - 1];
if(level_to_use == 255) {
Message(Chat::Red, "Your class cannot learn from this scroll.");
SummonItem(item_id);
return false;
}
if(level_to_use > GetLevel()) {
Message(Chat::Red, "You must be at least level %d to learn this spell.", level_to_use);
SummonItem(item_id);
return false;
}
for(int index = 0; index < EQ::spells::SPELLBOOK_SIZE; index++) {
if (!HasSpellScribed(spell_id)) {
auto next_slot = GetNextAvailableSpellBookSlot();
if (next_slot != -1) {
ScribeSpell(spell_id, next_slot);
return true;
} else {
Message(
Chat::Red,
"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
);
SummonItem(item_id);
return false;
}
} else {
Message(Chat::Red, "You already know this spell.");
SummonItem(item_id);
return false;
}
}
Message(Chat::Red, "You have learned too many spells and can learn no more.");
return false;
}
void Client::TrainDiscBySpellID(int32 spell_id) void Client::TrainDiscBySpellID(int32 spell_id)
{ {
int i; int i;