[Commands] Add #unmemspell and #unmemspells Commands. (#1867)

- Add #unmemspell [Spell ID] command to unmemorize a spell by ID from you or your target.
- Add #unmemspells command to unmemorize all spells from you or your target.
- Cleanup #memspell command and change arguments from #memspell [Slot] [Spell ID] to #memspell [Spell ID] [Spell Gem] for easier use.
- Add #memspell [Spell ID] functionality to memorize to first open spell gem if there are any using FindEmptyMemSlot helper method.
- Rename client->FindMemmedSpellByID(spell_id) to FindMemmedSpellBySpellID(spell_id).
- Add client->FindEmptyMemSlot() helper method.
- Add $client->FindEmptyMemSlot() to Perl.
- Add client:FindEmptyMemSlot() to Lua.
- Add $client->FindMemmedSpellBySpellID(spell_id) to Perl.
- Add client:FindMemmedSpellBySpellID(spell_id) to Lua.
This commit is contained in:
Kinglykrab 2021-12-08 18:18:14 -05:00 committed by GitHub
parent 1a1c3abc24
commit 94166e0f95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 265 additions and 54 deletions

View File

@ -541,6 +541,8 @@ SET(gm_commands
gm_commands/undyeme.cpp
gm_commands/unfreeze.cpp
gm_commands/unlock.cpp
gm_commands/unmemspell.cpp
gm_commands/unmemspells.cpp
gm_commands/unscribespell.cpp
gm_commands/unscribespells.cpp
gm_commands/untraindisc.cpp

View File

@ -792,8 +792,9 @@ public:
void UnmemSpell(int slot, bool update_client = true);
void UnmemSpellBySpellID(int32 spell_id);
void UnmemSpellAll(bool update_client = true);
int FindEmptyMemSlot();
uint16 FindMemmedSpellBySlot(int slot);
int FindMemmedSpellByID(uint16 spell_id);
int FindMemmedSpellBySpellID(uint16 spell_id);
int MemmedCount();
std::vector<int> GetLearnableDisciplines(uint8 min_level = 1, uint8 max_level = 0);
std::vector<int> GetLearnedDisciplines();

View File

@ -241,7 +241,7 @@ int command_init(void)
command_add("makepet", "[level] [class] [race] [texture] - Make a pet", AccountStatus::Guide, command_makepet) ||
command_add("mana", "- Fill your or your target's mana", AccountStatus::Guide, command_mana) ||
command_add("maxskills", "Maxes skills for you.", AccountStatus::GMMgmt, command_max_all_skills) ||
command_add("memspell", "[Slot] [Spell ID] - Memorize a Spell by ID in the specified Slot", AccountStatus::Guide, command_memspell) ||
command_add("memspell", "[Spell ID] [Spell Gem] - Memorize a Spell by ID to the specified Spell Gem for you or your target", AccountStatus::Guide, command_memspell) ||
command_add("merchant_close_shop", "Closes a merchant shop", AccountStatus::GMAdmin, command_merchantcloseshop) ||
command_add("merchant_open_shop", "Opens a merchants shop", AccountStatus::GMAdmin, command_merchantopenshop) ||
command_add("modifynpcstat", "- Modifys a NPC's stats", AccountStatus::GMLeadAdmin, command_modifynpcstat) ||
@ -378,6 +378,8 @@ int command_init(void)
command_add("undyeme", "- Remove dye from all of your armor slots", AccountStatus::Player, command_undyeme) ||
command_add("unfreeze", "- Unfreeze your target", AccountStatus::QuestTroupe, command_unfreeze) ||
command_add("unlock", "- Unlock the worldserver", AccountStatus::GMLeadAdmin, command_unlock) ||
command_add("unmemspell", "[Spell ID] - Unmemorize a Spell by ID for you or your target", AccountStatus::Guide, command_unmemspell) ||
command_add("unmemspells", " - Unmemorize all spells for you or your target", AccountStatus::Guide, command_unmemspells) ||
command_add("unscribespell", "[spellid] - Unscribe specified spell from your target's spell book.", AccountStatus::GMCoder, command_unscribespell) ||
command_add("unscribespells", "- Clear out your or your player target's spell book.", AccountStatus::GMCoder, command_unscribespells) ||
command_add("untraindisc", "[spellid] - Untrain specified discipline from your target.", AccountStatus::GMCoder, command_untraindisc) ||

View File

@ -301,6 +301,8 @@ void command_undye(Client *c, const Seperator *sep);
void command_undyeme(Client *c, const Seperator *sep);
void command_unfreeze(Client *c, const Seperator *sep);
void command_unlock(Client *c, const Seperator *sep);
void command_unmemspell(Client *c, const Seperator *sep);
void command_unmemspells(Client *c, const Seperator *sep);
void command_unscribespell(Client *c, const Seperator *sep);
void command_unscribespells(Client *c, const Seperator *sep);
void command_untraindisc(Client *c, const Seperator *sep);

View File

@ -5,43 +5,75 @@ void command_memspell(Client *c, const Seperator *sep)
int arguments = sep->argnum;
if (
!arguments ||
!sep->IsNumber(1) ||
!sep->IsNumber(2)
!sep->IsNumber(1)
) {
c->Message(Chat::White, "Usage: #memspell [Slot] [Spell ID]");
c->Message(Chat::White, "Usage: #memspell [Spell ID] [Spell Gem]");
return;
}
Client* target = c;
auto target = c;
if (c->GetTarget() && c->GetTarget()->IsClient() && c->GetGM()) {
target = c->GetTarget()->CastToClient();
}
uint32 spell_gem = std::stoul(sep->arg[1]);
uint32 slot = (spell_gem - 1);
uint16 spell_id = static_cast<uint16>(std::stoul(sep->arg[2]));
if (
IsValidSpell(spell_id) &&
slot < EQ::spells::SPELL_GEM_COUNT
) {
target->MemSpell(spell_id, slot);
auto spell_id = static_cast<uint16>(std::stoul(sep->arg[1]));
if (!IsValidSpell(spell_id)) {
c->Message(
Chat::White,
fmt::format(
"{} ({}) has been memorized to Spell Gem {} ({}) for {}.",
GetSpellName(spell_id),
spell_id,
spell_gem,
slot,
"Spell ID {} could not be found.",
spell_id
).c_str()
);
return;
}
auto empty_slot = target->FindEmptyMemSlot();
if (empty_slot == -1) {
c->Message(
Chat::White,
fmt::format(
"{} not have a place to memorize {} ({}).",
(
c == target ?
"yourself" :
"You do" :
fmt::format(
"{} ({})",
"{} ({}) does",
target->GetCleanName(),
target->GetID()
)
)
),
GetSpellName(spell_id),
spell_id
).c_str()
);
return;
}
auto spell_gem = sep->IsNumber(2) ? std::stoul(sep->arg[2]) : empty_slot;
if (spell_gem > EQ::spells::SPELL_GEM_COUNT) {
c->Message(
Chat::White,
fmt::format(
"Spell Gems range from 0 to {}.",
EQ::spells::SPELL_GEM_COUNT
).c_str()
);
return;
}
target->MemSpell(spell_id, spell_gem);
if (c != target) {
c->Message(
Chat::White,
fmt::format(
"{} ({}) memorized to spell gem {} for {} ({}).",
GetSpellName(spell_id),
spell_id,
spell_gem,
target->GetCleanName(),
target->GetID()
).c_str()
);
}

View File

@ -0,0 +1,68 @@
#include "../client.h"
void command_unmemspell(Client *c, const Seperator *sep)
{
int arguments = sep->argnum;
if (
!arguments ||
!sep->IsNumber(1)
) {
c->Message(Chat::White, "Usage: #unmemspell [Spell ID]");
return;
}
auto target = c;
if (c->GetTarget() && c->GetTarget()->IsClient() && c->GetGM()) {
target = c->GetTarget()->CastToClient();
}
auto spell_id = static_cast<uint16>(std::stoul(sep->arg[1]));
if (!IsValidSpell(spell_id)) {
c->Message(
Chat::White,
fmt::format(
"Spell ID {} could not be found.",
spell_id
).c_str()
);
return;
}
auto spell_gem = target->FindMemmedSpellBySpellID(spell_id);
if (spell_gem == -1) {
c->Message(
Chat::White,
fmt::format(
"{} not have {} ({}) memorized.",
(
c == target ?
"You do" :
fmt::format(
"{} ({}) does",
target->GetCleanName(),
target->GetID()
)
),
GetSpellName(spell_id),
spell_id
).c_str()
);
return;
}
target->UnmemSpellBySpellID(spell_id);
if (c != target) {
c->Message(
Chat::White,
fmt::format(
"{} ({}) unmemorized for {} ({}) from spell gem {}.",
GetSpellName(spell_id),
spell_id,
target->GetCleanName(),
target->GetID(),
spell_gem
).c_str()
);
}
}

View File

@ -0,0 +1,43 @@
#include "../client.h"
void command_unmemspells(Client *c, const Seperator *sep)
{
auto target = c;
if (c->GetTarget() && c->GetTarget()->IsClient() && c->GetGM()) {
target = c->GetTarget()->CastToClient();
}
auto memmed_count = target->MemmedCount();
if (!memmed_count) {
c->Message(
Chat::White,
fmt::format(
"{} no spells to unmemorize.",
(
c == target ?
"You have" :
fmt::format(
"{} ({}) has",
target->GetCleanName(),
target->GetID()
)
)
).c_str()
);
return;
}
target->UnmemSpellAll();
if (c != target) {
c->Message(
Chat::White,
fmt::format(
"{} ({}) has had {} spells unmemorized.",
target->GetCleanName(),
target->GetID(),
memmed_count
).c_str()
);
}
}

View File

@ -650,6 +650,16 @@ uint16 Lua_Client::FindMemmedSpellBySlot(int slot) {
return self->FindMemmedSpellBySlot(slot);
}
int Lua_Client::FindMemmedSpellBySpellID(uint16 spell_id) {
Lua_Safe_Call_Int();
return self->FindMemmedSpellBySpellID(spell_id);
}
int Lua_Client::FindEmptyMemSlot() {
Lua_Safe_Call_Int();
return self->FindEmptyMemSlot();
}
int Lua_Client::MemmedCount() {
Lua_Safe_Call_Int();
return self->MemmedCount();
@ -2378,7 +2388,9 @@ luabind::scope lua_register_client() {
.def("Escape", (void(Lua_Client::*)(void))&Lua_Client::Escape)
.def("FailTask", (void(Lua_Client::*)(int))&Lua_Client::FailTask)
.def("FilteredMessage", &Lua_Client::FilteredMessage)
.def("FindEmptyMemSlot", (int(Lua_Client::*)(void))&Lua_Client::FindEmptyMemSlot)
.def("FindMemmedSpellBySlot", (uint16(Lua_Client::*)(int))&Lua_Client::FindMemmedSpellBySlot)
.def("FindMemmedSpellBySpellID", (int(Lua_Client::*)(uint16))&Lua_Client::FindMemmedSpellBySpellID)
.def("FindSpellBookSlotBySpellID", (int(Lua_Client::*)(int))&Lua_Client::FindSpellBookSlotBySpellID)
.def("Fling", (void(Lua_Client::*)(float,float,float,float))&Lua_Client::Fling)
.def("Fling", (void(Lua_Client::*)(float,float,float,float,bool))&Lua_Client::Fling)

View File

@ -163,7 +163,9 @@ public:
void UnmemSpellBySpellID(int32 spell_id);
void UnmemSpellAll();
void UnmemSpellAll(bool update_client);
int FindEmptyMemSlot();
uint16 FindMemmedSpellBySlot(int slot);
int FindMemmedSpellBySpellID(uint16 spell_id);
int MemmedCount();
luabind::object GetLearnableDisciplines(lua_State* L);
luabind::object GetLearnableDisciplines(lua_State* L, uint8 min_level);

View File

@ -1897,6 +1897,23 @@ XS(XS_Client_UnmemSpellAll) {
XSRETURN_EMPTY;
}
XS(XS_Client_FindEmptyMemSlot); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_FindEmptyMemSlot) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Client::FindEmptyMemSlot(THIS)"); // @categories Account and Character, Spells and Disciplines
{
Client *THIS;
int RETVAL;
dXSTARG;
VALIDATE_THIS_IS_CLIENT;
RETVAL = THIS->FindEmptyMemSlot();
XSprePUSH;
PUSHi((IV) RETVAL);
}
XSRETURN(1);
}
XS(XS_Client_FindMemmedSpellBySlot); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_FindMemmedSpellBySlot) {
dXSARGS;
@ -1915,6 +1932,24 @@ XS(XS_Client_FindMemmedSpellBySlot) {
XSRETURN(1);
}
XS(XS_Client_FindMemmedSpellBySpellID); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_FindMemmedSpellBySpellID) {
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: Client::FindMemmedSpellBySpellID(THIS, uint16 spell_id)"); // @categories Account and Character, Spells and Disciplines
{
Client *THIS;
int RETVAL;
dXSTARG;
uint16 spell_id = (uint16) SvUV(ST(1));
VALIDATE_THIS_IS_CLIENT;
RETVAL = THIS->FindMemmedSpellBySpellID(spell_id);
XSprePUSH;
PUSHi((IV) RETVAL);
}
XSRETURN(1);
}
XS(XS_Client_MemmedCount); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_MemmedCount) {
dXSARGS;
@ -5960,7 +5995,9 @@ XS(boot_Client) {
newXSproto(strcpy(buf, "Escape"), XS_Client_Escape, file, "$");
newXSproto(strcpy(buf, "ExpeditionMessage"), XS_Client_ExpeditionMessage, file, "$$$");
newXSproto(strcpy(buf, "FailTask"), XS_Client_FailTask, file, "$$");
newXSproto(strcpy(buf, "FindEmptyMemSlot"), XS_Client_FindEmptyMemSlot, file, "$");
newXSproto(strcpy(buf, "FindMemmedSpellBySlot"), XS_Client_FindMemmedSpellBySlot, file, "$$");
newXSproto(strcpy(buf, "FindMemmedSpellBySpellID"), XS_Client_FindMemmedSpellBySpellID, file, "$$");
newXSproto(strcpy(buf, "Fling"), XS_Client_Fling, file, "$$$$$;$$");
newXSproto(strcpy(buf, "ForageItem"), XS_Client_ForageItem, file, "$");
newXSproto(strcpy(buf, "Freeze"), XS_Client_Freeze, file, "$");

View File

@ -5246,7 +5246,7 @@ void Mob::SendSpellBarEnable(uint16 spell_id)
manachange->spell_id = spell_id;
manachange->stamina = CastToClient()->GetEndurance();
manachange->keepcasting = 0;
manachange->slot = CastToClient()->FindMemmedSpellByID(spell_id);
manachange->slot = CastToClient()->FindMemmedSpellBySpellID(spell_id);
outapp->priority = 6;
CastToClient()->QueuePacket(outapp);
safe_delete(outapp);
@ -5377,88 +5377,98 @@ void Client::MakeBuffFadePacket(uint16 spell_id, int slot_id, bool send_message)
void Client::MemSpell(uint16 spell_id, int slot, bool update_client)
{
if(slot >= EQ::spells::SPELL_GEM_COUNT || slot < 0)
if (slot >= EQ::spells::SPELL_GEM_COUNT || slot < 0) {
return;
}
if(update_client)
{
if(m_pp.mem_spells[slot] != 0xFFFFFFFF)
if(update_client) {
if (IsValidSpell(m_pp.mem_spells[slot])) {
UnmemSpell(slot, update_client);
}
}
m_pp.mem_spells[slot] = spell_id;
LogSpells("Spell [{}] memorized into slot [{}]", spell_id, slot);
database.SaveCharacterMemorizedSpell(this->CharacterID(), m_pp.mem_spells[slot], slot);
database.SaveCharacterMemorizedSpell(CharacterID(), m_pp.mem_spells[slot], slot);
if(update_client)
{
if(update_client) {
MemorizeSpell(slot, spell_id, memSpellMemorize);
}
}
void Client::UnmemSpell(int slot, bool update_client)
{
if(slot > EQ::spells::SPELL_GEM_COUNT || slot < 0)
if (slot >= EQ::spells::SPELL_GEM_COUNT || slot < 0) {
return;
}
LogSpells("Spell [{}] forgotten from slot [{}]", m_pp.mem_spells[slot], slot);
m_pp.mem_spells[slot] = 0xFFFFFFFF;
database.DeleteCharacterMemorizedSpell(this->CharacterID(), m_pp.mem_spells[slot], slot);
database.DeleteCharacterMemorizedSpell(CharacterID(), m_pp.mem_spells[slot], slot);
if(update_client)
{
if(update_client) {
MemorizeSpell(slot, m_pp.mem_spells[slot], memSpellForget);
}
}
void Client::UnmemSpellBySpellID(int32 spell_id)
{
for(int i = 0; i < EQ::spells::SPELL_GEM_COUNT; i++) {
if(m_pp.mem_spells[i] == spell_id) {
UnmemSpell(i, true);
break;
}
auto spell_gem = FindMemmedSpellBySpellID(spell_id);
if (spell_gem >= EQ::spells::SPELL_GEM_COUNT || spell_gem < 0) {
return;
}
UnmemSpell(spell_gem);
}
void Client::UnmemSpellAll(bool update_client)
{
int i;
for(i = 0; i < EQ::spells::SPELL_GEM_COUNT; i++)
if(m_pp.mem_spells[i] != 0xFFFFFFFF)
UnmemSpell(i, update_client);
for (int spell_gem = 0; spell_gem < EQ::spells::SPELL_GEM_COUNT; spell_gem++) {
if (IsValidSpell(m_pp.mem_spells[spell_gem])) {
UnmemSpell(spell_gem, update_client);
}
}
}
uint32 Client::GetSpellIDByBookSlot(int book_slot) {
if (book_slot <= EQ::spells::SPELLBOOK_SIZE) {
return GetSpellByBookSlot(book_slot);
}
return -1; //default
return -1;
}
int Client::FindEmptyMemSlot() {
for (int spell_gem = 0; spell_gem < EQ::spells::SPELL_GEM_COUNT; spell_gem++) {
if (!IsValidSpell(m_pp.mem_spells[spell_gem])) {
return spell_gem;
}
}
return -1;
}
uint16 Client::FindMemmedSpellBySlot(int slot) {
if (m_pp.mem_spells[slot] != 0xFFFFFFFF)
if (IsValidSpell(m_pp.mem_spells[slot])) {
return m_pp.mem_spells[slot];
}
return 0;
}
int Client::MemmedCount() {
int memmed_count = 0;
for (int i = 0; i < EQ::spells::SPELL_GEM_COUNT; i++)
if (m_pp.mem_spells[i] != 0xFFFFFFFF)
for (int spell_gem = 0; spell_gem < EQ::spells::SPELL_GEM_COUNT; spell_gem++) {
if (IsValidSpell(m_pp.mem_spells[spell_gem])) {
memmed_count++;
}
}
return memmed_count;
}
int Client::FindMemmedSpellByID(uint16 spell_id) {
for (int i = 0; i < EQ::spells::SPELL_GEM_COUNT; i++) {
if (m_pp.mem_spells[i] == spell_id) {
return i;
int Client::FindMemmedSpellBySpellID(uint16 spell_id) {
for (int spell_gem = 0; spell_gem < EQ::spells::SPELL_GEM_COUNT; spell_gem++) {
if (IsValidSpell(m_pp.mem_spells[spell_gem]) && m_pp.mem_spells[spell_gem] == spell_id) {
return spell_gem;
}
}
return -1;