mirror of
https://github.com/EQEmu/Server.git
synced 2026-06-10 02:31:03 +00:00
[Items] Overhaul Item Hand-in System (#4593)
* [Items] Overhaul Item Hand-in System * Edge case lua fix * Merge fix * I'm going to be amazed if this works first try * Update linux-build.sh * Update linux-build.sh * Update linux-build.sh * Update linux-build.sh * Update linux-build.sh * Update linux-build.sh * Update linux-build.sh * Update linux-build.sh * Add protections against scripts that hand back items themselves * Remove EVENT_ITEM_ScriptStopReturn * test * Update npc_handins.cpp * Add Items:AlwaysReturnHandins * Update spdat.cpp * Bypass update prompt on CI
This commit is contained in:
+327
-258
@@ -89,6 +89,314 @@ extern PetitionList petition_list;
|
||||
|
||||
void UpdateWindowTitle(char* iNewTitle);
|
||||
|
||||
// client constructor purely for testing / mocking
|
||||
Client::Client() : Mob(
|
||||
"No name", // in_name
|
||||
"", // in_lastname
|
||||
0, // in_cur_hp
|
||||
0, // in_max_hp
|
||||
Gender::Male, // in_gender
|
||||
Race::Doug, // in_race
|
||||
Class::None, // in_class
|
||||
BodyType::Humanoid, // in_bodytype
|
||||
Deity::Unknown, // in_deity
|
||||
0, // in_level
|
||||
0, // in_npctype_id
|
||||
0.0f, // in_size
|
||||
0.7f, // in_runspeed
|
||||
glm::vec4(), // position
|
||||
0, // in_light
|
||||
0xFF, // in_texture
|
||||
0xFF, // in_helmtexture
|
||||
0, // in_ac
|
||||
0, // in_atk
|
||||
0, // in_str
|
||||
0, // in_sta
|
||||
0, // in_dex
|
||||
0, // in_agi
|
||||
0, // in_int
|
||||
0, // in_wis
|
||||
0, // in_cha
|
||||
0, // in_haircolor
|
||||
0, // in_beardcolor
|
||||
0, // in_eyecolor1
|
||||
0, // in_eyecolor2
|
||||
0, // in_hairstyle
|
||||
0, // in_luclinface
|
||||
0, // in_beard
|
||||
0, // in_drakkin_heritage
|
||||
0, // in_drakkin_tattoo
|
||||
0, // in_drakkin_details
|
||||
EQ::TintProfile(), // in_armor_tint
|
||||
0xff, // in_aa_title
|
||||
0, // in_see_invis
|
||||
0, // in_see_invis_undead
|
||||
0, // in_see_hide
|
||||
0, // in_see_improved_hide
|
||||
0, // in_hp_regen
|
||||
0, // in_mana_regen
|
||||
0, // in_qglobal
|
||||
0, // in_maxlevel
|
||||
0, // in_scalerate
|
||||
0, // in_armtexture
|
||||
0, // in_bracertexture
|
||||
0, // in_handtexture
|
||||
0, // in_legtexture
|
||||
0, // in_feettexture
|
||||
0, // in_usemodel
|
||||
false, // in_always_aggros_foes
|
||||
0, // in_heroic_strikethrough
|
||||
false // in_keeps_sold_items
|
||||
),
|
||||
hpupdate_timer(2000),
|
||||
camp_timer(29000),
|
||||
process_timer(100),
|
||||
consume_food_timer(CONSUMPTION_TIMER),
|
||||
zoneinpacket_timer(1000),
|
||||
linkdead_timer(RuleI(Zone, ClientLinkdeadMS)),
|
||||
dead_timer(2000),
|
||||
global_channel_timer(1000),
|
||||
fishing_timer(8000),
|
||||
endupkeep_timer(1000),
|
||||
autosave_timer(RuleI(Character, AutosaveIntervalS) * 1000),
|
||||
m_client_npc_aggro_scan_timer(RuleI(Aggro, ClientAggroCheckIdleInterval)),
|
||||
m_client_bulk_npc_pos_update_timer(60 * 1000),
|
||||
tribute_timer(Tribute_duration),
|
||||
proximity_timer(ClientProximity_interval),
|
||||
TaskPeriodic_Timer(RuleI(TaskSystem, PeriodicCheckTimer) * 1000),
|
||||
charm_update_timer(6000),
|
||||
rest_timer(1),
|
||||
pick_lock_timer(1000),
|
||||
charm_class_attacks_timer(3000),
|
||||
charm_cast_timer(3500),
|
||||
qglobal_purge_timer(30000),
|
||||
TrackingTimer(2000),
|
||||
RespawnFromHoverTimer(0),
|
||||
merc_timer(RuleI(Mercs, UpkeepIntervalMS)),
|
||||
ItemQuestTimer(500),
|
||||
anon_toggle_timer(250),
|
||||
afk_toggle_timer(250),
|
||||
helm_toggle_timer(250),
|
||||
aggro_meter_timer(AGGRO_METER_UPDATE_MS),
|
||||
m_Proximity(FLT_MAX, FLT_MAX, FLT_MAX), //arbitrary large number
|
||||
m_ZoneSummonLocation(-2.0f, -2.0f, -2.0f, -2.0f),
|
||||
m_AutoAttackPosition(0.0f, 0.0f, 0.0f, 0.0f),
|
||||
m_AutoAttackTargetLocation(0.0f, 0.0f, 0.0f),
|
||||
last_region_type(RegionTypeUnsupported),
|
||||
m_dirtyautohaters(false),
|
||||
m_position_update_timer(10000),
|
||||
consent_throttle_timer(2000),
|
||||
tmSitting(0),
|
||||
parcel_timer(RuleI(Parcel, ParcelDeliveryDelay)),
|
||||
lazy_load_bank_check_timer(1000),
|
||||
bandolier_throttle_timer(0)
|
||||
{
|
||||
eqs = nullptr;
|
||||
for (auto client_filter = FilterNone; client_filter < _FilterCount; client_filter = eqFilterType(client_filter + 1)) {
|
||||
SetFilter(client_filter, FilterShow);
|
||||
}
|
||||
|
||||
cheat_manager.SetClient(this);
|
||||
mMovementManager->AddClient(this);
|
||||
character_id = 0;
|
||||
conn_state = NoPacketsReceived;
|
||||
client_data_loaded = false;
|
||||
berserk = false;
|
||||
dead = false;
|
||||
client_state = CLIENT_CONNECTING;
|
||||
SetTrader(false);
|
||||
Haste = 0;
|
||||
SetCustomerID(0);
|
||||
SetTraderID(0);
|
||||
TrackingID = 0;
|
||||
WID = 0;
|
||||
account_id = 0;
|
||||
admin = AccountStatus::Player;
|
||||
lsaccountid = 0;
|
||||
guild_id = GUILD_NONE;
|
||||
guildrank = 0;
|
||||
guild_tribute_opt_in = 0;
|
||||
SetGuildListDirty(false);
|
||||
GuildBanker = false;
|
||||
memset(lskey, 0, sizeof(lskey));
|
||||
strcpy(account_name, "");
|
||||
tellsoff = false;
|
||||
last_reported_mana = 0;
|
||||
last_reported_endurance = 0;
|
||||
last_reported_endurance_percent = 0;
|
||||
last_reported_mana_percent = 0;
|
||||
gm_hide_me = false;
|
||||
AFK = false;
|
||||
LFG = false;
|
||||
LFGFromLevel = 0;
|
||||
LFGToLevel = 0;
|
||||
LFGMatchFilter = false;
|
||||
LFGComments[0] = '\0';
|
||||
LFP = false;
|
||||
gmspeed = 0;
|
||||
gminvul = false;
|
||||
playeraction = 0;
|
||||
SetTarget(0);
|
||||
auto_attack = false;
|
||||
auto_fire = false;
|
||||
runmode = false;
|
||||
linkdead_timer.Disable();
|
||||
zonesummon_id = 0;
|
||||
zonesummon_ignorerestrictions = 0;
|
||||
bZoning = false;
|
||||
m_lock_save_position = false;
|
||||
zone_mode = ZoneUnsolicited;
|
||||
casting_spell_id = 0;
|
||||
npcflag = false;
|
||||
npclevel = 0;
|
||||
fishing_timer.Disable();
|
||||
dead_timer.Disable();
|
||||
camp_timer.Disable();
|
||||
autosave_timer.Disable();
|
||||
GetMercTimer()->Disable();
|
||||
instalog = false;
|
||||
m_pp.autosplit = false;
|
||||
// initialise haste variable
|
||||
m_tradeskill_object = nullptr;
|
||||
delaytimer = false;
|
||||
PendingRezzXP = -1;
|
||||
PendingRezzDBID = 0;
|
||||
PendingRezzSpellID = 0;
|
||||
numclients++;
|
||||
// emuerror;
|
||||
UpdateWindowTitle(nullptr);
|
||||
horseId = 0;
|
||||
tgb = false;
|
||||
tribute_master_id = 0xFFFFFFFF;
|
||||
tribute_timer.Disable();
|
||||
task_state = nullptr;
|
||||
TotalSecondsPlayed = 0;
|
||||
keyring.clear();
|
||||
bind_sight_target = nullptr;
|
||||
p_raid_instance = nullptr;
|
||||
mercid = 0;
|
||||
mercSlot = 0;
|
||||
InitializeMercInfo();
|
||||
SetMerc(0);
|
||||
if (RuleI(World, PVPMinLevel) > 0 && level >= RuleI(World, PVPMinLevel) && m_pp.pvp == 0) SetPVP(true, false);
|
||||
dynamiczone_removal_timer.Disable();
|
||||
|
||||
//for good measure:
|
||||
memset(&m_pp, 0, sizeof(m_pp));
|
||||
memset(&m_epp, 0, sizeof(m_epp));
|
||||
PendingTranslocate = false;
|
||||
PendingSacrifice = false;
|
||||
sacrifice_caster_id = 0;
|
||||
controlling_boat_id = 0;
|
||||
controlled_mob_id = 0;
|
||||
qGlobals = nullptr;
|
||||
|
||||
if (!RuleB(Character, PerCharacterQglobalMaxLevel) && !RuleB(Character, PerCharacterBucketMaxLevel)) {
|
||||
SetClientMaxLevel(0);
|
||||
} else if (RuleB(Character, PerCharacterQglobalMaxLevel)) {
|
||||
SetClientMaxLevel(GetCharMaxLevelFromQGlobal());
|
||||
} else if (RuleB(Character, PerCharacterBucketMaxLevel)) {
|
||||
SetClientMaxLevel(GetCharMaxLevelFromBucket());
|
||||
}
|
||||
|
||||
KarmaUpdateTimer = new Timer(RuleI(Chat, KarmaUpdateIntervalMS));
|
||||
GlobalChatLimiterTimer = new Timer(RuleI(Chat, IntervalDurationMS));
|
||||
AttemptedMessages = 0;
|
||||
TotalKarma = 0;
|
||||
m_ClientVersion = EQ::versions::ClientVersion::Unknown;
|
||||
m_ClientVersionBit = 0;
|
||||
AggroCount = 0;
|
||||
ooc_regen = false;
|
||||
AreaHPRegen = 1.0f;
|
||||
AreaManaRegen = 1.0f;
|
||||
AreaEndRegen = 1.0f;
|
||||
XPRate = 100;
|
||||
current_endurance = 0;
|
||||
|
||||
CanUseReport = true;
|
||||
aa_los_them_mob = nullptr;
|
||||
los_status = false;
|
||||
los_status_facing = false;
|
||||
HideCorpseMode = HideCorpseNone;
|
||||
PendingGuildInvitation = false;
|
||||
|
||||
InitializeBuffSlots();
|
||||
|
||||
adventure_request_timer = nullptr;
|
||||
adventure_create_timer = nullptr;
|
||||
adventure_leave_timer = nullptr;
|
||||
adventure_door_timer = nullptr;
|
||||
adv_requested_data = nullptr;
|
||||
adventure_stats_timer = nullptr;
|
||||
adventure_leaderboard_timer = nullptr;
|
||||
adv_data = nullptr;
|
||||
adv_requested_theme = LDoNTheme::Unused;
|
||||
adv_requested_id = 0;
|
||||
adv_requested_member_count = 0;
|
||||
|
||||
for(int i = 0; i < XTARGET_HARDCAP; ++i)
|
||||
{
|
||||
XTargets[i].Type = Auto;
|
||||
XTargets[i].ID = 0;
|
||||
XTargets[i].Name[0] = 0;
|
||||
XTargets[i].dirty = false;
|
||||
}
|
||||
MaxXTargets = 5;
|
||||
XTargetAutoAddHaters = true;
|
||||
m_autohatermgr.SetOwner(this, nullptr, nullptr);
|
||||
m_activeautohatermgr = &m_autohatermgr;
|
||||
|
||||
initial_respawn_selection = 0;
|
||||
alternate_currency_loaded = false;
|
||||
|
||||
interrogateinv_flag = false;
|
||||
|
||||
trapid = 0;
|
||||
|
||||
for (int i = 0; i < InnateSkillMax; ++i)
|
||||
m_pp.InnateSkills[i] = InnateDisabled;
|
||||
|
||||
temp_pvp = false;
|
||||
|
||||
moving = false;
|
||||
|
||||
environment_damage_modifier = 0;
|
||||
invulnerable_environment_damage = false;
|
||||
|
||||
// rate limiter
|
||||
m_list_task_timers_rate_limit.Start(1000);
|
||||
|
||||
// gm
|
||||
SetDisplayMobInfoWindow(true);
|
||||
SetDevToolsEnabled(true);
|
||||
|
||||
bot_owner_options[booDeathMarquee] = false;
|
||||
bot_owner_options[booStatsUpdate] = false;
|
||||
bot_owner_options[booSpawnMessageSay] = false;
|
||||
bot_owner_options[booSpawnMessageTell] = true;
|
||||
bot_owner_options[booSpawnMessageClassSpecific] = true;
|
||||
bot_owner_options[booAutoDefend] = RuleB(Bots, AllowOwnerOptionAutoDefend);
|
||||
bot_owner_options[booBuffCounter] = false;
|
||||
bot_owner_options[booMonkWuMessage] = false;
|
||||
|
||||
m_parcel_platinum = 0;
|
||||
m_parcel_gold = 0;
|
||||
m_parcel_silver = 0;
|
||||
m_parcel_copper = 0;
|
||||
m_parcel_count = 0;
|
||||
m_parcel_enabled = true;
|
||||
m_parcel_merchant_engaged = false;
|
||||
m_parcels.clear();
|
||||
|
||||
m_buyer_id = 0;
|
||||
|
||||
SetBotPulling(false);
|
||||
SetBotPrecombat(false);
|
||||
|
||||
AI_Init();
|
||||
|
||||
}
|
||||
|
||||
Client::Client(EQStreamInterface *ieqs) : Mob(
|
||||
"No name", // in_name
|
||||
"", // in_lastname
|
||||
@@ -504,9 +812,11 @@ Client::~Client() {
|
||||
zone->RemoveAuth(GetName(), lskey);
|
||||
|
||||
//let the stream factory know were done with this stream
|
||||
eqs->Close();
|
||||
eqs->ReleaseFromUse();
|
||||
safe_delete(eqs);
|
||||
if (eqs) {
|
||||
eqs->Close();
|
||||
eqs->ReleaseFromUse();
|
||||
safe_delete(eqs);
|
||||
}
|
||||
|
||||
UninitializeBuffSlots();
|
||||
}
|
||||
@@ -2488,6 +2798,7 @@ void Client::AddMoneyToPP(uint64 copper, bool update_client){
|
||||
|
||||
/* Add Amount of Platinum */
|
||||
temporary_copper_two = temporary_copper / 1000;
|
||||
m_external_handin_money_returned.platinum = temporary_copper_two;
|
||||
int32 new_value = m_pp.platinum + temporary_copper_two;
|
||||
|
||||
if (new_value < 0) {
|
||||
@@ -2501,6 +2812,7 @@ void Client::AddMoneyToPP(uint64 copper, bool update_client){
|
||||
/* Add Amount of Gold */
|
||||
temporary_copper_two = temporary_copper / 100;
|
||||
new_value = m_pp.gold + temporary_copper_two;
|
||||
m_external_handin_money_returned.gold = temporary_copper_two;
|
||||
|
||||
if (new_value < 0) {
|
||||
m_pp.gold = 0;
|
||||
@@ -2513,6 +2825,7 @@ void Client::AddMoneyToPP(uint64 copper, bool update_client){
|
||||
/* Add Amount of Silver */
|
||||
temporary_copper_two = temporary_copper / 10;
|
||||
new_value = m_pp.silver + temporary_copper_two;
|
||||
m_external_handin_money_returned.silver = temporary_copper_two;
|
||||
|
||||
if (new_value < 0) {
|
||||
m_pp.silver = 0;
|
||||
@@ -2525,6 +2838,7 @@ void Client::AddMoneyToPP(uint64 copper, bool update_client){
|
||||
/* Add Amount of Copper */
|
||||
temporary_copper_two = temporary_copper;
|
||||
new_value = m_pp.copper + temporary_copper_two;
|
||||
m_external_handin_money_returned.copper = temporary_copper_two;
|
||||
|
||||
if (new_value < 0) {
|
||||
m_pp.copper = 0;
|
||||
@@ -2541,23 +2855,12 @@ void Client::AddMoneyToPP(uint64 copper, bool update_client){
|
||||
|
||||
SaveCurrency();
|
||||
|
||||
m_external_handin_money_returned.return_source = "AddMoneyToPP";
|
||||
|
||||
LogDebug("Client::AddMoneyToPP() [{}] should have: plat:[{}] gold:[{}] silver:[{}] copper:[{}]", GetName(), m_pp.platinum, m_pp.gold, m_pp.silver, m_pp.copper);
|
||||
}
|
||||
|
||||
void Client::EVENT_ITEM_ScriptStopReturn(){
|
||||
/* Set a timestamp in an entity variable for plugin check_handin.pl in return_items
|
||||
This will stopgap players from items being returned if global_npc.pl has a catch all return_items
|
||||
*/
|
||||
struct timeval read_time;
|
||||
char buffer[50];
|
||||
gettimeofday(&read_time, 0);
|
||||
sprintf(buffer, "%li.%li \n", read_time.tv_sec, read_time.tv_usec);
|
||||
SetEntityVariable("Stop_Return", buffer);
|
||||
}
|
||||
|
||||
void Client::AddMoneyToPP(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, bool update_client){
|
||||
EVENT_ITEM_ScriptStopReturn();
|
||||
|
||||
int32 new_value = m_pp.platinum + platinum;
|
||||
if (new_value >= 0 && new_value > m_pp.platinum) {
|
||||
m_pp.platinum += platinum;
|
||||
@@ -2585,6 +2888,14 @@ void Client::AddMoneyToPP(uint32 copper, uint32 silver, uint32 gold, uint32 plat
|
||||
RecalcWeight();
|
||||
SaveCurrency();
|
||||
|
||||
m_external_handin_money_returned = ExternalHandinMoneyReturned{
|
||||
.copper = copper,
|
||||
.silver = silver,
|
||||
.gold = gold,
|
||||
.platinum = platinum,
|
||||
.return_source = "AddMoneyToPP"
|
||||
};
|
||||
|
||||
#if (EQDEBUG>=5)
|
||||
LogDebug("Client::AddMoneyToPP() [{}] should have: plat:[{}] gold:[{}] silver:[{}] copper:[{}]",
|
||||
GetName(), m_pp.platinum, m_pp.gold, m_pp.silver, m_pp.copper);
|
||||
@@ -12373,248 +12684,6 @@ void Client::PlayerTradeEventLog(Trade *t, Trade *t2)
|
||||
RecordPlayerEventLogWithClient(trader2, PlayerEvent::TRADE, e);
|
||||
}
|
||||
|
||||
void Client::NPCHandinEventLog(Trade* t, NPC* n)
|
||||
{
|
||||
Client* c = t->GetOwner()->CastToClient();
|
||||
|
||||
std::vector<PlayerEvent::HandinEntry> hi = {};
|
||||
std::vector<PlayerEvent::HandinEntry> ri = {};
|
||||
PlayerEvent::HandinMoney hm{};
|
||||
PlayerEvent::HandinMoney rm{};
|
||||
|
||||
if (
|
||||
c->EntityVariableExists("HANDIN_ITEMS") &&
|
||||
c->EntityVariableExists("HANDIN_MONEY") &&
|
||||
c->EntityVariableExists("RETURN_ITEMS") &&
|
||||
c->EntityVariableExists("RETURN_MONEY")
|
||||
) {
|
||||
const std::string& handin_items = c->GetEntityVariable("HANDIN_ITEMS");
|
||||
const std::string& return_items = c->GetEntityVariable("RETURN_ITEMS");
|
||||
const std::string& handin_money = c->GetEntityVariable("HANDIN_MONEY");
|
||||
const std::string& return_money = c->GetEntityVariable("RETURN_MONEY");
|
||||
|
||||
// Handin Items
|
||||
if (!handin_items.empty()) {
|
||||
if (Strings::Contains(handin_items, ",")) {
|
||||
const auto handin_data = Strings::Split(handin_items, ",");
|
||||
for (const auto& h : handin_data) {
|
||||
const auto item_data = Strings::Split(h, "|");
|
||||
if (
|
||||
item_data.size() == 3 &&
|
||||
Strings::IsNumber(item_data[0]) &&
|
||||
Strings::IsNumber(item_data[1]) &&
|
||||
Strings::IsNumber(item_data[2])
|
||||
) {
|
||||
const uint32 item_id = Strings::ToUnsignedInt(item_data[0]);
|
||||
if (item_id != 0) {
|
||||
const auto* item = database.GetItem(item_id);
|
||||
|
||||
if (item) {
|
||||
hi.emplace_back(
|
||||
PlayerEvent::HandinEntry{
|
||||
.item_id = item_id,
|
||||
.item_name = item->Name,
|
||||
.charges = static_cast<uint16>(Strings::ToUnsignedInt(item_data[1])),
|
||||
.attuned = Strings::ToInt(item_data[2]) ? true : false
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (Strings::Contains(handin_items, "|")) {
|
||||
const auto item_data = Strings::Split(handin_items, "|");
|
||||
if (
|
||||
item_data.size() == 3 &&
|
||||
Strings::IsNumber(item_data[0]) &&
|
||||
Strings::IsNumber(item_data[1]) &&
|
||||
Strings::IsNumber(item_data[2])
|
||||
) {
|
||||
const uint32 item_id = Strings::ToUnsignedInt(item_data[0]);
|
||||
const auto* item = database.GetItem(item_id);
|
||||
|
||||
if (item) {
|
||||
hi.emplace_back(
|
||||
PlayerEvent::HandinEntry{
|
||||
.item_id = item_id,
|
||||
.item_name = item->Name,
|
||||
.charges = static_cast<uint16>(Strings::ToUnsignedInt(item_data[1])),
|
||||
.attuned = Strings::ToInt(item_data[2]) ? true : false
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handin Money
|
||||
if (!handin_money.empty()) {
|
||||
const auto hms = Strings::Split(handin_money, "|");
|
||||
|
||||
hm.copper = Strings::ToUnsignedInt(hms[0]);
|
||||
hm.silver = Strings::ToUnsignedInt(hms[1]);
|
||||
hm.gold = Strings::ToUnsignedInt(hms[2]);
|
||||
hm.platinum = Strings::ToUnsignedInt(hms[3]);
|
||||
}
|
||||
|
||||
// Return Items
|
||||
if (!return_items.empty()) {
|
||||
if (Strings::Contains(return_items, ",")) {
|
||||
const auto return_data = Strings::Split(return_items, ",");
|
||||
for (const auto& r : return_data) {
|
||||
const auto item_data = Strings::Split(r, "|");
|
||||
if (
|
||||
item_data.size() == 3 &&
|
||||
Strings::IsNumber(item_data[0]) &&
|
||||
Strings::IsNumber(item_data[1]) &&
|
||||
Strings::IsNumber(item_data[2])
|
||||
) {
|
||||
const uint32 item_id = Strings::ToUnsignedInt(item_data[0]);
|
||||
const auto* item = database.GetItem(item_id);
|
||||
|
||||
if (item) {
|
||||
ri.emplace_back(
|
||||
PlayerEvent::HandinEntry{
|
||||
.item_id = item_id,
|
||||
.item_name = item->Name,
|
||||
.charges = static_cast<uint16>(Strings::ToUnsignedInt(item_data[1])),
|
||||
.attuned = Strings::ToInt(item_data[2]) ? true : false
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (Strings::Contains(return_items, "|")) {
|
||||
const auto item_data = Strings::Split(return_items, "|");
|
||||
if (
|
||||
item_data.size() == 3 &&
|
||||
Strings::IsNumber(item_data[0]) &&
|
||||
Strings::IsNumber(item_data[1]) &&
|
||||
Strings::IsNumber(item_data[2])
|
||||
) {
|
||||
const uint32 item_id = Strings::ToUnsignedInt(item_data[0]);
|
||||
const auto* item = database.GetItem(item_id);
|
||||
|
||||
if (item) {
|
||||
ri.emplace_back(
|
||||
PlayerEvent::HandinEntry{
|
||||
.item_id = item_id,
|
||||
.item_name = item->Name,
|
||||
.charges = static_cast<uint16>(Strings::ToUnsignedInt(item_data[1])),
|
||||
.attuned = Strings::ToInt(item_data[2]) ? true : false
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return Money
|
||||
if (!return_money.empty()) {
|
||||
const auto rms = Strings::Split(return_money, "|");
|
||||
rm.copper = static_cast<uint32>(Strings::ToUnsignedInt(rms[0]));
|
||||
rm.silver = static_cast<uint32>(Strings::ToUnsignedInt(rms[1]));
|
||||
rm.gold = static_cast<uint32>(Strings::ToUnsignedInt(rms[2]));
|
||||
rm.platinum = static_cast<uint32>(Strings::ToUnsignedInt(rms[3]));
|
||||
}
|
||||
|
||||
c->DeleteEntityVariable("HANDIN_ITEMS");
|
||||
c->DeleteEntityVariable("HANDIN_MONEY");
|
||||
c->DeleteEntityVariable("RETURN_ITEMS");
|
||||
c->DeleteEntityVariable("RETURN_MONEY");
|
||||
|
||||
const bool handed_in_money = hm.platinum > 0 || hm.gold > 0 || hm.silver > 0 || hm.copper > 0;
|
||||
|
||||
const bool event_has_data_to_record = (
|
||||
!hi.empty() || handed_in_money
|
||||
);
|
||||
|
||||
if (player_event_logs.IsEventEnabled(PlayerEvent::NPC_HANDIN) && event_has_data_to_record) {
|
||||
auto e = PlayerEvent::HandinEvent{
|
||||
.npc_id = n->GetNPCTypeID(),
|
||||
.npc_name = n->GetCleanName(),
|
||||
.handin_items = hi,
|
||||
.handin_money = hm,
|
||||
.return_items = ri,
|
||||
.return_money = rm,
|
||||
.is_quest_handin = true
|
||||
};
|
||||
|
||||
RecordPlayerEventLogWithClient(c, PlayerEvent::NPC_HANDIN, e);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 item_count = 0;
|
||||
|
||||
hm.platinum = t->pp;
|
||||
hm.gold = t->gp;
|
||||
hm.silver = t->sp;
|
||||
hm.copper = t->cp;
|
||||
|
||||
for (uint16 i = EQ::invslot::TRADE_BEGIN; i <= EQ::invslot::TRADE_NPC_END; i++) {
|
||||
if (c->GetInv().GetItem(i)) {
|
||||
item_count++;
|
||||
}
|
||||
}
|
||||
|
||||
hi.reserve(item_count);
|
||||
|
||||
if (item_count > 0) {
|
||||
for (uint16 i = EQ::invslot::TRADE_BEGIN; i <= EQ::invslot::TRADE_NPC_END; i++) {
|
||||
const EQ::ItemInstance* inst = c->GetInv().GetItem(i);
|
||||
if (inst) {
|
||||
hi.emplace_back(
|
||||
PlayerEvent::HandinEntry{
|
||||
.item_id = inst->GetItem()->ID,
|
||||
.item_name = inst->GetItem()->Name,
|
||||
.charges = static_cast<uint16>(inst->GetCharges()),
|
||||
.attuned = inst->IsAttuned()
|
||||
}
|
||||
);
|
||||
|
||||
if (inst->IsClassBag()) {
|
||||
for (uint8 j = EQ::invbag::SLOT_BEGIN; j <= EQ::invbag::SLOT_END; j++) {
|
||||
inst = c->GetInv().GetItem(i, j);
|
||||
if (inst) {
|
||||
hi.emplace_back(
|
||||
PlayerEvent::HandinEntry{
|
||||
.item_id = inst->GetItem()->ID,
|
||||
.item_name = inst->GetItem()->Name,
|
||||
.charges = static_cast<uint16>(inst->GetCharges()),
|
||||
.attuned = inst->IsAttuned()
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const bool handed_in_money = hm.platinum > 0 || hm.gold > 0 || hm.silver > 0 || hm.copper > 0;
|
||||
|
||||
ri = hi;
|
||||
rm = hm;
|
||||
|
||||
const bool event_has_data_to_record = !hi.empty() || handed_in_money;
|
||||
|
||||
if (player_event_logs.IsEventEnabled(PlayerEvent::NPC_HANDIN) && event_has_data_to_record) {
|
||||
auto e = PlayerEvent::HandinEvent{
|
||||
.npc_id = n->GetNPCTypeID(),
|
||||
.npc_name = n->GetCleanName(),
|
||||
.handin_items = hi,
|
||||
.handin_money = hm,
|
||||
.return_items = ri,
|
||||
.return_money = rm,
|
||||
.is_quest_handin = false
|
||||
};
|
||||
|
||||
RecordPlayerEventLogWithClient(c, PlayerEvent::NPC_HANDIN, e);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::ShowSpells(Client* c, ShowSpellType show_spell_type)
|
||||
{
|
||||
std::string spell_string;
|
||||
|
||||
Reference in New Issue
Block a user