Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Items] Overhaul Item Handin System #4512

Draft
wants to merge 44 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
3dafffe
Initial
Kinglykrab Oct 14, 2024
45cab22
Push it
Akkadius Oct 14, 2024
498a138
More work
Akkadius Oct 14, 2024
61433e3
Handin logic
Akkadius Oct 14, 2024
35967d8
More
Akkadius Oct 14, 2024
58b9dfc
Make sure we always hand back but never double process
Akkadius Oct 14, 2024
935c863
Update trading.cpp
Akkadius Oct 14, 2024
09295fb
Push
Kinglykrab Oct 14, 2024
111c795
Push
Kinglykrab Oct 14, 2024
fc09ec7
ReturnHandinItems
Akkadius Oct 14, 2024
7f61bbd
Update client.h
Akkadius Oct 14, 2024
adba63e
Perl/Lua ReturnHandinItems
Kinglykrab Oct 14, 2024
b82d815
Update client.cpp
Kinglykrab Oct 14, 2024
ca25e7b
Update player_event_discord_formatter.cpp
Kinglykrab Oct 14, 2024
a4d8347
Checkin
Akkadius Oct 14, 2024
7fd0896
Fin
Akkadius Oct 14, 2024
b7d131a
Fix handin tracking
Akkadius Oct 15, 2024
58fffaa
Further simplify hand-in logic
Akkadius Oct 15, 2024
6baf9f8
Further cleanup and simplification
Akkadius Oct 15, 2024
b55bbd4
Tweaks
Akkadius Oct 15, 2024
53a166e
Tweaks: weapon charges should be at minimum 1
Akkadius Oct 15, 2024
c48016a
Consistent types
Akkadius Oct 15, 2024
f22b487
Simplify
Akkadius Oct 15, 2024
682e8e8
Add CheckForCompatibleQuestPlugins
Akkadius Oct 15, 2024
06fc61b
Add multiquest_enabled flag to NPCs
Kinglykrab Oct 15, 2024
19affb6
Update main.cpp
Kinglykrab Oct 15, 2024
c6c4aac
More code simplification
Akkadius Oct 20, 2024
409efef
Create NpcHandin log category, improve logging messages
Akkadius Oct 21, 2024
201944e
Implement tome hand in source side
Akkadius Oct 21, 2024
ae9daaf
Remove casters from guildmaster_map
Kinglykrab Oct 21, 2024
8e8608c
Revert "Remove casters from guildmaster_map"
Akkadius Oct 21, 2024
361cf5e
re-introduce check into IsDisciplineTome
Akkadius Oct 21, 2024
34163c5
Tweaks
Akkadius Oct 22, 2024
0a621bf
multi-quest working
Akkadius Oct 22, 2024
78ed388
move multi-quest buckets and methods to be npc scoped
Akkadius Oct 22, 2024
7eae203
Update npc.h
Akkadius Oct 22, 2024
34c6d04
Have multi-quest NPC's drop droppable items that were handed in
Akkadius Oct 22, 2024
d4c7704
cleanup
Akkadius Oct 22, 2024
0afa5f7
Update main.cpp
Kinglykrab Oct 24, 2024
26d8199
Fix client response
Akkadius Oct 24, 2024
8d9451a
logic simplification
Akkadius Oct 24, 2024
2c4e69e
tweaks
Akkadius Oct 24, 2024
14b7901
tests
Akkadius Oct 24, 2024
d155896
Automated testing
Akkadius Oct 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions common/database/database_update_manifest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5758,6 +5758,17 @@ ALTER TABLE `inventory_snapshots`
ALTER TABLE `character_exp_modifiers`
MODIFY COLUMN `aa_modifier` float NOT NULL DEFAULT 1.0 AFTER `instance_version`,
MODIFY COLUMN `exp_modifier` float NOT NULL DEFAULT 1.0 AFTER `aa_modifier`;
)"
},
ManifestEntry{
.version = 9285,
.description = "2024_10_15_npc_types_multiquest_enabled.sql",
.check = "SHOW COLUMNS FROM `npc_types` LIKE 'multiquest_enabled'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `npc_types`
ADD COLUMN `multiquest_enabled` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 AFTER `is_parcel_merchant`;
)"
}
// -- template; copy/paste this when you need to create a new entry
Expand Down
2 changes: 2 additions & 0 deletions common/eqemu_logsys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
log_settings[Logs::QuestErrors].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::EqTime].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::EqTime].log_to_gmsay = static_cast<uint8>(Logs::General);
log_settings[Logs::NpcHandin].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::NpcHandin].log_to_gmsay = static_cast<uint8>(Logs::General);

/**
* RFC 5424
Expand Down
4 changes: 3 additions & 1 deletion common/eqemu_logsys.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ namespace Logs {
EqTime,
Corpses,
XTargets,
NpcHandin,
MaxCategoryID /* Don't Remove this */
};

Expand Down Expand Up @@ -242,7 +243,8 @@ namespace Logs {
"Zoning",
"EqTime",
"Corpses",
"XTargets"
"XTargets",
"NpcHandin"
};
}

Expand Down
11 changes: 10 additions & 1 deletion common/eqemu_logsys_log_aliases.h
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,6 @@
OutF(LogSys, Logs::Detail, Logs::PacketServerClient, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)


#define LogLoginserver(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::Loginserver))\
OutF(LogSys, Logs::General, Logs::Loginserver, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
Expand Down Expand Up @@ -844,6 +843,16 @@
OutF(LogSys, Logs::Detail, Logs::XTargets, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)

#define LogNpcHandin(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::NpcHandin))\
OutF(LogSys, Logs::General, Logs::NpcHandin, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)

#define LogNpcHandinDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::NpcHandin))\
OutF(LogSys, Logs::Detail, Logs::NpcHandin, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)

#define Log(debug_level, log_category, message, ...) do {\
if (LogSys.IsLogEnabled(debug_level, log_category))\
LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
Expand Down
24 changes: 24 additions & 0 deletions common/events/player_event_discord_formatter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,18 @@ std::string PlayerEventDiscordFormatter::FormatNPCHandinEvent(
h.charges > 1 ? fmt::format(" Charges: {}", h.charges) : "",
h.attuned ? " (Attuned)" : ""
);

for (int i = 0; i < h.augment_ids.size(); i++) {
if (!Strings::EqualFold(h.augment_names[i], "None")) {
const uint8 slot_id = (i + 1);
handin_items_info += fmt::format(
"Augment {}: {} ({})\n",
slot_id,
h.augment_names[i],
h.augment_ids[i]
);
}
}
}
}

Expand All @@ -727,6 +739,18 @@ std::string PlayerEventDiscordFormatter::FormatNPCHandinEvent(
r.charges > 1 ? fmt::format(" Charges: {}", r.charges) : "",
r.attuned ? " (Attuned)" : ""
);

for (int i = 0; i < r.augment_ids.size(); i++) {
if (!Strings::EqualFold(r.augment_names[i], "None")) {
const uint8 slot_id = (i + 1);
handin_items_info += fmt::format(
"Augment {}: {} ({})\n",
slot_id,
r.augment_names[i],
r.augment_ids[i]
);
}
}
}
}

Expand Down
21 changes: 21 additions & 0 deletions common/item_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,27 @@ bool EQ::ItemData::IsType1HWeapon() const
return ((ItemType == item::ItemType1HBlunt) || (ItemType == item::ItemType1HSlash) || (ItemType == item::ItemType1HPiercing) || (ItemType == item::ItemTypeMartial));
}

bool EQ::ItemData::IsPetUsable() const
{
if (ItemClass == item::ItemClassBag) {
return true;
}

switch (ItemType) {
case item::ItemType1HBlunt:
case item::ItemType1HSlash:
case item::ItemType1HPiercing:
case item::ItemType2HBlunt:
case item::ItemType2HSlash:
case item::ItemTypeMartial:
case item::ItemTypeShield:
case item::ItemTypeArmor:
return true;
default:
return false;
}
}

bool EQ::ItemData::IsType2HWeapon() const
{
return ((ItemType == item::ItemType2HBlunt) || (ItemType == item::ItemType2HSlash) || (ItemType == item::ItemType2HPiercing));
Expand Down
1 change: 1 addition & 0 deletions common/item_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,7 @@ namespace EQ
bool IsType1HWeapon() const;
bool IsType2HWeapon() const;
bool IsTypeShield() const;
bool IsPetUsable() const;
bool IsQuestItem() const;

static bool CheckLoreConflict(const ItemData* l_item, const ItemData* r_item);
Expand Down
12 changes: 12 additions & 0 deletions common/item_instance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1806,6 +1806,18 @@ std::vector<uint32> EQ::ItemInstance::GetAugmentIDs() const
return augments;
}

std::vector<std::string> EQ::ItemInstance::GetAugmentNames() const
{
std::vector<std::string> augment_names;

for (uint8 slot_id = invaug::SOCKET_BEGIN; slot_id <= invaug::SOCKET_END; slot_id++) {
const auto augment = GetAugment(slot_id);
augment_names.push_back(augment ? augment->GetItem()->Name : "None");
}

return augment_names;
}

int EQ::ItemInstance::GetItemRegen(bool augments) const
{
int stat = 0;
Expand Down
1 change: 1 addition & 0 deletions common/item_instance.h
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ namespace EQ
int GetItemSkillsStat(EQ::skills::SkillType skill, bool augments = false) const;
uint32 GetItemGuildFavor() const;
std::vector<uint32> GetAugmentIDs() const;
std::vector<std::string> GetAugmentNames() const;
static void AddGUIDToMap(uint64 existing_serial_number);
static void ClearGUIDMap();

Expand Down
12 changes: 12 additions & 0 deletions common/repositories/base/base_npc_types_repository.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ class BaseNpcTypesRepository {
int32_t faction_amount;
uint8_t keeps_sold_items;
uint8_t is_parcel_merchant;
uint8_t multiquest_enabled;
};

static std::string PrimaryKey()
Expand Down Expand Up @@ -287,6 +288,7 @@ class BaseNpcTypesRepository {
"faction_amount",
"keeps_sold_items",
"is_parcel_merchant",
"multiquest_enabled",
};
}

Expand Down Expand Up @@ -422,6 +424,7 @@ class BaseNpcTypesRepository {
"faction_amount",
"keeps_sold_items",
"is_parcel_merchant",
"multiquest_enabled",
};
}

Expand Down Expand Up @@ -591,6 +594,7 @@ class BaseNpcTypesRepository {
e.faction_amount = 0;
e.keeps_sold_items = 1;
e.is_parcel_merchant = 0;
e.multiquest_enabled = 0;

return e;
}
Expand Down Expand Up @@ -756,6 +760,7 @@ class BaseNpcTypesRepository {
e.faction_amount = row[126] ? static_cast<int32_t>(atoi(row[126])) : 0;
e.keeps_sold_items = row[127] ? static_cast<uint8_t>(strtoul(row[127], nullptr, 10)) : 1;
e.is_parcel_merchant = row[128] ? static_cast<uint8_t>(strtoul(row[128], nullptr, 10)) : 0;
e.multiquest_enabled = row[129] ? static_cast<uint8_t>(strtoul(row[129], nullptr, 10)) : 0;

return e;
}
Expand Down Expand Up @@ -917,6 +922,7 @@ class BaseNpcTypesRepository {
v.push_back(columns[126] + " = " + std::to_string(e.faction_amount));
v.push_back(columns[127] + " = " + std::to_string(e.keeps_sold_items));
v.push_back(columns[128] + " = " + std::to_string(e.is_parcel_merchant));
v.push_back(columns[129] + " = " + std::to_string(e.multiquest_enabled));

auto results = db.QueryDatabase(
fmt::format(
Expand Down Expand Up @@ -1067,6 +1073,7 @@ class BaseNpcTypesRepository {
v.push_back(std::to_string(e.faction_amount));
v.push_back(std::to_string(e.keeps_sold_items));
v.push_back(std::to_string(e.is_parcel_merchant));
v.push_back(std::to_string(e.multiquest_enabled));

auto results = db.QueryDatabase(
fmt::format(
Expand Down Expand Up @@ -1225,6 +1232,7 @@ class BaseNpcTypesRepository {
v.push_back(std::to_string(e.faction_amount));
v.push_back(std::to_string(e.keeps_sold_items));
v.push_back(std::to_string(e.is_parcel_merchant));
v.push_back(std::to_string(e.multiquest_enabled));

insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
Expand Down Expand Up @@ -1387,6 +1395,7 @@ class BaseNpcTypesRepository {
e.faction_amount = row[126] ? static_cast<int32_t>(atoi(row[126])) : 0;
e.keeps_sold_items = row[127] ? static_cast<uint8_t>(strtoul(row[127], nullptr, 10)) : 1;
e.is_parcel_merchant = row[128] ? static_cast<uint8_t>(strtoul(row[128], nullptr, 10)) : 0;
e.multiquest_enabled = row[129] ? static_cast<uint8_t>(strtoul(row[129], nullptr, 10)) : 0;

all_entries.push_back(e);
}
Expand Down Expand Up @@ -1540,6 +1549,7 @@ class BaseNpcTypesRepository {
e.faction_amount = row[126] ? static_cast<int32_t>(atoi(row[126])) : 0;
e.keeps_sold_items = row[127] ? static_cast<uint8_t>(strtoul(row[127], nullptr, 10)) : 1;
e.is_parcel_merchant = row[128] ? static_cast<uint8_t>(strtoul(row[128], nullptr, 10)) : 0;
e.multiquest_enabled = row[129] ? static_cast<uint8_t>(strtoul(row[129], nullptr, 10)) : 0;

all_entries.push_back(e);
}
Expand Down Expand Up @@ -1743,6 +1753,7 @@ class BaseNpcTypesRepository {
v.push_back(std::to_string(e.faction_amount));
v.push_back(std::to_string(e.keeps_sold_items));
v.push_back(std::to_string(e.is_parcel_merchant));
v.push_back(std::to_string(e.multiquest_enabled));

auto results = db.QueryDatabase(
fmt::format(
Expand Down Expand Up @@ -1894,6 +1905,7 @@ class BaseNpcTypesRepository {
v.push_back(std::to_string(e.faction_amount));
v.push_back(std::to_string(e.keeps_sold_items));
v.push_back(std::to_string(e.is_parcel_merchant));
v.push_back(std::to_string(e.multiquest_enabled));

insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
Expand Down
5 changes: 1 addition & 4 deletions common/ruletypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,10 +283,9 @@ RULE_CATEGORY(Pets)
RULE_REAL(Pets, AttackCommandRange, 150, "Range at which a pet will respond to attack commands")
RULE_BOOL(Pets, UnTargetableSwarmPet, false, "Setting whether swarm pets should be targetable")
RULE_REAL(Pets, PetPowerLevelCap, 10, "Maximum number of levels a player pet can go up with pet power")
RULE_BOOL(Pets, CanTakeNoDrop, false, "Setting whether anyone can give no-drop items to pets")
RULE_BOOL(Pets, CanTakeQuestItems, true, "Setting whether anyone can give quest items to pets")
RULE_BOOL(Pets, LivelikeBreakCharmOnInvis, true, "Default: true will break charm on any type of invis (hide/ivu/iva/etc) false will only break if the pet can not see you (ex. you have an undead pet and cast IVU")
RULE_BOOL(Pets, ClientPetsUseOwnerNameInLastName, true, "Disable this to keep client pet's last names from being owner_name's pet")
RULE_BOOL(Pets, CanTakeNoDrop, false, "Setting whether anyone can give no-drop items to pets")
RULE_INT(Pets, PetTauntRange, 150, "Range at which a pet will taunt targets.")
RULE_CATEGORY_END()

Expand Down Expand Up @@ -657,8 +656,6 @@ RULE_BOOL(NPC, EnableNPCQuestJournal, false, "Setting whether the NPC Quest Jour
RULE_INT(NPC, LastFightingDelayMovingMin, 10000, "Minimum time before mob goes home after all aggro loss (milliseconds)")
RULE_INT(NPC, LastFightingDelayMovingMax, 20000, "Maximum time before mob goes home after all aggro loss (milliseconds)")
RULE_BOOL(NPC, SmartLastFightingDelayMoving, true, "When true, mobs that started going home previously will do so again immediately if still on FD hate list")
RULE_BOOL(NPC, ReturnNonQuestNoDropItems, false, "Returns NO DROP items on NPC that don't have an EVENT_TRADE sub in their script")
RULE_BOOL(NPC, ReturnQuestItemsFromNonQuestNPCs, false, "Returns Quest items traded to NPCs that are not flagged as a Quest NPC")
RULE_INT(NPC, StartEnrageValue, 9, " Percentage HP that an NPC will begin to enrage")
RULE_BOOL(NPC, LiveLikeEnrage, false, "If set to true then only player controlled pets will enrage")
RULE_BOOL(NPC, EnableMeritBasedFaction, false, "If set to true, faction will be given in the same way as experience (solo/group/raid)")
Expand Down
53 changes: 52 additions & 1 deletion common/spdat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2367,7 +2367,7 @@ bool IsAegolismSpell(uint16 spell_id) {


bool AegolismStackingIsSymbolSpell(uint16 spell_id) {

/*
This is hardcoded to be specific to the type of HP buffs that are removed if a mob has an Aegolism buff.
*/
Expand Down Expand Up @@ -2430,3 +2430,54 @@ bool AegolismStackingIsArmorClassSpell(uint16 spell_id) {

return 0;
}

bool IsDisciplineTome(const EQ::ItemData* item)
{
if (!item->IsClassCommon() || item->ItemType != EQ::item::ItemTypeSpell) {
return false;
}

//Need a way to determine the difference between a spell and a tome
//so they cant turn in a spell and get it as a discipline
//this is kinda a hack:

const std::string item_name = item->Name;

if (
!Strings::BeginsWith(item_name, "Tome of ") &&
!Strings::BeginsWith(item_name, "Skill: ")
) {
return false;
}

//we know for sure none of the int casters get disciplines
uint32 class_bit = 0;
class_bit |= 1 << (Class::Wizard - 1);
class_bit |= 1 << (Class::Enchanter - 1);
class_bit |= 1 << (Class::Magician - 1);
class_bit |= 1 << (Class::Necromancer - 1);
if (item->Classes & class_bit) {
return false;
}

const auto& spell_id = static_cast<uint32>(item->Scroll.Effect);
if (!IsValidSpell(spell_id)) {
return false;
}

if (!IsDiscipline(spell_id)) {
return false;
}

const auto &spell = spells[spell_id];
if (
spell.classes[Class::Wizard - 1] != 255 &&
spell.classes[Class::Enchanter - 1] != 255 &&
spell.classes[Class::Magician - 1] != 255 &&
spell.classes[Class::Necromancer - 1] != 255
) {
return false;
}

return true;
}
2 changes: 2 additions & 0 deletions common/spdat.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include "classes.h"
#include "skills.h"
#include "item_data.h"

#define SPELL_UNKNOWN 0xFFFF
#define POISON_PROC 0xFFFE
Expand Down Expand Up @@ -1628,5 +1629,6 @@ bool IsCastRestrictedSpell(uint16 spell_id);
bool IsAegolismSpell(uint16 spell_id);
bool AegolismStackingIsSymbolSpell(uint16 spell_id);
bool AegolismStackingIsArmorClassSpell(uint16 spell_id);
bool IsDisciplineTome(const EQ::ItemData* item);

#endif
2 changes: 1 addition & 1 deletion common/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/

#define CURRENT_BINARY_DATABASE_VERSION 9284
#define CURRENT_BINARY_DATABASE_VERSION 9285
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9045

#endif
Expand Down
11 changes: 11 additions & 0 deletions zone/attack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2513,6 +2513,17 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
return false;
}

if (IsMultiQuestEnabled()) {
for (auto &i: m_hand_in.items) {
if (i.is_multiquest_item && i.item->GetItem()->NoDrop != 0) {
auto lde = LootdropEntriesRepository::NewNpcEntity();
lde.equip_item = 0;
lde.item_charges = i.item->GetCharges();
AddLootDrop(i.item->GetItem(), lde, true);
}
}
}

if (killer_mob && killer_mob->IsOfClientBot() && IsValidSpell(spell) && damage > 0) {
char val1[20] = { 0 };

Expand Down
Loading