mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
[Quest API] Add Spell Blocked Event to Perl/Lua (#4217)
* [Spells] Add Unblockable Spell Table and Spell Blocked Event - Add `EVENT_SPELL_BLOCKED`, exports `$blocking_spell_id`, `$cast_spell_id`, `$blocking_spell`, and `$cast_spell`. - Add `event_spell_blocked`, exports `e.blocking_spell_id`, `e.cast_spell_id`, `e.blocking_spell`, and `e.cast_spell`. - Adds `spells_unblockable` table with a `spell_id` and `is_unblockable` column. - This table will need to be populated based on known spells that should be unblockable. - This event will allow operators to perform events when spells are blocked. * Cleanup * Cleanup * Update spells.cpp * Remove unused repositories. * Finalize * Update lua_parser_events.cpp
This commit is contained in:
parent
048aad437b
commit
d77966797e
@ -1854,9 +1854,9 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
|
||||
sp[tempid].min_range = Strings::ToFloat(row[231]);
|
||||
sp[tempid].no_remove = Strings::ToBool(row[232]);
|
||||
sp[tempid].damage_shield_type = 0;
|
||||
}
|
||||
}
|
||||
|
||||
LoadDamageShieldTypes(sp, max_spells);
|
||||
LoadDamageShieldTypes(sp, max_spells);
|
||||
}
|
||||
|
||||
void SharedDatabase::LoadCharacterInspectMessage(uint32 character_id, InspectMessage_Struct* message) {
|
||||
|
||||
@ -202,6 +202,7 @@ const char* QuestEventSubroutines[_LargestEventID] = {
|
||||
"EVENT_ENTITY_VARIABLE_SET",
|
||||
"EVENT_ENTITY_VARIABLE_UPDATE",
|
||||
"EVENT_AA_LOSS",
|
||||
"EVENT_SPELL_BLOCKED",
|
||||
|
||||
// Add new events before these or Lua crashes
|
||||
"EVENT_SPELL_EFFECT_BOT",
|
||||
@ -1937,6 +1938,25 @@ void PerlembParser::ExportEventVariables(
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_SPELL_BLOCKED: {
|
||||
Seperator sep(data);
|
||||
const uint32 blocking_spell_id = Strings::ToUnsignedInt(sep.arg[0]);
|
||||
const uint32 cast_spell_id = Strings::ToUnsignedInt(sep.arg[1]);
|
||||
|
||||
ExportVar(package_name.c_str(), "blocking_spell_id", blocking_spell_id);
|
||||
ExportVar(package_name.c_str(), "cast_spell_id", cast_spell_id);
|
||||
|
||||
if (IsValidSpell(blocking_spell_id)) {
|
||||
ExportVar(package_name.c_str(), "blocking_spell", "Spell", (void*) &spells[blocking_spell_id]);
|
||||
}
|
||||
|
||||
if (IsValidSpell(cast_spell_id)) {
|
||||
ExportVar(package_name.c_str(), "cast_spell", "Spell", (void*) &spells[cast_spell_id]);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//tradeskill events
|
||||
case EVENT_COMBINE_SUCCESS:
|
||||
case EVENT_COMBINE_FAILURE: {
|
||||
|
||||
@ -143,6 +143,7 @@ typedef enum {
|
||||
EVENT_ENTITY_VARIABLE_SET,
|
||||
EVENT_ENTITY_VARIABLE_UPDATE,
|
||||
EVENT_AA_LOSS,
|
||||
EVENT_SPELL_BLOCKED,
|
||||
|
||||
// Add new events before these or Lua crashes
|
||||
EVENT_SPELL_EFFECT_BOT,
|
||||
|
||||
@ -184,6 +184,7 @@ const char *LuaEvents[_LargestEventID] = {
|
||||
"event_entity_variable_set",
|
||||
"event_entity_variable_update",
|
||||
"event_aa_loss"
|
||||
"event_spell_blocked"
|
||||
};
|
||||
|
||||
extern Zone *zone;
|
||||
@ -257,6 +258,7 @@ LuaParser::LuaParser() {
|
||||
NPCArgumentDispatch[EVENT_ENTITY_VARIABLE_DELETE] = handle_npc_entity_variable;
|
||||
NPCArgumentDispatch[EVENT_ENTITY_VARIABLE_SET] = handle_npc_entity_variable;
|
||||
NPCArgumentDispatch[EVENT_ENTITY_VARIABLE_UPDATE] = handle_npc_entity_variable;
|
||||
NPCArgumentDispatch[EVENT_SPELL_BLOCKED] = handle_npc_spell_blocked;
|
||||
|
||||
PlayerArgumentDispatch[EVENT_SAY] = handle_player_say;
|
||||
PlayerArgumentDispatch[EVENT_ENVIRONMENTAL_DAMAGE] = handle_player_environmental_damage;
|
||||
@ -345,6 +347,7 @@ LuaParser::LuaParser() {
|
||||
PlayerArgumentDispatch[EVENT_ENTITY_VARIABLE_SET] = handle_player_entity_variable;
|
||||
PlayerArgumentDispatch[EVENT_ENTITY_VARIABLE_UPDATE] = handle_player_entity_variable;
|
||||
PlayerArgumentDispatch[EVENT_AA_LOSS] = handle_player_aa_loss;
|
||||
PlayerArgumentDispatch[EVENT_SPELL_BLOCKED] = handle_player_spell_blocked;
|
||||
|
||||
ItemArgumentDispatch[EVENT_ITEM_CLICK] = handle_item_click;
|
||||
ItemArgumentDispatch[EVENT_ITEM_CLICK_CAST] = handle_item_click;
|
||||
@ -399,6 +402,7 @@ LuaParser::LuaParser() {
|
||||
BotArgumentDispatch[EVENT_ENTITY_VARIABLE_DELETE] = handle_bot_entity_variable;
|
||||
BotArgumentDispatch[EVENT_ENTITY_VARIABLE_SET] = handle_bot_entity_variable;
|
||||
BotArgumentDispatch[EVENT_ENTITY_VARIABLE_UPDATE] = handle_bot_entity_variable;
|
||||
BotArgumentDispatch[EVENT_SPELL_BLOCKED] = handle_bot_spell_blocked;
|
||||
#endif
|
||||
|
||||
L = nullptr;
|
||||
|
||||
@ -626,6 +626,39 @@ void handle_npc_entity_variable(
|
||||
}
|
||||
}
|
||||
|
||||
void handle_npc_spell_blocked(
|
||||
QuestInterface *parse,
|
||||
lua_State* L,
|
||||
NPC* npc,
|
||||
Mob *init,
|
||||
std::string data,
|
||||
uint32 extra_data,
|
||||
std::vector<std::any> *extra_pointers
|
||||
)
|
||||
{
|
||||
Seperator sep(data.c_str());
|
||||
|
||||
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[0]));
|
||||
lua_setfield(L, -2, "blocking_spell_id");
|
||||
|
||||
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[1]));
|
||||
lua_setfield(L, -2, "cast_spell_id");
|
||||
|
||||
const uint32 blocking_spell_id = Strings::ToUnsignedInt(sep.arg[0]);
|
||||
|
||||
Lua_Spell l_spell_one(IsValidSpell(blocking_spell_id) ? &spells[blocking_spell_id] : nullptr);
|
||||
luabind::adl::object l_spell_one_o = luabind::adl::object(L, l_spell_one);
|
||||
l_spell_one_o.push(L);
|
||||
lua_setfield(L, -2, "blocking_spell");
|
||||
|
||||
const uint32 cast_spell_id = Strings::ToUnsignedInt(sep.arg[0]);
|
||||
|
||||
Lua_Spell l_spell_two(IsValidSpell(cast_spell_id) ? &spells[cast_spell_id] : nullptr);
|
||||
luabind::adl::object l_spell_two_o = luabind::adl::object(L, l_spell_two);
|
||||
l_spell_two_o.push(L);
|
||||
lua_setfield(L, -2, "cast_spell");
|
||||
}
|
||||
|
||||
// Player
|
||||
void handle_player_say(
|
||||
QuestInterface *parse,
|
||||
@ -1674,11 +1707,44 @@ void handle_player_aa_loss(
|
||||
std::string data,
|
||||
uint32 extra_data,
|
||||
std::vector<std::any> *extra_pointers
|
||||
) {
|
||||
)
|
||||
{
|
||||
lua_pushinteger(L, Strings::ToInt(data));
|
||||
lua_setfield(L, -2, "aa_lost");
|
||||
}
|
||||
|
||||
void handle_player_spell_blocked(
|
||||
QuestInterface *parse,
|
||||
lua_State* L,
|
||||
Client* client,
|
||||
std::string data,
|
||||
uint32 extra_data,
|
||||
std::vector<std::any> *extra_pointers
|
||||
)
|
||||
{
|
||||
Seperator sep(data.c_str());
|
||||
|
||||
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[0]));
|
||||
lua_setfield(L, -2, "blocking_spell_id");
|
||||
|
||||
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[1]));
|
||||
lua_setfield(L, -2, "cast_spell_id");
|
||||
|
||||
const uint32 blocking_spell_id = Strings::ToUnsignedInt(sep.arg[0]);
|
||||
|
||||
Lua_Spell l_spell_one(IsValidSpell(blocking_spell_id) ? &spells[blocking_spell_id] : nullptr);
|
||||
luabind::adl::object l_spell_one_o = luabind::adl::object(L, l_spell_one);
|
||||
l_spell_one_o.push(L);
|
||||
lua_setfield(L, -2, "blocking_spell");
|
||||
|
||||
const uint32 cast_spell_id = Strings::ToUnsignedInt(sep.arg[0]);
|
||||
|
||||
Lua_Spell l_spell_two(IsValidSpell(cast_spell_id) ? &spells[cast_spell_id] : nullptr);
|
||||
luabind::adl::object l_spell_two_o = luabind::adl::object(L, l_spell_two);
|
||||
l_spell_two_o.push(L);
|
||||
lua_setfield(L, -2, "cast_spell");
|
||||
}
|
||||
|
||||
// Item
|
||||
void handle_item_click(
|
||||
QuestInterface *parse,
|
||||
@ -2690,4 +2756,37 @@ void handle_bot_entity_variable(
|
||||
}
|
||||
}
|
||||
|
||||
void handle_bot_spell_blocked(
|
||||
QuestInterface *parse,
|
||||
lua_State* L,
|
||||
Bot* bot,
|
||||
Mob *init,
|
||||
std::string data,
|
||||
uint32 extra_data,
|
||||
std::vector<std::any> *extra_pointers
|
||||
)
|
||||
{
|
||||
Seperator sep(data.c_str());
|
||||
|
||||
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[0]));
|
||||
lua_setfield(L, -2, "blocking_spell_id");
|
||||
|
||||
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[1]));
|
||||
lua_setfield(L, -2, "cast_spell_id");
|
||||
|
||||
const uint32 blocking_spell_id = Strings::ToUnsignedInt(sep.arg[0]);
|
||||
|
||||
Lua_Spell l_spell_one(IsValidSpell(blocking_spell_id) ? &spells[blocking_spell_id] : nullptr);
|
||||
luabind::adl::object l_spell_one_o = luabind::adl::object(L, l_spell_one);
|
||||
l_spell_one_o.push(L);
|
||||
lua_setfield(L, -2, "blocking_spell");
|
||||
|
||||
const uint32 cast_spell_id = Strings::ToUnsignedInt(sep.arg[0]);
|
||||
|
||||
Lua_Spell l_spell_two(IsValidSpell(cast_spell_id) ? &spells[cast_spell_id] : nullptr);
|
||||
luabind::adl::object l_spell_two_o = luabind::adl::object(L, l_spell_two);
|
||||
l_spell_two_o.push(L);
|
||||
lua_setfield(L, -2, "cast_spell");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -250,6 +250,16 @@ void handle_npc_entity_variable(
|
||||
std::vector<std::any> *extra_pointers
|
||||
);
|
||||
|
||||
void handle_npc_spell_blocked(
|
||||
QuestInterface *parse,
|
||||
lua_State* L,
|
||||
NPC* npc,
|
||||
Mob *init,
|
||||
std::string data,
|
||||
uint32 extra_data,
|
||||
std::vector<std::any> *extra_pointers
|
||||
);
|
||||
|
||||
// Player
|
||||
void handle_player_say(
|
||||
QuestInterface *parse,
|
||||
@ -836,6 +846,15 @@ void handle_player_aa_loss(
|
||||
std::vector<std::any> *extra_pointers
|
||||
);
|
||||
|
||||
void handle_player_spell_blocked(
|
||||
QuestInterface *parse,
|
||||
lua_State* L,
|
||||
Client* client,
|
||||
std::string data,
|
||||
uint32 extra_data,
|
||||
std::vector<std::any> *extra_pointers
|
||||
);
|
||||
|
||||
// Item
|
||||
void handle_item_click(
|
||||
QuestInterface *parse,
|
||||
@ -1230,5 +1249,15 @@ void handle_bot_entity_variable(
|
||||
std::vector<std::any> *extra_pointers
|
||||
);
|
||||
|
||||
void handle_bot_spell_blocked(
|
||||
QuestInterface *parse,
|
||||
lua_State* L,
|
||||
Bot* bot,
|
||||
Mob* init,
|
||||
std::string data,
|
||||
uint32 extra_data,
|
||||
std::vector<std::any> *extra_pointers
|
||||
);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
119
zone/spells.cpp
119
zone/spells.cpp
@ -3066,7 +3066,17 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2,
|
||||
int blocked_effect, blocked_below_value, blocked_slot;
|
||||
int overwrite_effect, overwrite_below_value, overwrite_slot;
|
||||
|
||||
LogSpells("Check Stacking on old [{}] ([{}]) @ lvl [{}] (by [{}]) vs. new [{}] ([{}]) @ lvl [{}] (by [{}])", sp1.name, spellid1, caster_level1, (caster1==nullptr)?"Nobody":caster1->GetName(), sp2.name, spellid2, caster_level2, (caster2==nullptr)?"Nobody":caster2->GetName());
|
||||
LogSpells(
|
||||
"Check Stacking on old [{}] ([{}]) @ lvl [{}] (by [{}]) vs. new [{}] ([{}]) @ lvl [{}] (by [{}])",
|
||||
sp1.name,
|
||||
spellid1,
|
||||
caster_level1,
|
||||
!caster1 ? "Nobody" : caster1->GetName(),
|
||||
sp2.name,
|
||||
spellid2,
|
||||
caster_level2,
|
||||
!caster2 ? "Nobody" : caster2->GetName()
|
||||
);
|
||||
|
||||
if (IsResurrectionEffects(spellid1)) {
|
||||
return 0;
|
||||
@ -3534,28 +3544,103 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
|
||||
|
||||
if (IsValidSpell(curbuf.spellid)) {
|
||||
// there's a buff in this slot
|
||||
ret = CheckStackConflict(curbuf.spellid, curbuf.casterlevel, spell_id,
|
||||
caster_level, entity_list.GetMobID(curbuf.casterid), caster, buffslot);
|
||||
if (ret == -1) { // stop the spell
|
||||
LogSpells("Adding buff [{}] failed: stacking prevented by spell [{}] in slot [{}] with caster level [{}]",
|
||||
spell_id, curbuf.spellid, buffslot, curbuf.casterlevel);
|
||||
if (caster && caster->IsClient() && RuleB(Client, UseLiveBlockedMessage)) {
|
||||
if (caster->GetClass() != Class::Bard) {
|
||||
caster->Message(Chat::Red, "Your %s did not take hold on %s. (Blocked by %s.)", spells[spell_id].name, GetName(), spells[curbuf.spellid].name);
|
||||
ret = CheckStackConflict(
|
||||
curbuf.spellid,
|
||||
curbuf.casterlevel,
|
||||
spell_id,
|
||||
caster_level,
|
||||
entity_list.GetMobID(curbuf.casterid),
|
||||
caster,
|
||||
buffslot
|
||||
);
|
||||
|
||||
if (ret == -1) { // stop the spell
|
||||
LogSpells(
|
||||
"Adding buff [{}] failed: stacking prevented by spell [{}] in slot [{}] with caster level [{}]",
|
||||
spell_id,
|
||||
curbuf.spellid,
|
||||
buffslot,
|
||||
curbuf.casterlevel
|
||||
);
|
||||
|
||||
if (caster) {
|
||||
if (caster->IsClient() && RuleB(Client, UseLiveBlockedMessage) && caster->GetClass() != Class::Bard) {
|
||||
caster->Message(
|
||||
Chat::Red,
|
||||
fmt::format(
|
||||
"Your {} did not take hold on {}. (Blocked by {}.)",
|
||||
spells[spell_id].name,
|
||||
GetName(),
|
||||
spells[curbuf.spellid].name
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
|
||||
const bool caster_has_block_event = (
|
||||
(caster->IsBot() && parse->BotHasQuestSub(EVENT_SPELL_BLOCKED)) ||
|
||||
(caster->IsClient() && parse->PlayerHasQuestSub(EVENT_SPELL_BLOCKED)) ||
|
||||
(caster->IsNPC() && parse->HasQuestSub(caster->GetNPCTypeID(), EVENT_SPELL_BLOCKED))
|
||||
);
|
||||
|
||||
const bool cast_on_has_block_event = (
|
||||
(IsBot() && parse->BotHasQuestSub(EVENT_SPELL_BLOCKED)) ||
|
||||
(IsClient() && parse->PlayerHasQuestSub(EVENT_SPELL_BLOCKED)) ||
|
||||
(IsNPC() && parse->HasQuestSub(GetNPCTypeID(), EVENT_SPELL_BLOCKED))
|
||||
);
|
||||
|
||||
if (caster_has_block_event || cast_on_has_block_event) {
|
||||
const std::string& export_string = fmt::format(
|
||||
"{} {}",
|
||||
curbuf.spellid,
|
||||
spell_id
|
||||
);
|
||||
|
||||
if (caster_has_block_event) {
|
||||
if (caster->IsBot()) {
|
||||
parse->EventBot(EVENT_SPELL_BLOCKED, caster->CastToBot(), this, export_string, 0);
|
||||
} else if (caster->IsClient()) {
|
||||
parse->EventPlayer(EVENT_SPELL_BLOCKED, caster->CastToClient(), export_string, 0);
|
||||
} else if (caster->IsNPC()) {
|
||||
parse->EventNPC(EVENT_SPELL_BLOCKED, caster->CastToNPC(), this, export_string, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (cast_on_has_block_event && caster != this) {
|
||||
if (IsBot()) {
|
||||
parse->EventBot(EVENT_SPELL_BLOCKED, CastToBot(), caster, export_string, 0);
|
||||
} else if (IsClient()) {
|
||||
parse->EventPlayer(EVENT_SPELL_BLOCKED, CastToClient(), export_string, 0);
|
||||
} else if (IsNPC()) {
|
||||
parse->EventNPC(EVENT_SPELL_BLOCKED, CastToNPC(), caster, export_string, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
if (ret == 1) { // set a flag to indicate that there will be overwriting
|
||||
LogSpells("Adding buff [{}] will overwrite spell [{}] in slot [{}] with caster level [{}]",
|
||||
spell_id, curbuf.spellid, buffslot, curbuf.casterlevel);
|
||||
} else if (ret == 1 && !will_overwrite) {
|
||||
// set a flag to indicate that there will be overwriting
|
||||
LogSpells(
|
||||
"Adding buff [{}] will overwrite spell [{}] in slot [{}] with caster level [{}]",
|
||||
spell_id,
|
||||
curbuf.spellid,
|
||||
buffslot,
|
||||
curbuf.casterlevel
|
||||
);
|
||||
|
||||
// If this is the first buff it would override, use its slot
|
||||
will_overwrite = true;
|
||||
overwrite_slots.push_back(buffslot);
|
||||
}
|
||||
if (ret == 2) { //ResurrectionEffectBlock handling to move potential overwrites to a new buff slock while keeping Res Sickness
|
||||
LogSpells("Adding buff [{}] will overwrite spell [{}] in slot [{}] with caster level [{}], but ResurrectionEffectBlock is set to 2. Attempting to move [{}] to an empty buff slot.",
|
||||
spell_id, curbuf.spellid, buffslot, curbuf.casterlevel, spell_id);
|
||||
} else if (ret == 2) {
|
||||
//ResurrectionEffectBlock handling to move potential overwrites to a new buff slock while keeping Res Sickness
|
||||
LogSpells(
|
||||
"Adding buff [{}] will overwrite spell [{}] in slot [{}] with caster level [{}], but ResurrectionEffectBlock is set to 2. Attempting to move [{}] to an empty buff slot.",
|
||||
spell_id,
|
||||
curbuf.spellid,
|
||||
buffslot,
|
||||
curbuf.casterlevel,
|
||||
spell_id
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (emptyslot == -1) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user