mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-16 22:58:34 +00:00
[Feature] Add Parcel Feature for RoF2 Clients (#4198)
* Add Parcel Feature Add the parcel system for RoF2 client * Fixed a duplicate define * Reformat reformating and review changes * Further Formatting * Memory Mgmt Updates Refactored to using unique_ptr/make_unique/etc to avoid manual memory mgmt. Other format changes * Refactor db structure Refactor for db structure of parcels to character_parcels Removal of parcel_merchants Addition of npc_types.is_parcel_merchant Cleanup as a result * Refactor to use item id 99990 for money transfers. Removed the money string function as a result, though simplified the messaging related to money. Other updates based on feedback. * Move prune routine out of scheduler and into a world process. Removed RuleI from #define * Update * Update database.cpp * Update database_update_manifest.cpp * Update main.cpp * Update client_process.cpp * Update parcels.cpp * Remove parcel merchant content to optional sql instead of manifest. --------- Co-authored-by: Akkadius <akkadius1@gmail.com>
This commit is contained in:
+115
-43
@@ -69,6 +69,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "../common/events/player_event_logs.h"
|
||||
#include "../common/repositories/character_stats_record_repository.h"
|
||||
#include "dialogue_window.h"
|
||||
#include "../common/rulesys.h"
|
||||
|
||||
extern QueryServ* QServ;
|
||||
extern Zone* zone;
|
||||
@@ -321,6 +322,8 @@ void MapOpcodes()
|
||||
ConnectedOpcodes[OP_OpenGuildTributeMaster] = &Client::Handle_OP_OpenGuildTributeMaster;
|
||||
ConnectedOpcodes[OP_OpenInventory] = &Client::Handle_OP_OpenInventory;
|
||||
ConnectedOpcodes[OP_OpenTributeMaster] = &Client::Handle_OP_OpenTributeMaster;
|
||||
ConnectedOpcodes[OP_ShopSendParcel] = &Client::Handle_OP_ShopSendParcel;
|
||||
ConnectedOpcodes[OP_ShopRetrieveParcel] = &Client::Handle_OP_ShopRetrieveParcel;
|
||||
ConnectedOpcodes[OP_PDeletePetition] = &Client::Handle_OP_PDeletePetition;
|
||||
ConnectedOpcodes[OP_PetCommands] = &Client::Handle_OP_PetCommands;
|
||||
ConnectedOpcodes[OP_Petition] = &Client::Handle_OP_Petition;
|
||||
@@ -818,6 +821,10 @@ void Client::CompleteConnect()
|
||||
);
|
||||
}
|
||||
|
||||
if(ClientVersion() == EQ::versions::ClientVersion::RoF2 && RuleB(Parcel, EnableParcelMerchants)) {
|
||||
SendParcelStatus();
|
||||
}
|
||||
|
||||
if (zone && zone->GetInstanceTimer()) {
|
||||
bool is_permanent = false;
|
||||
uint32 remaining_time = database.GetTimeRemainingInstance(zone->GetInstanceID(), is_permanent);
|
||||
@@ -4271,6 +4278,12 @@ void Client::Handle_OP_Bug(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_OP_Camp(const EQApplicationPacket *app)
|
||||
{
|
||||
if (ClientVersion() == EQ::versions::ClientVersion::RoF2 && RuleB(Parcel, EnableParcelMerchants) && GetEngagedWithParcelMerchant()) {
|
||||
Stand();
|
||||
MessageString(Chat::Yellow, TRADER_BUSY_TWO);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsLFP())
|
||||
worldserver.StopLFP(CharacterID());
|
||||
|
||||
@@ -4324,6 +4337,12 @@ void Client::Handle_OP_CancelTrade(const EQApplicationPacket *app)
|
||||
FinishTrade(this);
|
||||
trade->Reset();
|
||||
}
|
||||
|
||||
if (ClientVersion() == EQ::versions::ClientVersion::RoF2 && RuleB(Parcel, EnableParcelMerchants)) {
|
||||
DoParcelCancel();
|
||||
SetEngagedWithParcelMerchant(false);
|
||||
}
|
||||
|
||||
EQApplicationPacket end_trade1(OP_FinishWindow, 0);
|
||||
QueuePacket(&end_trade1);
|
||||
|
||||
@@ -13877,6 +13896,11 @@ void Client::Handle_OP_Shielding(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_OP_ShopEnd(const EQApplicationPacket *app)
|
||||
{
|
||||
if (ClientVersion() == EQ::versions::ClientVersion::RoF2 && RuleB(Parcel, EnableParcelMerchants)) {
|
||||
DoParcelCancel();
|
||||
SetEngagedWithParcelMerchant(false);
|
||||
}
|
||||
|
||||
EQApplicationPacket empty(OP_ShopEndConfirm);
|
||||
QueuePacket(&empty);
|
||||
return;
|
||||
@@ -14423,82 +14447,107 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_OP_ShopRequest(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size != sizeof(Merchant_Click_Struct)) {
|
||||
LogError("Wrong size: OP_ShopRequest, size=[{}], expected [{}]", app->size, sizeof(Merchant_Click_Struct));
|
||||
if (app->size != sizeof(MerchantClick_Struct)) {
|
||||
LogError("Wrong size: OP_ShopRequest, size=[{}], expected [{}]", app->size, sizeof(MerchantClick_Struct));
|
||||
return;
|
||||
}
|
||||
|
||||
Merchant_Click_Struct* mc = (Merchant_Click_Struct*)app->pBuffer;
|
||||
MerchantClick_Struct *mc = (MerchantClick_Struct *) app->pBuffer;
|
||||
|
||||
// Send back opcode OP_ShopRequest - tells client to open merchant window.
|
||||
//EQApplicationPacket* outapp = new EQApplicationPacket(OP_ShopRequest, sizeof(Merchant_Click_Struct));
|
||||
//Merchant_Click_Struct* mco=(Merchant_Click_Struct*)outapp->pBuffer;
|
||||
int merchantid = 0;
|
||||
Mob* tmp = entity_list.GetMob(mc->npcid);
|
||||
// EQApplicationPacket* outapp = new EQApplicationPacket(OP_ShopRequest, sizeof(Merchant_Click_Struct));
|
||||
// Merchant_Click_Struct* mco=(Merchant_Click_Struct*)outapp->pBuffer;
|
||||
int merchant_id = 0;
|
||||
int tabs_to_display = None;
|
||||
Mob *tmp = entity_list.GetMob(mc->npc_id);
|
||||
|
||||
if (tmp == 0 || !tmp->IsNPC() || tmp->GetClass() != Class::Merchant)
|
||||
if (tmp == 0 || !tmp->IsNPC() || tmp->GetClass() != Class::Merchant) {
|
||||
return;
|
||||
}
|
||||
|
||||
//you have to be somewhat close to them to be properly using them
|
||||
if (DistanceSquared(m_Position, tmp->GetPosition()) > USE_NPC_RANGE2)
|
||||
// you have to be somewhat close to them to be properly using them
|
||||
if (DistanceSquared(m_Position, tmp->GetPosition()) > USE_NPC_RANGE2) {
|
||||
return;
|
||||
}
|
||||
|
||||
merchantid = tmp->CastToNPC()->MerchantType;
|
||||
merchant_id = tmp->CastToNPC()->MerchantType;
|
||||
|
||||
if (ClientVersion() == EQ::versions::ClientVersion::RoF2 && tmp->CastToNPC()->GetParcelMerchant()) {
|
||||
tabs_to_display = SellBuyParcel;
|
||||
}
|
||||
else {
|
||||
tabs_to_display = SellBuy;
|
||||
}
|
||||
|
||||
int action = MerchantActions::Open;
|
||||
if (merchant_id == 0) {
|
||||
auto outapp = new EQApplicationPacket(OP_ShopRequest, sizeof(MerchantClick_Struct));
|
||||
auto mco = (MerchantClick_Struct *) outapp->pBuffer;
|
||||
mco->npc_id = mc->npc_id;
|
||||
mco->player_id = 0;
|
||||
mco->command = MerchantActions::Open;
|
||||
mco->rate = 1.0;
|
||||
mco->tab_display = tabs_to_display;
|
||||
|
||||
int action = 1;
|
||||
if (merchantid == 0) {
|
||||
auto outapp = new EQApplicationPacket(OP_ShopRequest, sizeof(Merchant_Click_Struct));
|
||||
Merchant_Click_Struct* mco = (Merchant_Click_Struct*)outapp->pBuffer;
|
||||
mco->npcid = mc->npcid;
|
||||
mco->playerid = 0;
|
||||
mco->command = 1; //open...
|
||||
mco->rate = 1.0;
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tmp->IsEngaged()) {
|
||||
MessageString(Chat::White, MERCHANT_BUSY);
|
||||
action = 0;
|
||||
}
|
||||
if (GetFeigned() || IsInvisible())
|
||||
{
|
||||
Message(Chat::White, "You cannot use a merchant right now.");
|
||||
action = 0;
|
||||
}
|
||||
int primaryfaction = tmp->CastToNPC()->GetPrimaryFaction();
|
||||
int factionlvl = GetFactionLevel(CharacterID(), tmp->CastToNPC()->GetNPCTypeID(), GetRace(), GetClass(), GetDeity(), primaryfaction, tmp);
|
||||
if (factionlvl >= 7) {
|
||||
MerchantRejectMessage(tmp, primaryfaction);
|
||||
action = 0;
|
||||
action = MerchantActions::Close;
|
||||
}
|
||||
|
||||
if (tmp->Charmed())
|
||||
action = 0;
|
||||
if (GetFeigned() || IsInvisible()) {
|
||||
Message(Chat::White, "You cannot use a merchant right now.");
|
||||
action = MerchantActions::Close;
|
||||
}
|
||||
|
||||
int primaryfaction = tmp->CastToNPC()->GetPrimaryFaction();
|
||||
int factionlvl = GetFactionLevel(
|
||||
CharacterID(), tmp->CastToNPC()->GetNPCTypeID(), GetRace(), GetClass(), GetDeity(),
|
||||
primaryfaction, tmp
|
||||
);
|
||||
if (factionlvl >= 7) {
|
||||
MerchantRejectMessage(tmp, primaryfaction);
|
||||
action = MerchantActions::Close;
|
||||
}
|
||||
|
||||
if (tmp->Charmed()) {
|
||||
action = MerchantActions::Close;
|
||||
}
|
||||
|
||||
if (!tmp->CastToNPC()->IsMerchantOpen()) {
|
||||
tmp->SayString(zone->random.Int(MERCHANT_CLOSED_ONE, MERCHANT_CLOSED_THREE));
|
||||
action = 0;
|
||||
action = MerchantActions::Close;
|
||||
}
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_ShopRequest, sizeof(Merchant_Click_Struct));
|
||||
Merchant_Click_Struct* mco = (Merchant_Click_Struct*)outapp->pBuffer;
|
||||
auto outapp = new EQApplicationPacket(OP_ShopRequest, sizeof(MerchantClick_Struct));
|
||||
auto mco = (MerchantClick_Struct *) outapp->pBuffer;
|
||||
|
||||
mco->npc_id = mc->npc_id;
|
||||
mco->player_id = 0;
|
||||
mco->command = action; // Merchant command 0x01 = open
|
||||
mco->tab_display = tabs_to_display;
|
||||
|
||||
mco->npcid = mc->npcid;
|
||||
mco->playerid = 0;
|
||||
mco->command = action; // Merchant command 0x01 = open
|
||||
if (RuleB(Merchant, UsePriceMod)) {
|
||||
mco->rate = 1 / ((RuleR(Merchant, BuyCostMod))*Client::CalcPriceMod(tmp, true)); // works
|
||||
mco->rate = 1 / ((RuleR(Merchant, BuyCostMod)) * Client::CalcPriceMod(tmp, true)); // works
|
||||
}
|
||||
else
|
||||
else {
|
||||
mco->rate = 1 / (RuleR(Merchant, BuyCostMod));
|
||||
}
|
||||
|
||||
outapp->priority = 6;
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
if (action == 1)
|
||||
BulkSendMerchantInventory(merchantid, tmp->GetNPCTypeID());
|
||||
if (action == MerchantActions::Open) {
|
||||
BulkSendMerchantInventory(merchant_id, tmp->GetNPCTypeID());
|
||||
if ((tabs_to_display & Parcel) == Parcel) {
|
||||
SendBulkParcels();
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -17162,3 +17211,26 @@ void Client::Handle_OP_GuildTributeDonatePlat(const EQApplicationPacket *app)
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Handle_OP_ShopSendParcel(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size != sizeof(Parcel_Struct)) {
|
||||
LogError("Received Handle_OP_ShopSendParcel packet. Expected size {}, received size {}.", sizeof(Parcel_Struct),
|
||||
app->size);
|
||||
return;
|
||||
}
|
||||
|
||||
auto parcel_in = (Parcel_Struct *)app->pBuffer;
|
||||
DoParcelSend(parcel_in);
|
||||
}
|
||||
|
||||
void Client::Handle_OP_ShopRetrieveParcel(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size != sizeof(ParcelRetrieve_Struct)) {
|
||||
LogError("Received Handle_OP_ShopRetrieveParcel packet. Expected size {}, received size {}.",
|
||||
sizeof(ParcelRetrieve_Struct), app->size);
|
||||
return;
|
||||
}
|
||||
|
||||
auto parcel_in = (ParcelRetrieve_Struct *)app->pBuffer;
|
||||
DoParcelRetrieve(*parcel_in);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user