diff --git a/common/repositories/base/base_npc_types_repository.h b/common/repositories/base/base_npc_types_repository.h index 7d0def72d..4a6a0f688 100644 --- a/common/repositories/base/base_npc_types_repository.h +++ b/common/repositories/base/base_npc_types_repository.h @@ -16,6 +16,7 @@ #include "../../strings.h" #include + class BaseNpcTypesRepository { public: struct NpcTypes { @@ -145,6 +146,7 @@ public: int32_t exp_mod; int32_t heroic_strikethrough; int32_t faction_amount; + uint8_t keeps_sold_items; }; static std::string PrimaryKey() @@ -281,6 +283,7 @@ public: "exp_mod", "heroic_strikethrough", "faction_amount", + "keeps_sold_items", }; } @@ -413,6 +416,7 @@ public: "exp_mod", "heroic_strikethrough", "faction_amount", + "keeps_sold_items", }; } @@ -579,6 +583,7 @@ public: e.exp_mod = 100; e.heroic_strikethrough = 0; e.faction_amount = 0; + e.keeps_sold_items = 0; return e; } @@ -604,8 +609,9 @@ public: { auto results = db.QueryDatabase( fmt::format( - "{} WHERE id = {} LIMIT 1", + "{} WHERE {} = {} LIMIT 1", BaseSelect(), + PrimaryKey(), npc_types_id ) ); @@ -740,6 +746,7 @@ public: e.exp_mod = static_cast(atoi(row[123])); e.heroic_strikethrough = static_cast(atoi(row[124])); e.faction_amount = static_cast(atoi(row[125])); + e.keeps_sold_items = static_cast(strtoul(row[126], nullptr, 10)); return e; } @@ -898,6 +905,7 @@ public: v.push_back(columns[123] + " = " + std::to_string(e.exp_mod)); v.push_back(columns[124] + " = " + std::to_string(e.heroic_strikethrough)); v.push_back(columns[125] + " = " + std::to_string(e.faction_amount)); + v.push_back(columns[126] + " = " + std::to_string(e.keeps_sold_items)); auto results = db.QueryDatabase( fmt::format( @@ -1045,6 +1053,7 @@ public: v.push_back(std::to_string(e.exp_mod)); v.push_back(std::to_string(e.heroic_strikethrough)); v.push_back(std::to_string(e.faction_amount)); + v.push_back(std::to_string(e.keeps_sold_items)); auto results = db.QueryDatabase( fmt::format( @@ -1200,6 +1209,7 @@ public: v.push_back(std::to_string(e.exp_mod)); v.push_back(std::to_string(e.heroic_strikethrough)); v.push_back(std::to_string(e.faction_amount)); + v.push_back(std::to_string(e.keeps_sold_items)); insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); } @@ -1359,6 +1369,7 @@ public: e.exp_mod = static_cast(atoi(row[123])); e.heroic_strikethrough = static_cast(atoi(row[124])); e.faction_amount = static_cast(atoi(row[125])); + e.keeps_sold_items = static_cast(strtoul(row[126], nullptr, 10)); all_entries.push_back(e); } @@ -1509,6 +1520,7 @@ public: e.exp_mod = static_cast(atoi(row[123])); e.heroic_strikethrough = static_cast(atoi(row[124])); e.faction_amount = static_cast(atoi(row[125])); + e.keeps_sold_items = static_cast(strtoul(row[126], nullptr, 10)); all_entries.push_back(e); } diff --git a/common/version.h b/common/version.h index f043aa1ab..3fe574ff2 100644 --- a/common/version.h +++ b/common/version.h @@ -34,7 +34,7 @@ * Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9212 +#define CURRENT_BINARY_DATABASE_VERSION 9213 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9035 diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 2925a39e8..bb9c093f6 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -466,6 +466,7 @@ 9210|2022_10_11_fix_misty_pok_stone.sql|select * from doors where id = 2040 and `name` = 'POKRVPORT500' and client_version_mask = 4294967232|empty| 9211|2022_10_14_fix_neriak_pok_stone.sql|select * from doors where id = 2057 and `name` = 'POKNRKPORT500' and client_version_mask = 4294967232|empty| 9212|2022_10_14_fix_misty_pok_stone.sql|select * from doors where id = 2040 and `name` = 'POKRVPORT500' and dest_zone = 'misty'|empty| +9213|2022_12_24_npc_keeps_sold_items.sql|SHOW COLUMNS FROM `npc_types` LIKE 'keeps_sold_items'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2022_12_24_npc_keeps_sold_items.sql b/utils/sql/git/required/2022_12_24_npc_keeps_sold_items.sql new file mode 100644 index 000000000..33d530203 --- /dev/null +++ b/utils/sql/git/required/2022_12_24_npc_keeps_sold_items.sql @@ -0,0 +1,2 @@ +ALTER TABLE `npc_types` +ADD COLUMN `keeps_sold_items` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 AFTER `faction_amount`; \ No newline at end of file diff --git a/zone/beacon.cpp b/zone/beacon.cpp index c63172632..1dbb234e6 100644 --- a/zone/beacon.cpp +++ b/zone/beacon.cpp @@ -52,14 +52,66 @@ extern Zone* zone; // if lifetime is 0 this is a permanent beacon.. not sure if that'll be // useful for anything -Beacon::Beacon(const glm::vec4 &in_pos, int lifetime) -:Mob -( - nullptr, nullptr, 0, 0, 0, INVISIBLE_MAN, 0, BT_NoTarget, 0, 0, 0, 0, 0, in_pos, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, EQ::TintProfile(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false +Beacon::Beacon(const glm::vec4 &in_pos, int lifetime) : Mob( + nullptr, // in_name + nullptr, // in_lastname + 0, // in_cur_hp + 0, // in_max_hp + MALE, // in_gender + INVISIBLE_MAN, // in_race + 0, // in_class + BT_NoTarget, // in_bodytype + 0, // in_deity + 0, // in_level + 0, // in_npctype_id + 0.0f, // in_size + 0.0f, // in_runspeed + in_pos, // position + 0, // in_light + 0, // in_texture + 0, // 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 + 0, // 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 ), - remove_timer(lifetime), - spell_timer(0) + remove_timer(lifetime), + spell_timer(0) { remove_timer.Disable(); spell_timer.Disable(); diff --git a/zone/client.cpp b/zone/client.cpp index 176857684..1f30d5471 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -82,63 +82,64 @@ char entirecommand[255]; void UpdateWindowTitle(char* iNewTitle); -Client::Client(EQStreamInterface* ieqs) -: Mob("No name", // name - "", // lastname - 0, // cur_hp - 0, // max_hp - 0, // gender - 0, // race - 0, // class - BT_Humanoid, // bodytype - 0, // deity - 0, // level - 0, // npctypeid - 0, // size - 0.7, // runspeed - glm::vec4(), - 0, // light - verified for client innate_light value - 0xFF, // texture - 0xFF, // helmtexture - 0, // ac - 0, // atk - 0, // str - 0, // sta - 0, // dex - 0, // agi - 0, // int - 0, // wis - 0, // cha - 0, // Luclin Hair Colour - 0, // Luclin Beard Color - 0, // Luclin Eye1 - 0, // Luclin Eye2 - 0, // Luclin Hair Style - 0, // Luclin Face - 0, // Luclin Beard - 0, // Drakkin Heritage - 0, // Drakkin Tattoo - 0, // Drakkin Details - EQ::TintProfile(), // Armor Tint - 0xff, // AA Title - 0, // see_invis - 0, // see_invis_undead - 0, - 0, - 0, - 0, - 0, // qglobal - 0, // maxlevel - 0, // scalerate - 0, - 0, - 0, - 0, - 0, - 0, - 0, - false - ), +Client::Client(EQStreamInterface *ieqs) : Mob( + "No name", // in_name + "", // in_lastname + 0, // in_cur_hp + 0, // in_max_hp + 0, // in_gender + 0, // in_race + 0, // in_class + BT_Humanoid, // in_bodytype + 0, // 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), diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 939bfcc83..3df7cbea2 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -13403,32 +13403,50 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app) int charges = mp->quantity; - int freeslot = 0; - if ((freeslot = zone->SaveTempItem(vendor->CastToNPC()->MerchantType, vendor->GetNPCTypeID(), itemid, charges, true)) > 0) { - EQ::ItemInstance* inst2 = inst->Clone(); + if (vendor->GetKeepsSoldItems()) { + int freeslot = 0; + if ( + (freeslot = zone->SaveTempItem( + vendor->CastToNPC()->MerchantType, + vendor->GetNPCTypeID(), + itemid, + charges, + true + ) + ) > 0) { + EQ::ItemInstance *inst2 = inst->Clone(); + + while (true) { + if (!inst2) { + break; + } + + uint32 price = ( + item->Price * + RuleR(Merchant, SellCostMod) * + item->SellRate + ); + + if (RuleB(Merchant, UsePriceMod)) { + price *= Client::CalcPriceMod(vendor, false); + } + + inst2->SetPrice(price); + inst2->SetMerchantSlot(freeslot); + + uint32 merchant_quantity = zone->GetTempMerchantQuantity(vendor->GetNPCTypeID(), freeslot); + + if (inst2->IsStackable()) { + inst2->SetCharges(merchant_quantity); + } + + inst2->SetMerchantCount(merchant_quantity); + + SendItemPacket(freeslot - 1, inst2, ItemPacketMerchant); + safe_delete(inst2); - while (true) { - if (inst2 == nullptr) break; - - if (RuleB(Merchant, UsePriceMod)) { - inst2->SetPrice(item->Price*(RuleR(Merchant, SellCostMod))*item->SellRate*Client::CalcPriceMod(vendor, false)); } - else - inst2->SetPrice(item->Price*(RuleR(Merchant, SellCostMod))*item->SellRate); - inst2->SetMerchantSlot(freeslot); - - uint32 MerchantQuantity = zone->GetTempMerchantQuantity(vendor->GetNPCTypeID(), freeslot); - - if (inst2->IsStackable()) { - inst2->SetCharges(MerchantQuantity); - } - inst2->SetMerchantCount(MerchantQuantity); - - SendItemPacket(freeslot - 1, inst2, ItemPacketMerchant); - safe_delete(inst2); - - break; } } diff --git a/zone/corpse.cpp b/zone/corpse.cpp index 361434fbd..1a463f437 100644 --- a/zone/corpse.cpp +++ b/zone/corpse.cpp @@ -30,6 +30,7 @@ Child of the Mob class. #define strcasecmp _stricmp #endif +#include "../common/data_verification.h" #include "../common/global_define.h" #include "../common/eqemu_logsys.h" #include "../common/rulesys.h" @@ -148,19 +149,75 @@ Corpse* Corpse::LoadCharacterCorpseEntity(uint32 in_dbid, uint32 in_charid, std: return pc; } -Corpse::Corpse(NPC* in_npc, ItemList* in_itemlist, uint32 in_npctypeid, const NPCType** in_npctypedata, uint32 in_decaytime) -// vesuvias - appearence fix -: Mob("Unnamed_Corpse","",0,0,in_npc->GetGender(),in_npc->GetRace(),in_npc->GetClass(),BT_Humanoid,//bodytype added - in_npc->GetDeity(),in_npc->GetLevel(),in_npc->GetNPCTypeID(),in_npc->GetSize(),0, - in_npc->GetPosition(), in_npc->GetInnateLightType(), in_npc->GetTexture(),in_npc->GetHelmTexture(), - 0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,EQ::TintProfile(),0xff,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - (*in_npctypedata)->use_model, false), - corpse_decay_timer(in_decaytime), - corpse_rez_timer(0), - corpse_delay_timer(RuleI(NPC, CorpseUnlockTimer)), - corpse_graveyard_timer(0), - loot_cooldown_timer(10) +Corpse::Corpse( + NPC *in_npc, + ItemList *in_itemlist, + uint32 in_npctypeid, + const NPCType **in_npctypedata, + uint32 in_decaytime +) : Mob( + "Unnamed_Corpse", // in_name + "", // in_lastname + 0, // in_cur_hp + 0, // in_max_hp + in_npc->GetGender(), // in_gender + in_npc->GetRace(), // in_race + in_npc->GetClass(), // in_class + BT_Humanoid, // in_bodytype + in_npc->GetDeity(), // in_deity + in_npc->GetLevel(), // in_level + in_npc->GetNPCTypeID(), // in_npctype_id + in_npc->GetSize(), // in_size + 0.0f, // in_runspeed + in_npc->GetPosition(), // position + in_npc->GetInnateLightType(), // in_light + in_npc->GetTexture(), // in_texture + in_npc->GetHelmTexture(), // 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 + (*in_npctypedata)->use_model, // in_usemodel + false, // in_always_aggros_foes + 0, // in_heroic_strikethrough + false // in_keeps_sold_items +), + corpse_decay_timer(in_decaytime), + corpse_rez_timer(0), + corpse_delay_timer(RuleI(NPC, CorpseUnlockTimer)), + corpse_graveyard_timer(0), + loot_cooldown_timer(10) { corpse_graveyard_timer.Disable(); @@ -184,23 +241,31 @@ Corpse::Corpse(NPC* in_npc, ItemList* in_itemlist, uint32 in_npctypeid, const NP strcpy(name, in_npc->GetName()); for(int count = 0; count < 100; count++) { - if ((level >= npcCorpseDecayTimes[count].minlvl) && (level <= npcCorpseDecayTimes[count].maxlvl)) { + if ( + EQ::ValueWithin( + level, + npcCorpseDecayTimes[count].minlvl, + npcCorpseDecayTimes[count].maxlvl + ) + ) { corpse_decay_timer.SetTimer(npcCorpseDecayTimes[count].seconds*1000); break; } } - if(IsEmpty()) { + + if (IsEmpty()) { corpse_decay_timer.SetTimer(RuleI(NPC,EmptyNPCCorpseDecayTimeMS)+1000); } - if(in_npc->HasPrivateCorpse()) { + if (in_npc->HasPrivateCorpse()) { corpse_delay_timer.SetTimer(corpse_decay_timer.GetRemainingTime() + 1000); } for (int i = 0; i < MAX_LOOTERS; i++){ allowed_looters[i] = 0; } + rez_experience = 0; UpdateEquipmentLight(); @@ -210,107 +275,105 @@ Corpse::Corpse(NPC* in_npc, ItemList* in_itemlist, uint32 in_npctypeid, const NP } Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( - "Unnamed_Corpse", // const char* in_name, - "", // const char* in_lastname, - 0, // int32 in_cur_hp, - 0, // int32 in_max_hp, - client->GetGender(), // uint8 in_gender, - client->GetRace(), // uint16 in_race, - client->GetClass(), // uint8 in_class, - BT_Humanoid, // bodyType in_bodytype, - client->GetDeity(), // uint8 in_deity, - client->GetLevel(), // uint8 in_level, - 0, // uint32 in_npctype_id, - client->GetSize(), // float in_size, - 0, // float in_runspeed, - client->GetPosition(), - client->GetInnateLightType(), // uint8 in_light, - verified for client innate_light value - client->GetTexture(), // uint8 in_texture, - client->GetHelmTexture(), // uint8 in_helmtexture, - 0, // uint16 in_ac, - 0, // uint16 in_atk, - 0, // uint16 in_str, - 0, // uint16 in_sta, - 0, // uint16 in_dex, - 0, // uint16 in_agi, - 0, // uint16 in_int, - 0, // uint16 in_wis, - 0, // uint16 in_cha, - client->GetPP().haircolor, // uint8 in_haircolor, - client->GetPP().beardcolor, // uint8 in_beardcolor, - client->GetPP().eyecolor1, // uint8 in_eyecolor1, // the eyecolors always seem to be the same, maybe left and right eye? - client->GetPP().eyecolor2, // uint8 in_eyecolor2, - client->GetPP().hairstyle, // uint8 in_hairstyle, - client->GetPP().face, // uint8 in_luclinface, - client->GetPP().beard, // uint8 in_beard, - client->GetPP().drakkin_heritage, // uint32 in_drakkin_heritage, - client->GetPP().drakkin_tattoo, // uint32 in_drakkin_tattoo, - client->GetPP().drakkin_details, // uint32 in_drakkin_details, - EQ::TintProfile(), // uint32 in_armor_tint[_MaterialCount], - 0xff, // uint8 in_aa_title, - 0, // uint8 in_see_invis, // see through invis - 0, // uint8 in_see_invis_undead, // see through invis vs. undead - 0, // uint8 in_see_hide, - 0, // uint8 in_see_improved_hide, - 0, // int32 in_hp_regen, - 0, // int32 in_mana_regen, - 0, // uint8 in_qglobal, - 0, // uint8 in_maxlevel, - 0, // uint32 in_scalerate - 0, // uint8 in_armtexture, - 0, // uint8 in_bracertexture, - 0, // uint8 in_handtexture, - 0, // uint8 in_legtexture, - 0, // uint8 in_feettexture, - 0, // uint8 in_usemodel, - 0, // bool in_always_aggro, - 0 // Int32 in_heroic_strikethrough - ), + "Unnamed_Corpse", // in_name + "", // in_lastname + 0, // in_cur_hp + 0, // in_max_hp + client->GetGender(), // in_gender + client->GetRace(), // in_race + client->GetClass(), // in_class + BT_Humanoid, // in_bodytype + client->GetDeity(), // in_deity + client->GetLevel(), // in_level + 0, // in_npctype_id + client->GetSize(), // in_size + 0, // in_runspeed + client->GetPosition(), // position + client->GetInnateLightType(), // in_light + client->GetTexture(), // in_texture + client->GetHelmTexture(), // 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 + client->GetPP().haircolor, // in_haircolor + client->GetPP().beardcolor, // in_beardcolor + client->GetPP().eyecolor1, // in_eyecolor1 + client->GetPP().eyecolor2, // in_eyecolor2 + client->GetPP().hairstyle, // in_hairstyle + client->GetPP().face, // in_luclinface + client->GetPP().beard, // in_beard + client->GetPP().drakkin_heritage, // in_drakkin_heritage + client->GetPP().drakkin_tattoo, // in_drakkin_tattoo + client->GetPP().drakkin_details, // 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_aggro + 0, // in_heroic_strikethrough + false // in_keeps_sold_items +), corpse_decay_timer(RuleI(Character, CorpseDecayTimeMS)), corpse_rez_timer(RuleI(Character, CorpseResTimeMS)), corpse_delay_timer(RuleI(NPC, CorpseUnlockTimer)), corpse_graveyard_timer(RuleI(Zone, GraveyardTimeMS)), loot_cooldown_timer(10) { - int i; - PlayerProfile_Struct *pp = &client->GetPP(); EQ::ItemInstance *item = nullptr; - /* Check if Zone has Graveyard First */ - if(!zone->HasGraveyard()) { + if (!zone->HasGraveyard()) { corpse_graveyard_timer.Disable(); } - for (i = 0; i < MAX_LOOTERS; i++){ + for (int i = 0; i < MAX_LOOTERS; i++){ allowed_looters[i] = 0; } if (client->AutoConsentGroupEnabled()) { - Group* grp = client->GetGroup(); - consented_group_id = grp ? grp->GetID() : 0; + auto* g = client->GetGroup(); + consented_group_id = g ? g->GetID() : 0; } if (client->AutoConsentRaidEnabled()) { - Raid* raid = client->GetRaid(); - consented_raid_id = raid ? raid->GetID() : 0; + auto* r = client->GetRaid(); + consented_raid_id = r ? r->GetID() : 0; } consented_guild_id = client->AutoConsentGuildEnabled() ? client->GuildID() : 0; - is_corpse_changed = true; - rez_experience = in_rezexp; - can_corpse_be_rezzed = true; - is_player_corpse = true; - is_locked = false; - being_looted_by = 0xFFFFFFFF; - char_id = client->CharacterID(); - corpse_db_id = 0; - player_corpse_depop = false; - copper = 0; - silver = 0; - gold = 0; - platinum = 0; + is_corpse_changed = true; + rez_experience = in_rezexp; + can_corpse_be_rezzed = true; + is_player_corpse = true; + is_locked = false; + being_looted_by = 0xFFFFFFFF; + char_id = client->CharacterID(); + corpse_db_id = 0; + player_corpse_depop = false; + copper = 0; + silver = 0; + gold = 0; + platinum = 0; strcpy(corpse_name, pp->name); strcpy(name, pp->name); @@ -321,17 +384,22 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( SetPlayerKillItemID(0); /* Check Rule to see if we can leave corpses */ - if(!RuleB(Character, LeaveNakedCorpses) || + if ( + !RuleB(Character, LeaveNakedCorpses) || RuleB(Character, LeaveCorpses) && - GetLevel() >= RuleI(Character, DeathItemLossLevel)) { + GetLevel() >= RuleI(Character, DeathItemLossLevel) + ) { // cash // Let's not move the cash when 'RespawnFromHover = true' && 'client->GetClientVersion() < EQClientSoF' since the client doesn't. // (change to first client that supports 'death hover' mode, if not SoF.) - if (!RuleB(Character, RespawnFromHover) || client->ClientVersion() < EQ::versions::ClientVersion::SoF) { + if ( + !RuleB(Character, RespawnFromHover) || + client->ClientVersion() < EQ::versions::ClientVersion::SoF + ) { SetCash(pp->copper, pp->silver, pp->gold, pp->platinum); - pp->copper = 0; - pp->silver = 0; - pp->gold = 0; + pp->copper = 0; + pp->silver = 0; + pp->gold = 0; pp->platinum = 0; } @@ -346,12 +414,21 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( // ..then regress and process invslot::EQUIPMENT_BEGIN through invslot::EQUIPMENT_END... // without additional work to database loading of player corpses, this order is not // currently preserved and a re-work of this processing loop is not warranted. - for (i = EQ::invslot::POSSESSIONS_BEGIN; i <= EQ::invslot::POSSESSIONS_END; ++i) { + for (int i = EQ::invslot::POSSESSIONS_BEGIN; i <= EQ::invslot::POSSESSIONS_END; ++i) { item = client->GetInv().GetItem(i); - if (item == nullptr) { continue; } + if (!item) { + continue; + } - if(!client->IsBecomeNPC() || (client->IsBecomeNPC() && !item->GetItem()->NoRent)) + if ( + !client->IsBecomeNPC() || + ( + client->IsBecomeNPC() && + !item->GetItem()->NoRent + ) + ) { MoveItemToCorpse(client, item, i, removed_list); + } } database.TransactionBegin(); @@ -393,7 +470,7 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( UpdateActiveLight(); return; - } //end "not leaving naked corpses" + } UpdateEquipmentLight(); UpdateActiveLight(); @@ -450,73 +527,75 @@ void Corpse::MoveItemToCorpse(Client *client, EQ::ItemInstance *inst, int16 equi } // To be called from LoadFromDBData -Corpse::Corpse(uint32 in_dbid, uint32 in_charid, const char* in_charname, ItemList* in_itemlist, uint32 in_copper, uint32 in_silver, uint32 in_gold, uint32 in_plat, const glm::vec4& position, float in_size, uint8 in_gender, uint16 in_race, uint8 in_class, uint8 in_deity, uint8 in_level, uint8 in_texture, uint8 in_helmtexture,uint32 in_rezexp, bool wasAtGraveyard) -: Mob("Unnamed_Corpse", -"", -0, -0, -in_gender, -in_race, -in_class, -BT_Humanoid, -in_deity, -in_level, -0, -in_size, -0, -position, -0, // verified for client innate_light value -in_texture, -in_helmtexture, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -EQ::TintProfile(), -0xff, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -false), +Corpse::Corpse(uint32 in_dbid, uint32 in_charid, const char* in_charname, ItemList* in_itemlist, uint32 in_copper, uint32 in_silver, uint32 in_gold, uint32 in_plat, const glm::vec4& position, float in_size, uint8 in_gender, uint16 in_race, uint8 in_class, uint8 in_deity, uint8 in_level, uint8 in_texture, uint8 in_helmtexture,uint32 in_rezexp, bool wasAtGraveyard) : Mob( + "Unnamed_Corpse", // in_name + "", // in_lastname + 0, // in_cur_hp + 0, // in_max_hp + in_gender, // in_gender + in_race, // in_race + in_class, // in_class + BT_Humanoid, // in_bodytype + in_deity, // in_deity + in_level, // in_level + 0, // in_npctype_id + in_size, // in_size + 0.0f, // in_runspeed + position, // position + 0, // in_light + in_texture, // in_texture + in_helmtexture, // 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 +), corpse_decay_timer(RuleI(Character, CorpseDecayTimeMS)), corpse_rez_timer(RuleI(Character, CorpseResTimeMS)), corpse_delay_timer(RuleI(NPC, CorpseUnlockTimer)), corpse_graveyard_timer(RuleI(Zone, GraveyardTimeMS)), loot_cooldown_timer(10) { - LoadPlayerCorpseDecayTime(in_dbid); - if (!zone->HasGraveyard() || wasAtGraveyard) + if (!zone->HasGraveyard() || wasAtGraveyard) { corpse_graveyard_timer.Disable(); + } is_corpse_changed = false; is_player_corpse = true; @@ -541,6 +620,7 @@ false), for (int i = 0; i < MAX_LOOTERS; i++){ allowed_looters[i] = 0; } + SetPlayerKillItemID(0); UpdateEquipmentLight(); diff --git a/zone/encounter.cpp b/zone/encounter.cpp index 0508c5a87..f03909e2f 100644 --- a/zone/encounter.cpp +++ b/zone/encounter.cpp @@ -32,13 +32,64 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA class Zone; -Encounter::Encounter(const char* enc_name) - :Mob - ( - nullptr, nullptr, 0, 0, 0, INVISIBLE_MAN, 0, BT_NoTarget, 0, 0, 0, 0, 0, glm::vec4(0,0,0,0), 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, EQ::TintProfile(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false - ) -{ +Encounter::Encounter(const char *enc_name) : Mob( + nullptr, // in_name + nullptr, // in_lastname + 0, // in_cur_hp + 0, // in_max_hp + MALE, // in_gender + INVISIBLE_MAN, // in_race + 0, // in_class + BT_NoTarget, // in_bodytype + 0, // in_deity + 0, // in_level + 0, // in_npcype_id + 0, // in_size + 0, // in_runspeed + glm::vec4(0, 0, 0, 0), // position + 0, // in_light + 0, // in_texture + 0, // 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 + 0, // 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 +) { encounter_name[0] = 0; strn0cpy(encounter_name, enc_name, 64); remove_me = false; diff --git a/zone/gm_commands/modifynpcstat.cpp b/zone/gm_commands/modifynpcstat.cpp index 8961eb489..75047caf9 100755 --- a/zone/gm_commands/modifynpcstat.cpp +++ b/zone/gm_commands/modifynpcstat.cpp @@ -8,7 +8,7 @@ void command_modifynpcstat(Client *c, const Seperator *sep) ListModifyNPCStatMap(c); return; } - + if (!c->GetTarget() || !c->GetTarget()->IsNPC()) { c->Message(Chat::White, "You must target an NPC to use this command."); return; @@ -76,6 +76,7 @@ std::map GetModifyNPCStatMap() { "hp_regen_per_second", "HP Regen Per Second" }, { "int", "Intelligence" }, { "_int", "Intelligence" }, + { "keeps_sold_items", "Keeps Sold Items" }, { "level", "Level" }, { "loottable_id", "Loottable ID" }, { "mana_regen", "Mana Regen" }, diff --git a/zone/gm_commands/npcedit.cpp b/zone/gm_commands/npcedit.cpp index 0ff5a17dc..ddabd6380 100755 --- a/zone/gm_commands/npcedit.cpp +++ b/zone/gm_commands/npcedit.cpp @@ -1491,6 +1491,22 @@ void command_npcedit(Client *c, const Seperator *sep) ); return; } + } else if (!strcasecmp(sep->arg[1], "keeps_sold_items")) { + if (sep->IsNumber(2)) { + auto keeps_sold_items = static_cast(std::stoul(sep->arg[2])); + n.keeps_sold_items = keeps_sold_items; + d = fmt::format( + "{} will {} Keep Sold Items.", + npc_id_string, + keeps_sold_items ? "now" : "no longer" + ); + } else { + c->Message( + Chat::White, + "Usage: #npcedit keeps_sold_items [Flag] - Sets an NPC's Keeps Sold Items Flag [0 = False, 1 = True]" + ); + return; + } } else if (!strcasecmp(sep->arg[1], "setanimation")) { if (sep->IsNumber(2)) { auto animation_id = std::stoul(sep->arg[2]); @@ -1760,6 +1776,10 @@ void SendNPCEditSubCommands(Client *c) Chat::White, "Usage: #npcedit exp_mod [Modifier] - Sets an NPC's Experience Modifier [50 = 50%, 100 = 100%, 200 = 200%]" ); + c->Message( + Chat::White, + "Usage: #npcedit keeps_sold_items [Flag] - Sets an NPC's Keeps Sold Items Flag [0 = False, 1 = True]" + ); c->Message( Chat::White, "Usage: #npcedit setanimation [Animation ID] - Sets an NPC's Animation on Spawn (Stored in spawn2 table)" diff --git a/zone/lua_npc.cpp b/zone/lua_npc.cpp index 2dc28013f..8e1ac586f 100644 --- a/zone/lua_npc.cpp +++ b/zone/lua_npc.cpp @@ -691,6 +691,16 @@ void Lua_NPC::SendPayload(int payload_id, std::string payload_value) { self->SendPayload(payload_id, payload_value); } +bool Lua_NPC::GetKeepsSoldItems() { + Lua_Safe_Call_Bool(); + return self->GetKeepsSoldItems(); +} + +void Lua_NPC::SetKeepsSoldItems(bool keeps_sold_items) { + Lua_Safe_Call_Void(); + self->SetKeepsSoldItems(keeps_sold_items); +} + luabind::scope lua_register_npc() { return luabind::class_("NPC") .def(luabind::constructor<>()) @@ -736,6 +746,7 @@ luabind::scope lua_register_npc() { .def("GetGuardPointZ", (float(Lua_NPC::*)(void))&Lua_NPC::GetGuardPointZ) .def("GetHealScale", (float(Lua_NPC::*)(void))&Lua_NPC::GetHealScale) .def("GetItemIDBySlot", (uint32(Lua_NPC::*)(uint16))&Lua_NPC::GetItemIDBySlot) + .def("GetKeepsSoldItems", (bool(Lua_NPC::*)(void))&Lua_NPC::GetKeepsSoldItems) .def("GetLootList", (Lua_NPC_Loot_List(Lua_NPC::*)(lua_State* L))&Lua_NPC::GetLootList) .def("GetLoottableID", (int(Lua_NPC::*)(void))&Lua_NPC::GetLoottableID) .def("GetMaxDMG", (uint32(Lua_NPC::*)(void))&Lua_NPC::GetMaxDMG) @@ -805,6 +816,7 @@ luabind::scope lua_register_npc() { .def("SetFollowID", (void(Lua_NPC::*)(int))&Lua_NPC::SetFollowID) .def("SetGold", (void(Lua_NPC::*)(uint32))&Lua_NPC::SetGold) .def("SetGrid", (void(Lua_NPC::*)(int))&Lua_NPC::SetGrid) + .def("SetKeepsSoldItems", (void(Lua_NPC::*)(bool))&Lua_NPC::SetKeepsSoldItems) .def("SetNPCFactionID", (void(Lua_NPC::*)(int))&Lua_NPC::SetNPCFactionID) .def("SetPetSpellID", (void(Lua_NPC::*)(int))&Lua_NPC::SetPetSpellID) .def("SetPlatinum", (void(Lua_NPC::*)(uint32))&Lua_NPC::SetPlatinum) diff --git a/zone/lua_npc.h b/zone/lua_npc.h index 7b7eda13c..ad42c5cee 100644 --- a/zone/lua_npc.h +++ b/zone/lua_npc.h @@ -159,6 +159,8 @@ public: float GetNPCStat(std::string stat); void SendPayload(int payload_id); void SendPayload(int payload_id, std::string payload_value); + bool GetKeepsSoldItems(); + void SetKeepsSoldItems(bool keeps_sold_items); }; #endif diff --git a/zone/mob.cpp b/zone/mob.cpp index 2f80bb4be..c192a54b6 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -98,6 +98,7 @@ Mob::Mob( uint16 in_usemodel, bool in_always_aggro, int32 in_heroic_strikethrough, + bool in_keeps_sold_items, int64 in_hp_regen_per_second ) : attack_timer(2000), @@ -252,39 +253,40 @@ Mob::Mob( aa_title = 0xFF; } - AC = in_ac; - ATK = in_atk; - STR = in_str; - STA = in_sta; - DEX = in_dex; - AGI = in_agi; - INT = in_int; - WIS = in_wis; - CHA = in_cha; - MR = CR = FR = DR = PR = Corrup = PhR = 0; - ExtraHaste = 0; - bEnraged = false; - current_mana = 0; - max_mana = 0; - hp_regen = in_hp_regen; - hp_regen_per_second = in_hp_regen_per_second; - mana_regen = in_mana_regen; - ooc_regen = RuleI(NPC, OOCRegen); //default Out of Combat Regen - maxlevel = in_maxlevel; - scalerate = in_scalerate; - invisible = 0; - invisible_undead = 0; - invisible_animals = 0; - sneaking = false; - hidden = false; - improved_hidden = false; - invulnerable = false; - IsFullHP = (current_hp == max_hp); - qglobal = 0; - spawned = false; - rare_spawn = false; - always_aggro = in_always_aggro; + AC = in_ac; + ATK = in_atk; + STR = in_str; + STA = in_sta; + DEX = in_dex; + AGI = in_agi; + INT = in_int; + WIS = in_wis; + CHA = in_cha; + MR = CR = FR = DR = PR = Corrup = PhR = 0; + ExtraHaste = 0; + bEnraged = false; + current_mana = 0; + max_mana = 0; + hp_regen = in_hp_regen; + hp_regen_per_second = in_hp_regen_per_second; + mana_regen = in_mana_regen; + ooc_regen = RuleI(NPC, OOCRegen); //default Out of Combat Regen + maxlevel = in_maxlevel; + scalerate = in_scalerate; + invisible = 0; + invisible_undead = 0; + invisible_animals = 0; + sneaking = false; + hidden = false; + improved_hidden = false; + invulnerable = false; + IsFullHP = (current_hp == max_hp); + qglobal = 0; + spawned = false; + rare_spawn = false; + always_aggro = in_always_aggro; heroic_strikethrough = in_heroic_strikethrough; + keeps_sold_items = in_keeps_sold_items; InitializeBuffSlots(); diff --git a/zone/mob.h b/zone/mob.h index 28ff9640a..fe6f1da13 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -165,6 +165,7 @@ public: uint16 in_usemodel, bool in_always_aggros_foes, int32 in_heroic_strikethrough, + bool keeps_sold_items, int64 in_hp_regen_per_second = 0 ); virtual ~Mob(); @@ -653,6 +654,8 @@ public: bool IsControllableBoat() const; inline const bool AlwaysAggro() const { return always_aggro; } inline int32 GetHeroicStrikethrough() const { return heroic_strikethrough; } + inline const bool GetKeepsSoldItems() const { return keeps_sold_items; } + inline void SetKeepsSoldItems(bool in_keeps_sold_items) { keeps_sold_items = in_keeps_sold_items; } void CopyHateList(Mob* to); @@ -1531,6 +1534,7 @@ protected: bool no_target_hotkey; bool rare_spawn; int32 heroic_strikethrough; + bool keeps_sold_items; uint32 m_PlayerState; uint32 GetPlayerState() { return m_PlayerState; } diff --git a/zone/npc.cpp b/zone/npc.cpp index 0d4eec93f..7995ed5f3 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -121,7 +121,8 @@ NPC::NPC(const NPCType *npc_type_data, Spawn2 *in_respawn, const glm::vec4 &posi npc_type_data->use_model, npc_type_data->always_aggro, npc_type_data->hp_regen_per_second, - npc_type_data->heroic_strikethrough + npc_type_data->heroic_strikethrough, + npc_type_data->keeps_sold_items ), attacked_timer(CombatEventTimer_expire), swarm_timer(100), @@ -210,12 +211,13 @@ NPC::NPC(const NPCType *npc_type_data, Spawn2 *in_respawn, const glm::vec4 &posi LevelScale(); } - base_damage = round((max_dmg - min_dmg) / 1.9); - min_damage = min_dmg - round(base_damage / 10.0); - accuracy_rating = npc_type_data->accuracy_rating; - avoidance_rating = npc_type_data->avoidance_rating; - ATK = npc_type_data->ATK; + base_damage = round((max_dmg - min_dmg) / 1.9); + min_damage = min_dmg - round(base_damage / 10.0); + accuracy_rating = npc_type_data->accuracy_rating; + avoidance_rating = npc_type_data->avoidance_rating; + ATK = npc_type_data->ATK; heroic_strikethrough = npc_type_data->heroic_strikethrough; + keeps_sold_items = npc_type_data->keeps_sold_items; // used for when switch back to charm default_ac = npc_type_data->AC; @@ -2672,6 +2674,10 @@ void NPC::ModifyNPCStat(std::string stat, std::string value) heroic_strikethrough = atoi(value.c_str()); return; } + else if (stat_lower == "keeps_sold_items") { + SetKeepsSoldItems(Strings::ToBool(value)); + return; + } } float NPC::GetNPCStat(std::string stat) @@ -2813,6 +2819,9 @@ float NPC::GetNPCStat(std::string stat) else if (stat_lower == "heroic_strikethrough") { return heroic_strikethrough; } + else if (stat_lower == "keeps_sold_items") { + return keeps_sold_items; + } //default values else if (stat_lower == "default_ac") { return default_ac; diff --git a/zone/perl_npc.cpp b/zone/perl_npc.cpp index efccaa173..a5fc52d12 100644 --- a/zone/perl_npc.cpp +++ b/zone/perl_npc.cpp @@ -680,6 +680,16 @@ void Perl_NPC_SendPayload(NPC* self, int payload_id, std::string payload_value) self->SendPayload(payload_id, payload_value); } +bool Perl_NPC_GetKeepsSoldItems(NPC* self) +{ + return self->GetKeepsSoldItems(); +} + +void Perl_NPC_SetKeepsSoldItems(NPC* self, bool keeps_sold_items) +{ + self->SetKeepsSoldItems(keeps_sold_items); +} + void perl_register_npc() { perl::interpreter perl(PERL_GET_THX); @@ -731,6 +741,7 @@ void perl_register_npc() package.add("GetGuardPointZ", &Perl_NPC_GetGuardPointZ); package.add("GetHealScale", &Perl_NPC_GetHealScale); package.add("GetItemIDBySlot", &Perl_NPC_GetItemIDBySlot); + package.add("GetKeepsSoldItems", &Perl_NPC_GetKeepsSoldItems); package.add("GetLootList", &Perl_NPC_GetLootList); package.add("GetLoottableID", &Perl_NPC_GetLoottableID); package.add("GetMaxDMG", &Perl_NPC_GetMaxDMG); @@ -799,6 +810,7 @@ void perl_register_npc() package.add("SendPayload", (void(*)(NPC*, int))&Perl_NPC_SendPayload); package.add("SendPayload", (void(*)(NPC*, int, std::string))&Perl_NPC_SendPayload); package.add("SetCopper", &Perl_NPC_SetCopper); + package.add("SetKeepsSoldItems", &Perl_NPC_SetKeepsSoldItems); package.add("SetGold", &Perl_NPC_SetGold); package.add("SetGrid", &Perl_NPC_SetGrid); package.add("SetNPCFactionID", &Perl_NPC_SetNPCFactionID); diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 398f6be7f..3ab638f7b 100755 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -2134,6 +2134,7 @@ const NPCType *ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load t->hp_regen_per_second = n.hp_regen_per_second; t->heroic_strikethrough = n.heroic_strikethrough; t->faction_amount = n.faction_amount; + t->keeps_sold_items = n.keeps_sold_items; // If NPC with duplicate NPC id already in table, // free item we attempted to add. diff --git a/zone/zonedump.h b/zone/zonedump.h index d5abaf475..51b21ee31 100644 --- a/zone/zonedump.h +++ b/zone/zonedump.h @@ -34,124 +34,125 @@ spawn2 mediumblob, npcs mediumblob, npc_loot mediumblob, gmspawntype mediumblob, struct NPCType { - char name[64]; - char lastname[64]; - int64 current_hp; - int64 max_hp; - float size; - float runspeed; - uint8 gender; - uint16 race; - uint8 class_; - uint8 bodytype; // added for targettype support - uint32 deity; //not loaded from DB - uint8 level; - uint32 npc_id; - uint8 texture; - uint8 helmtexture; - uint32 herosforgemodel; - uint32 loottable_id; - uint32 npc_spells_id; - uint32 npc_spells_effects_id; - int32 npc_faction_id; - int32 faction_amount; // faction association magnitude, will use primary faction - uint32 merchanttype; - uint32 alt_currency_type; - uint32 adventure_template; - uint32 trap_template; - uint8 light; - uint32 AC; - uint64 Mana; //not loaded from DB - uint32 ATK; //not loaded from DB - uint32 STR; - uint32 STA; - uint32 DEX; - uint32 AGI; - uint32 INT; - uint32 WIS; - uint32 CHA; - int32 MR; - int32 FR; - int32 CR; - int32 PR; - int32 DR; - int32 Corrup; - int32 PhR; - uint8 haircolor; - uint8 beardcolor; - uint8 eyecolor1; // the eyecolors always seem to be the same, maybe left and right eye? - uint8 eyecolor2; - uint8 hairstyle; - uint8 luclinface; // - uint8 beard; // - uint32 drakkin_heritage; - uint32 drakkin_tattoo; - uint32 drakkin_details; - EQ::TintProfile armor_tint; - uint32 min_dmg; - uint32 max_dmg; - uint32 charm_ac; - uint32 charm_min_dmg; - uint32 charm_max_dmg; - int charm_attack_delay; - int charm_accuracy_rating; - int charm_avoidance_rating; - int charm_atk; - int16 attack_count; - char special_abilities[512]; - uint16 d_melee_texture1; - uint16 d_melee_texture2; - char ammo_idfile[30]; - uint8 prim_melee_type; - uint8 sec_melee_type; - uint8 ranged_type; - int64 hp_regen; - int64 hp_regen_per_second; - int64 mana_regen; - int32 aggroradius; // added for AI improvement - neotokyo - int32 assistradius; // assist radius, defaults to aggroradis if not set - uint16 see_invis; // See Invis flag added - uint16 see_invis_undead; // See Invis vs. Undead flag added - bool see_hide; - bool see_improved_hide; - bool qglobal; - bool npc_aggro; - uint8 spawn_limit; //only this many may be in zone at a time (0=no limit) - uint8 mount_color; //only used by horse class - float attack_speed; //%+- on attack delay of the mob. - int attack_delay; //delay between attacks in ms - int accuracy_rating; // flat bonus before mods - int avoidance_rating; // flat bonus before mods - bool findable; //can be found with find command - bool trackable; - int16 slow_mitigation; - uint8 maxlevel; - uint32 scalerate; - bool private_corpse; - bool unique_spawn_by_name; - bool underwater; - uint32 emoteid; - float spellscale; - float healscale; - bool no_target_hotkey; - bool raid_target; - uint8 armtexture; - uint8 bracertexture; - uint8 handtexture; - uint8 legtexture; - uint8 feettexture; - bool ignore_despawn; - bool show_name; // should default on - bool untargetable; - bool skip_global_loot; - bool rare_spawn; - bool skip_auto_scale; // just so it doesn't mess up bots or mercs, probably should add to DB too just in case - int8 stuck_behavior; - uint16 use_model; - int8 flymode; - bool always_aggro; - int exp_mod; - int heroic_strikethrough; + char name[64]; + char lastname[64]; + int64 current_hp; + int64 max_hp; + float size; + float runspeed; + uint8 gender; + uint16 race; + uint8 class_; + uint8 bodytype; // added for targettype support + uint32 deity; //not loaded from DB + uint8 level; + uint32 npc_id; + uint8 texture; + uint8 helmtexture; + uint32 herosforgemodel; + uint32 loottable_id; + uint32 npc_spells_id; + uint32 npc_spells_effects_id; + int32 npc_faction_id; + int32 faction_amount; // faction association magnitude, will use primary faction + uint32 merchanttype; + uint32 alt_currency_type; + uint32 adventure_template; + uint32 trap_template; + uint8 light; + uint32 AC; + uint64 Mana; //not loaded from DB + uint32 ATK; //not loaded from DB + uint32 STR; + uint32 STA; + uint32 DEX; + uint32 AGI; + uint32 INT; + uint32 WIS; + uint32 CHA; + int32 MR; + int32 FR; + int32 CR; + int32 PR; + int32 DR; + int32 Corrup; + int32 PhR; + uint8 haircolor; + uint8 beardcolor; + uint8 eyecolor1; // the eyecolors always seem to be the same, maybe left and right eye? + uint8 eyecolor2; + uint8 hairstyle; + uint8 luclinface; // + uint8 beard; // + uint32 drakkin_heritage; + uint32 drakkin_tattoo; + uint32 drakkin_details; + EQ::TintProfile armor_tint; + uint32 min_dmg; + uint32 max_dmg; + uint32 charm_ac; + uint32 charm_min_dmg; + uint32 charm_max_dmg; + int charm_attack_delay; + int charm_accuracy_rating; + int charm_avoidance_rating; + int charm_atk; + int16 attack_count; + char special_abilities[512]; + uint16 d_melee_texture1; + uint16 d_melee_texture2; + char ammo_idfile[30]; + uint8 prim_melee_type; + uint8 sec_melee_type; + uint8 ranged_type; + int64 hp_regen; + int64 hp_regen_per_second; + int64 mana_regen; + int32 aggroradius; // added for AI improvement - neotokyo + int32 assistradius; // assist radius, defaults to aggroradis if not set + uint16 see_invis; // See Invis flag added + uint16 see_invis_undead; // See Invis vs. Undead flag added + bool see_hide; + bool see_improved_hide; + bool qglobal; + bool npc_aggro; + uint8 spawn_limit; //only this many may be in zone at a time (0=no limit) + uint8 mount_color; //only used by horse class + float attack_speed; //%+- on attack delay of the mob. + int attack_delay; //delay between attacks in ms + int accuracy_rating; // flat bonus before mods + int avoidance_rating; // flat bonus before mods + bool findable; //can be found with find command + bool trackable; + int16 slow_mitigation; + uint8 maxlevel; + uint32 scalerate; + bool private_corpse; + bool unique_spawn_by_name; + bool underwater; + uint32 emoteid; + float spellscale; + float healscale; + bool no_target_hotkey; + bool raid_target; + uint8 armtexture; + uint8 bracertexture; + uint8 handtexture; + uint8 legtexture; + uint8 feettexture; + bool ignore_despawn; + bool show_name; // should default on + bool untargetable; + bool skip_global_loot; + bool rare_spawn; + bool skip_auto_scale; // just so it doesn't mess up bots or mercs, probably should add to DB too just in case + int8 stuck_behavior; + uint16 use_model; + int8 flymode; + bool always_aggro; + int exp_mod; + int heroic_strikethrough; + bool keeps_sold_items; }; namespace player_lootitem {