diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index aab82e4f7..d2fbcbb76 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -3468,6 +3468,7 @@ struct MerchantList { int8 level_required; uint16 alt_currency_cost; uint32 classes_required; + uint8 probability; }; struct TempMerchantList { diff --git a/utils/sql/git/required/2014_08_20_merchantlist_probability.sql b/utils/sql/git/required/2014_08_20_merchantlist_probability.sql new file mode 100644 index 000000000..9ceedbb30 --- /dev/null +++ b/utils/sql/git/required/2014_08_20_merchantlist_probability.sql @@ -0,0 +1 @@ +ALTER TABLE `merchantlist` ADD `probability` INT(3) NOT NULL DEFAULT '100' AFTER `classes_required`; \ No newline at end of file diff --git a/zone/client_process.cpp b/zone/client_process.cpp index 6045881e1..acdf67be8 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -983,17 +983,18 @@ void Client::BulkSendMerchantInventory(int merchant_id, int npcid) { uint8 handychance = 0; for (itr = merlist.begin(); itr != merlist.end() && i < numItemSlots; ++itr) { MerchantList ml = *itr; - if(GetLevel() < ml.level_required) { + if (merch->CastToNPC()->GetMerchantProbability() > ml.probability) + continue; + + if(GetLevel() < ml.level_required) continue; - } if (!(ml.classes_required & (1 << (GetClass() - 1)))) continue; int32 fac = merch ? merch->GetPrimaryFaction() : 0; - if(fac != 0 && GetModCharacterFactionLevel(fac) < ml.faction_required) { + if(fac != 0 && GetModCharacterFactionLevel(fac) < ml.faction_required) continue; - } handychance = MakeRandomInt(0, merlist.size() + tmp_merlist.size() - 1 ); diff --git a/zone/entity.cpp b/zone/entity.cpp index 5ff19847f..d904dbdfe 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -622,6 +622,7 @@ void EntityList::AddCorpse(Corpse *corpse, uint32 in_id) void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue) { npc->SetID(GetFreeID()); + npc->SetMerchantProbability((uint8) MakeRandomInt(0, 99)); parse->EventNPC(EVENT_SPAWN, npc, nullptr, "", 0); uint16 emoteid = npc->GetEmoteID(); diff --git a/zone/lua_npc.cpp b/zone/lua_npc.cpp index 41524af15..dabc1c46f 100644 --- a/zone/lua_npc.cpp +++ b/zone/lua_npc.cpp @@ -442,6 +442,15 @@ void Lua_NPC::MerchantCloseShop() { self->MerchantCloseShop(); } +void Lua_NPC::SetMerchantProbability(uint8 amt) { + Lua_Safe_Call_Void(); + self->SetMerchantProbability(amt); +} + +uint8 Lua_NPC::GetMerchantProbability() { + Lua_Safe_Call_Int(); + return self->GetMerchantProbability(); +} luabind::scope lua_register_npc() { return luabind::class_("NPC") @@ -532,7 +541,9 @@ luabind::scope lua_register_npc() { .def("GetSpawnKillCount", (int(Lua_NPC::*)(void))&Lua_NPC::GetSpawnKillCount) .def("GetScore", (int(Lua_NPC::*)(void))&Lua_NPC::GetScore) .def("MerchantOpenShop", (void(Lua_NPC::*)(void))&Lua_NPC::MerchantOpenShop) - .def("MerchantCloseShop", (void(Lua_NPC::*)(void))&Lua_NPC::MerchantCloseShop); + .def("MerchantCloseShop", (void(Lua_NPC::*)(void))&Lua_NPC::MerchantCloseShop) + .def("SetMerchantProbability", (void(Lua_NPC::*)(void))&Lua_NPC::SetMerchantProbability) + .def("GetMerchantProbability", (uint8(Lua_NPC::*)(void))&Lua_NPC::GetMerchantProbability); } #endif diff --git a/zone/lua_npc.h b/zone/lua_npc.h index 8c34ed17d..7db7f7e4b 100644 --- a/zone/lua_npc.h +++ b/zone/lua_npc.h @@ -114,6 +114,8 @@ public: int GetScore(); void MerchantOpenShop(); void MerchantCloseShop(); + void SetMerchantProbability(uint8 amt); + uint8 GetMerchantProbability(); }; #endif diff --git a/zone/npc.h b/zone/npc.h index 5c8fd43bb..34fcfcd0a 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -390,6 +390,8 @@ public: uint32 GetSpawnKillCount(); int GetScore(); + void SetMerchantProbability(uint8 amt) { probability = amt; } + uint8 GetMerchantProbability() { return probability; } void mod_prespawn(Spawn2 *sp); int mod_npc_damage(int damage, SkillUseTypes skillinuse, int hand, const Item_Struct* weapon, Mob* other); void mod_npc_killed_merit(Mob* c); @@ -504,6 +506,7 @@ protected: std::list mercDataList; bool raid_target; + uint8 probability; private: uint32 loottable_id; diff --git a/zone/perl_npc.cpp b/zone/perl_npc.cpp index 891709113..dcc66b886 100644 --- a/zone/perl_npc.cpp +++ b/zone/perl_npc.cpp @@ -2145,6 +2145,54 @@ XS(XS_NPC_GetScore) XSRETURN(1); } +XS(XS_NPC_SetMerchantProbability); +XS(XS_NPC_SetMerchantProbability) { + dXSARGS; + if (items != 2) + Perl_croak(aTHX_ "Usage: NPC::SetMerchantProbability(THIS, Probability)"); + { + NPC *THIS; + uint8 Probability = (uint8)SvIV(ST(1)); + + if (sv_derived_from(ST(0), "NPC")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(NPC *,tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type NPC"); + if(THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + THIS->SetMerchantProbability(Probability); + } + XSRETURN_EMPTY; +} + +XS(XS_NPC_GetMerchantProbability); +XS(XS_NPC_GetMerchantProbability) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: NPC::GetMerchantProbability(THIS)"); + { + NPC *THIS; + uint8 RETVAL; + dXSTARG; + + if (sv_derived_from(ST(0), "NPC")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(NPC *,tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type NPC"); + if(THIS == NULL) + Perl_croak(aTHX_ "THIS is NULL, avoiding crash."); + + RETVAL = THIS->GetMerchantProbability(); + XSprePUSH; PUSHu((UV)RETVAL); + } + XSRETURN(1); +} + #ifdef __cplusplus extern "C" #endif @@ -2243,6 +2291,8 @@ XS(boot_NPC) newXSproto(strcpy(buf, "GetAccuracyRating"), XS_NPC_GetAccuracyRating, file, "$"); newXSproto(strcpy(buf, "GetSpawnKillCount"), XS_NPC_GetSpawnKillCount, file, "$"); newXSproto(strcpy(buf, "GetScore"), XS_NPC_GetScore, file, "$"); + newXSproto(strcpy(buf, "SetMerchantProbability"), XS_NPC_SetMerchantProbability, file, "$$"); + newXSproto(strcpy(buf, "GetMerchantProbability"), XS_NPC_GetMerchantProbability, file, "$"); XSRETURN_YES; } diff --git a/zone/zone.cpp b/zone/zone.cpp index 4124ba7d3..d0d8efb2f 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -469,7 +469,7 @@ void Zone::LoadNewMerchantData(uint32 merchantid){ MYSQL_RES *result; MYSQL_ROW row; std::list merlist; - if (database.RunQuery(query, MakeAnyLenString(&query, "SELECT item, slot, faction_required, level_required, alt_currency_cost, classes_required FROM merchantlist WHERE merchantid=%d", merchantid), errbuf, &result)) { + if (database.RunQuery(query, MakeAnyLenString(&query, "SELECT item, slot, faction_required, level_required, alt_currency_cost, classes_required, probability FROM merchantlist WHERE merchantid=%d", merchantid), errbuf, &result)) { while((row = mysql_fetch_row(result))) { MerchantList ml; ml.id = merchantid; @@ -479,6 +479,7 @@ void Zone::LoadNewMerchantData(uint32 merchantid){ ml.level_required = atoul(row[3]); ml.alt_currency_cost = atoul(row[3]); ml.classes_required = atoul(row[4]); + ml.probability = atoul(row[5]); merlist.push_back(ml); } merchanttable[merchantid] = merlist; @@ -526,6 +527,7 @@ void Zone::LoadMerchantData_result(MYSQL_RES* result) { ml.level_required = atoul(row[4]); ml.alt_currency_cost = atoul(row[5]); ml.classes_required = atoul(row[6]); + ml.probability = atoul(row[7]); cur->second.push_back(ml); } } @@ -539,7 +541,7 @@ void Zone::GetMerchantDataForZoneLoad(){ workpt.b1() = DBA_b1_Zone_MerchantLists; DBAsyncWork* dbaw = new DBAsyncWork(&database, &MTdbafq, workpt, DBAsync::Read); dbaw->AddQuery(1, &query, MakeAnyLenString(&query, - "select ml.merchantid,ml.slot,ml.item,ml.faction_required,ml.level_required,ml.alt_currency_cost,ml.classes_required " + "select ml.merchantid,ml.slot,ml.item,ml.faction_required,ml.level_required,ml.alt_currency_cost,ml.classes_required,ml.probability " "from merchantlist ml, npc_types nt, spawnentry se, spawn2 s2 " "where nt.merchant_id=ml.merchantid and nt.id=se.npcid " "and se.spawngroupid=s2.spawngroupid and s2.zone='%s' and s2.version=%u " diff --git a/zone/zonedump.h b/zone/zonedump.h index 98841630a..052f7446d 100644 --- a/zone/zonedump.h +++ b/zone/zonedump.h @@ -126,6 +126,7 @@ struct NPCType float healscale; bool no_target_hotkey; bool raid_target; + uint8 probability; }; /*