[Quest API] Add EVENT_AA_BUY and EVENT_AA_GAIN to Perl/Lua. (#2504)

# Perl
- Add EVENT_AA_BUY to Perl.
  - Exports `$aa_cost`, `$aa_id`, `$aa_previous_id`, and `$aa_next_id`
- Add EVENT_AA_GAIN to Perl.
  - Exports `$aa_gained`
- Add quest::getaaname(aa_id) to Perl.

# Lua
- Add event_aa_buy to Lua.
  - Exports `e.aa_cost`, `e.aa_id`, `e.aa_previous_id`, and `e.aa_next_id`
- Add event_aa_gain to Lua.
  - Exports `e.aa_gained`
- Add eq.get_aa_name(aa_id) to Lua.
This commit is contained in:
Kinglykrab 2022-11-05 11:09:47 -04:00 committed by GitHub
parent a3928ec504
commit f6dbdf5db8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 263 additions and 27 deletions

View File

@ -29,6 +29,7 @@ Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
#include "groups.h"
#include "mob.h"
#include "queryserv.h"
#include "quest_parser_collection.h"
#include "raids.h"
#include "string_ids.h"
#include "titles.h"
@ -1147,65 +1148,95 @@ bool Client::GrantAlternateAdvancementAbility(int aa_id, int points, bool ignore
}
void Client::FinishAlternateAdvancementPurchase(AA::Rank *rank, bool ignore_cost) {
int rank_id = rank->base_ability->first_rank_id;
auto rank_id = rank->base_ability->first_rank_id;
if(rank->base_ability->charges > 0) {
if (rank->base_ability->charges) {
uint32 charges = 0;
GetAA(rank_id, &charges);
if(charges > 0) {
if (charges) {
return;
}
SetAA(rank_id, rank->current_value, rank->base_ability->charges);
}
else {
} else {
SetAA(rank_id, rank->current_value, 0);
//if not max then send next aa
if(rank->next) {
if (rank->next) {
SendAlternateAdvancementRank(rank->base_ability->id, rank->next->current_value);
}
}
int cost = !ignore_cost ? rank->cost : 0;
auto cost = !ignore_cost ? rank->cost : 0;
m_pp.aapoints -= cost ;
m_pp.aapoints -= static_cast<uint32>(cost);
SaveAA();
SendAlternateAdvancementPoints();
SendAlternateAdvancementStats();
if(rank->prev) {
MessageString(Chat::Yellow, AA_IMPROVE,
std::to_string(rank->title_sid).c_str(),
std::to_string(rank->prev->current_value).c_str(),
std::to_string(cost).c_str(),
cost == 1 ? std::to_string(AA_POINT).c_str() : std::to_string(AA_POINTS).c_str());
if (rank->prev) {
MessageString(
Chat::Yellow,
AA_IMPROVE,
std::to_string(rank->title_sid).c_str(),
std::to_string(rank->prev->current_value).c_str(),
std::to_string(cost).c_str(),
cost == 1 ? std::to_string(AA_POINT).c_str() : std::to_string(AA_POINTS).c_str()
);
/* QS: Player_Log_AA_Purchases */
if(RuleB(QueryServ, PlayerLogAAPurchases)) {
std::string event_desc = StringFormat("Ranked AA Purchase :: aa_id:%i at cost:%i in zoneid:%i instid:%i", rank->id, cost, GetZoneID(), GetInstanceID());
if (RuleB(QueryServ, PlayerLogAAPurchases)) {
const auto event_desc = fmt::format(
"Ranked AA Purchase :: aa_id:{} at cost:{} in zoneid:{} instid:{}",
rank->id,
cost,
GetZoneID(),
GetInstanceID()
);
QServ->PlayerLogEvent(Player_Log_AA_Purchases, CharacterID(), event_desc);
}
}
else {
MessageString(Chat::Yellow, AA_GAIN_ABILITY,
std::to_string(rank->title_sid).c_str(),
std::to_string(cost).c_str(),
cost == 1 ? std::to_string(AA_POINT).c_str() : std::to_string(AA_POINTS).c_str());
} else {
MessageString(
Chat::Yellow,
AA_GAIN_ABILITY,
std::to_string(rank->title_sid).c_str(),
std::to_string(cost).c_str(),
cost == 1 ? std::to_string(AA_POINT).c_str() : std::to_string(AA_POINTS).c_str()
);
/* QS: Player_Log_AA_Purchases */
if(RuleB(QueryServ, PlayerLogAAPurchases)) {
std::string event_desc = StringFormat("Initial AA Purchase :: aa_id:%i at cost:%i in zoneid:%i instid:%i", rank->id, cost, GetZoneID(), GetInstanceID());
if (RuleB(QueryServ, PlayerLogAAPurchases)) {
const auto event_desc = fmt::format(
"Initial AA Purchase :: aa_id:{} at cost:{} in zoneid:{} instid:{}",
rank->id,
cost,
GetZoneID(),
GetInstanceID()
);
QServ->PlayerLogEvent(Player_Log_AA_Purchases, CharacterID(), event_desc);
}
}
const auto export_string = fmt::format(
"{} {} {} {}",
cost,
rank->id,
rank->prev_id,
rank->next_id
);
parse->EventPlayer(EVENT_AA_BUY, this, export_string, 0);
CalcBonuses();
if(cost > 0) {
if(title_manager.IsNewAATitleAvailable(m_pp.aapoints_spent, GetBaseClass()))
if (cost) {
if (title_manager.IsNewAATitleAvailable(m_pp.aapoints_spent, GetBaseClass())) {
NotifyNewTitlesAvailable();
}
}
}

View File

@ -142,6 +142,7 @@ int command_init(void)
command_add("faction", "[Find (criteria | all ) | Review (criteria | all) | Reset (id)] - Resets Player's Faction", AccountStatus::QuestTroupe, command_faction) ||
command_add("factionassociation", "[factionid] [amount] - triggers a faction hits via association", AccountStatus::GMLeadAdmin, command_faction_association) ||
command_add("feature", "Change your or your target's feature's temporarily", AccountStatus::QuestTroupe, command_feature) ||
command_add("findaa", "[Search Criteria] - Search for an AA", AccountStatus::Guide, command_findaa) ||
command_add("findaliases", "[Search Criteria]- Searches for available command aliases, by alias or command", AccountStatus::Player, command_findaliases) ||
command_add("findclass", "[Search Criteria] - Search for a class", AccountStatus::Guide, command_findclass) ||
command_add("findfaction", "[Search Criteria] - Search for a faction", AccountStatus::Guide, command_findfaction) ||
@ -980,6 +981,7 @@ void command_bot(Client *c, const Seperator *sep)
#include "gm_commands/equipitem.cpp"
#include "gm_commands/faction.cpp"
#include "gm_commands/feature.cpp"
#include "gm_commands/findaa.cpp"
#include "gm_commands/findclass.cpp"
#include "gm_commands/findfaction.cpp"
#include "gm_commands/findnpctype.cpp"

View File

@ -82,6 +82,7 @@ void command_equipitem(Client *c, const Seperator *sep);
void command_faction(Client *c, const Seperator *sep);
void command_faction_association(Client *c, const Seperator *sep);
void command_feature(Client *c, const Seperator *sep);
void command_findaa(Client *c, const Seperator *sep);
void command_findaliases(Client *c, const Seperator *sep);
void command_findclass(Client *c, const Seperator *sep);
void command_findfaction(Client *c, const Seperator *sep);

View File

@ -161,6 +161,8 @@ const char *QuestEventSubroutines[_LargestEventID] = {
"EVENT_MERCHANT_SELL",
"EVENT_INSPECT",
"EVENT_TASK_BEFORE_UPDATE",
"EVENT_AA_BUY",
"EVENT_AA_GAIN"
};
PerlembParser::PerlembParser() : perl(nullptr)
@ -1737,6 +1739,20 @@ void PerlembParser::ExportEventVariables(
break;
}
case EVENT_AA_BUY: {
Seperator sep(data);
ExportVar(package_name.c_str(), "aa_cost", sep.arg[0]);
ExportVar(package_name.c_str(), "aa_id", sep.arg[1]);
ExportVar(package_name.c_str(), "aa_previous_id", sep.arg[2]);
ExportVar(package_name.c_str(), "aa_next_id", sep.arg[3]);
break;
}
case EVENT_AA_GAIN: {
ExportVar(package_name.c_str(), "aa_gained", data);
break;
}
case EVENT_INSPECT: {
ExportVar(package_name.c_str(), "target_id", extradata);
break;

View File

@ -3724,6 +3724,15 @@ bool Perl__IsSnowing()
return zone->IsSnowing();
}
std::string Perl__getaaname(int aa_id)
{
if (!zone) {
return std::string();
}
return zone->GetAAName(aa_id);
}
void perl_register_quest()
{
perl::interpreter perl(PERL_GET_THX);
@ -4083,6 +4092,7 @@ void perl_register_quest()
package.add("forcedooropen", (void(*)(uint32, bool))&Perl__forcedooropen);
package.add("getaaexpmodifierbycharid", (double(*)(uint32, uint32))&Perl__getaaexpmodifierbycharid);
package.add("getaaexpmodifierbycharid", (double(*)(uint32, uint32, int16))&Perl__getaaexpmodifierbycharid);
package.add("getaaname", (std::string(*)(int))&Perl__getaaname);
package.add("getbodytypename", &Perl__getbodytypename);
package.add("getcharidbyname", &Perl__getcharidbyname);
package.add("getclassname", (std::string(*)(uint8))&Perl__getclassname);

View File

@ -104,6 +104,8 @@ typedef enum {
EVENT_MERCHANT_SELL,
EVENT_INSPECT,
EVENT_TASK_BEFORE_UPDATE,
EVENT_AA_BUY,
EVENT_AA_GAIN,
_LargestEventID
} QuestEventID;

View File

@ -715,6 +715,13 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
SendSound();
}
const auto export_string = fmt::format(
"{}",
gained
);
parse->EventPlayer(EVENT_AA_GAIN, this, export_string, 0);
/* QS: PlayerLogAARate */
if (RuleB(QueryServ, PlayerLogAARate)){
int add_points = (m_pp.aapoints - last_unspentAA);

100
zone/gm_commands/findaa.cpp Executable file
View File

@ -0,0 +1,100 @@
#include "../client.h"
void command_findaa(Client *c, const Seperator *sep)
{
auto arguments = sep->argnum;
if (!arguments) {
c->Message(Chat::White, "Command Syntax: #findaa [Search Criteria]");
return;
}
if (sep->IsNumber(1)) {
int aa_id = std::stoi(sep->arg[1]);
auto aa_name = zone->GetAAName(aa_id);
if (!aa_name.empty()) {
c->Message(
Chat::White,
fmt::format(
"AA {}: {}",
aa_id,
aa_name
).c_str()
);
} else {
c->Message(
Chat::White,
fmt::format(
"AA ID {} was not found.",
aa_id
).c_str()
);
}
} else {
const auto search_criteria = Strings::ToLower(sep->argplus[1]);
if (!search_criteria.empty()) {
std::map<int, std::string> ordered_aas;
for (const auto& a : zone->aa_abilities) {
ordered_aas[a.second.get()->id] = a.second.get()->name;
}
int found_count = 0;
for (const auto& a : ordered_aas) {
auto aa_name = zone->GetAAName(a.first);
if (!aa_name.empty()) {
auto aa_name_lower = Strings::ToLower(aa_name);
if (aa_name_lower.find(search_criteria) == std::string::npos) {
continue;
}
c->Message(
Chat::White,
fmt::format(
"AA {}: {}",
a.first,
aa_name
).c_str()
);
found_count++;
if (found_count == 50) {
break;
}
}
}
if (!found_count) {
c->Message(
Chat::White,
fmt::format(
"No AAs were found matching '{}'.",
search_criteria
).c_str()
);
return;
}
if (found_count == 50) {
c->Message(
Chat::White,
fmt::format(
"50 AAs were found matching '{}', max reached.",
search_criteria
).c_str()
);
} else {
auto skill_message = found_count == 1 ? "An AA was" : fmt::format("{} AAs were", found_count);
c->Message(
Chat::White,
fmt::format(
"{} found matching '{}'.",
skill_message,
search_criteria
).c_str()
);
}
}
}
}

View File

@ -3444,6 +3444,14 @@ bool lua_is_snowing() {
return zone->IsSnowing();
}
std::string lua_get_aa_name(int aa_id) {
if (!zone) {
return std::string();
}
return zone->GetAAName(aa_id);
}
#define LuaCreateNPCParse(name, c_type, default_value) do { \
cur = table[#name]; \
if(luabind::type(cur) != LUA_TNIL) { \
@ -3910,6 +3918,7 @@ luabind::scope lua_register_general() {
luabind::def("has_recipe_learned", &lua_has_recipe_learned),
luabind::def("is_raining", &lua_is_raining),
luabind::def("is_snowing", &lua_is_snowing),
luabind::def("get_aa_name", &lua_get_aa_name),
/*
Cross Zone
@ -4308,7 +4317,9 @@ luabind::scope lua_register_events() {
luabind::value("merchant_buy", static_cast<int>(EVENT_MERCHANT_BUY)),
luabind::value("merchant_sell", static_cast<int>(EVENT_MERCHANT_SELL)),
luabind::value("inspect", static_cast<int>(EVENT_INSPECT)),
luabind::value("task_before_update", static_cast<int>(EVENT_TASK_BEFORE_UPDATE))
luabind::value("task_before_update", static_cast<int>(EVENT_TASK_BEFORE_UPDATE)),
luabind::value("aa_buy", static_cast<int>(EVENT_AA_BUY)),
luabind::value("aa_gain", static_cast<int>(EVENT_AA_GAIN))
];
}

View File

@ -148,6 +148,8 @@ const char *LuaEvents[_LargestEventID] = {
"event_merchant_sell",
"event_inspect",
"event_task_before_update",
"event_aa_buy",
"event_aa_gain"
};
extern Zone *zone;
@ -249,6 +251,8 @@ LuaParser::LuaParser() {
PlayerArgumentDispatch[EVENT_MERCHANT_BUY] = handle_player_merchant;
PlayerArgumentDispatch[EVENT_MERCHANT_SELL] = handle_player_merchant;
PlayerArgumentDispatch[EVENT_INSPECT] = handle_player_inspect;
PlayerArgumentDispatch[EVENT_AA_BUY] = handle_player_aa_buy;
PlayerArgumentDispatch[EVENT_AA_GAIN] = handle_player_aa_gain;
ItemArgumentDispatch[EVENT_ITEM_CLICK] = handle_item_click;
ItemArgumentDispatch[EVENT_ITEM_CLICK_CAST] = handle_item_click;

View File

@ -898,4 +898,24 @@ void handle_player_merchant(QuestInterface* parse, lua_State* L, Client* client,
lua_setfield(L, -2, "item_cost");
}
void handle_player_aa_buy(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, std::stoi(sep.arg[0]));
lua_setfield(L, -2, "aa_cost");
lua_pushinteger(L, std::stoi(sep.arg[1]));
lua_setfield(L, -2, "aa_id");
lua_pushinteger(L, std::stoi(sep.arg[2]));
lua_setfield(L, -2, "aa_previous_id");
lua_pushinteger(L, std::stoi(sep.arg[3]));
lua_setfield(L, -2, "aa_next_id");
}
void handle_player_aa_gain(QuestInterface* parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector<std::any>* extra_pointers) {
lua_pushinteger(L, std::stoi(data));
lua_setfield(L, -2, "aa_gained");
}
#endif

View File

@ -125,6 +125,10 @@ void handle_player_merchant(QuestInterface* parse, lua_State* L, Client* client,
std::vector<std::any>* extra_pointers);
void handle_player_inspect(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<std::any> *extra_pointers);
void handle_player_aa_buy(QuestInterface* parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<std::any>* extra_pointers);
void handle_player_aa_gain(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, lua_State* L, Client* client, EQ::ItemInstance* item, Mob *mob, std::string data, uint32 extra_data,

View File

@ -2950,3 +2950,29 @@ void Zone::LoadDynamicZoneTemplates()
dz_template_cache[dz_template.id] = dz_template;
}
}
std::string Zone::GetAAName(int aa_id)
{
if (!aa_id) {
return std::string();
}
int current_aa_id = 0;
const auto& r = aa_ranks.find(aa_id);
if (
r != aa_ranks.end() &&
r->second.get()->base_ability
) {
current_aa_id = r->second.get()->base_ability->id;
}
if (current_aa_id) {
const auto& a = aa_abilities.find(current_aa_id);
if (a != aa_abilities.end()) {
return a->second.get()->name;
}
}
return std::string();
}

View File

@ -249,6 +249,8 @@ public:
uint32 GetCurrencyID(uint32 item_id);
uint32 GetCurrencyItemID(uint32 currency_id);
std::string GetAAName(int aa_id);
inline bool IsRaining() { return zone_weather == EQ::constants::WeatherTypes::Raining; }
inline bool IsSnowing() { return zone_weather == EQ::constants::WeatherTypes::Snowing; }