Additional housing features (UI items panel)
Furthering issue #124 - spawn_instance_data now tracks unique item id - inside door widget now lists all items in the house, can move or pickup from UI - Support for examine item by unique item id in house instance
This commit is contained in:
parent
23898ae6d5
commit
313b060328
11 changed files with 239 additions and 31 deletions
|
@ -2721,9 +2721,61 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
|
|||
}
|
||||
break;
|
||||
}
|
||||
case COMMAND_MOVE_ITEM:
|
||||
{
|
||||
int32 id = 0;
|
||||
|
||||
if (sep->IsNumber(0))
|
||||
id = atoul(sep->arg[0]);
|
||||
|
||||
Spawn* spawn = 0;
|
||||
if (id == 0)
|
||||
{
|
||||
spawn = cmdTarget;
|
||||
}
|
||||
else
|
||||
spawn = client->GetCurrentZone()->GetSpawnFromUniqueItemID(id);
|
||||
|
||||
if (!spawn || !client->HasOwnerOrEditAccess() || !spawn->GetPickupItemID())
|
||||
break;
|
||||
|
||||
client->SendMoveObjectMode(spawn, 0);
|
||||
break;
|
||||
}
|
||||
case COMMAND_PICKUP:
|
||||
{
|
||||
int32 id = 0;
|
||||
if (sep->IsNumber(0))
|
||||
id = atoul(sep->arg[0]);
|
||||
|
||||
Spawn* spawn = 0;
|
||||
if (id == 0)
|
||||
{
|
||||
spawn = cmdTarget;
|
||||
}
|
||||
else
|
||||
spawn = client->GetCurrentZone()->GetSpawnFromUniqueItemID(id);
|
||||
|
||||
if (!spawn || !client->HasOwnerOrEditAccess() || !spawn->GetPickupItemID())
|
||||
break;
|
||||
|
||||
client->AddItem(spawn->GetPickupItemID(), 1);
|
||||
|
||||
Query query;
|
||||
query.RunQuery2(Q_INSERT, "delete from spawn_instance_data where spawn_id = %u and spawn_location_id = %u and pickup_item_id = %u", spawn->GetDatabaseID(), spawn->GetSpawnLocationID(), spawn->GetPickupItemID());
|
||||
|
||||
if (database.RemoveSpawnFromSpawnLocation(spawn)) {
|
||||
client->GetCurrentZone()->RemoveSpawn(false, spawn, true, true);
|
||||
}
|
||||
|
||||
// we had a UI Window displayed, update the house items
|
||||
if ( id > 0 )
|
||||
client->GetCurrentZone()->SendHouseItems(client);
|
||||
|
||||
break;
|
||||
}
|
||||
case COMMAND_HOUSE:
|
||||
{
|
||||
PrintSep(sep, "COMMAND_HOUSE");
|
||||
if (sep && sep->IsNumber(0))
|
||||
{
|
||||
int32 unique_id = atoi(sep->arg[0]);
|
||||
|
@ -2745,12 +2797,12 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
|
|||
hz = world.GetHouseZone(ph->house_id);
|
||||
|
||||
ClientPacketFunctions::SendBaseHouseWindow(client, hz, ph, client->GetPlayer()->GetID());
|
||||
client->GetCurrentZone()->SendHouseItems(client);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case COMMAND_HOUSE_UI:
|
||||
{
|
||||
PrintSep(sep, "COMMAND_HOUSEUI");
|
||||
if (sep && sep->IsNumber(0) && client->GetCurrentZone()->GetInstanceType() == Instance_Type::NONE)
|
||||
{
|
||||
int32 unique_id = atoi(sep->arg[0]);
|
||||
|
|
|
@ -878,6 +878,8 @@ private:
|
|||
#define COMMAND_GM 513
|
||||
#define COMMAND_HOUSE_UI 514
|
||||
#define COMMAND_HOUSE 515
|
||||
#define COMMAND_MOVE_ITEM 516
|
||||
#define COMMAND_PICKUP 517
|
||||
|
||||
#define GET_AA_XML 751
|
||||
#define ADD_AA 752
|
||||
|
|
|
@ -95,6 +95,7 @@ void ClientPacketFunctions::SendHousingList(Client* client) {
|
|||
packet->setArrayDataByName("unknown2", 1, i);
|
||||
}
|
||||
client->QueuePacket(packet->serialize());
|
||||
safe_delete(packet);
|
||||
}
|
||||
|
||||
void ClientPacketFunctions::SendBaseHouseWindow(Client* client, HouseZone* hz, PlayerHouse* ph, int32 spawnID) {
|
||||
|
|
|
@ -105,6 +105,7 @@ Spawn::Spawn(){
|
|||
MCommandMutex.SetName("Entity::MCommandMutex");
|
||||
has_spawn_proximities = false;
|
||||
pickup_item_id = 0;
|
||||
pickup_unique_item_id = 0;
|
||||
}
|
||||
|
||||
Spawn::~Spawn(){
|
||||
|
|
|
@ -1052,7 +1052,13 @@ public:
|
|||
pickup_item_id = itemid;
|
||||
}
|
||||
|
||||
void SetPickupUniqueItemID(int32 uniqueid)
|
||||
{
|
||||
pickup_unique_item_id = uniqueid;
|
||||
}
|
||||
|
||||
int32 GetPickupItemID() { return pickup_item_id; }
|
||||
int32 GetPickupUniqueItemID() { return pickup_unique_item_id; }
|
||||
protected:
|
||||
|
||||
bool send_spawn_changes;
|
||||
|
@ -1079,6 +1085,7 @@ protected:
|
|||
int8 merchant_type;
|
||||
int32 transporter_id;
|
||||
int32 pickup_item_id;
|
||||
int32 pickup_unique_item_id;
|
||||
map<int32, vector<int16>* > required_quests;
|
||||
map<int32, LUAHistory> required_history;
|
||||
EquipmentItemList equipment_list;
|
||||
|
|
|
@ -393,6 +393,7 @@ void Widget::HandleUse(Client* client, string command, int8 overrideWidgetType){
|
|||
ClientPacketFunctions::SendHouseVisitWindow(client, world.GetAllPlayerHousesByHouseID(m_houseID));
|
||||
|
||||
ClientPacketFunctions::SendBaseHouseWindow(client, hz, ph, id);
|
||||
client->GetCurrentZone()->SendHouseItems(client);
|
||||
}
|
||||
else {
|
||||
if (hz)
|
||||
|
|
|
@ -6708,13 +6708,14 @@ void WorldDatabase::GetHouseSpawnInstanceData(ZoneServer* zone, Spawn* spawn)
|
|||
|
||||
DatabaseResult result;
|
||||
|
||||
database_new.Select(&result, "SELECT pickup_item_id\n"
|
||||
database_new.Select(&result, "SELECT pickup_item_id, pickup_unique_item_id\n"
|
||||
" FROM spawn_instance_data\n"
|
||||
" WHERE spawn_id = %u and spawn_location_id = %u",
|
||||
spawn->GetDatabaseID(),spawn->GetSpawnLocationID());
|
||||
|
||||
if (result.GetNumRows() > 0 && result.Next()) {
|
||||
spawn->SetPickupItemID(result.GetInt32(0));
|
||||
spawn->SetPickupUniqueItemID(result.GetInt32(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1862,7 +1862,7 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
|
|||
|
||||
if (upkeep_due > (Timer::GetUnixTimeStamp() + 7257600)) // 84 days max upkeep to pay https://eq2.zam.com/wiki/Housing_%28EQ2%29#Upkeep
|
||||
{
|
||||
Message(CHANNEL_COLOR_YELLOW, "You cannot pay more than 1 month of upkeep.");
|
||||
Message(CHANNEL_COLOR_YELLOW, "You cannot pay more than 3 months of upkeep.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2381,8 +2381,28 @@ void Client::HandleExamineInfoRequest(EQApplicationPacket* app) {
|
|||
return;
|
||||
}
|
||||
request->LoadPacketData(app->pBuffer, app->size);
|
||||
|
||||
int32 id = request->getType_int32_ByName("id");
|
||||
Item* item = GetPlayer()->item_list.GetItemFromUniqueID(id, true);
|
||||
|
||||
Item* item = 0;
|
||||
|
||||
// translate from unique id to spawn id for houses
|
||||
Spawn* spawn = this->GetCurrentZone()->GetSpawnFromUniqueItemID(id);
|
||||
|
||||
bool wasSpawn = false;
|
||||
if (spawn)
|
||||
{
|
||||
item = master_item_list.GetItem(spawn->GetPickupItemID());
|
||||
if (item)
|
||||
{
|
||||
wasSpawn = true;
|
||||
item = new Item(item);
|
||||
item->details.unique_id = spawn->GetPickupUniqueItemID();
|
||||
}
|
||||
}
|
||||
|
||||
if (!item)
|
||||
item = GetPlayer()->item_list.GetItemFromUniqueID(id, true);
|
||||
if (!item)
|
||||
item = GetPlayer()->GetEquipmentList()->GetItemFromUniqueID(id);
|
||||
if (!item)
|
||||
|
@ -2392,6 +2412,8 @@ void Client::HandleExamineInfoRequest(EQApplicationPacket* app) {
|
|||
EQ2Packet* app = item->serialize(GetVersion(), false, GetPlayer());
|
||||
//DumpPacket(app);
|
||||
QueuePacket(app);
|
||||
if (wasSpawn)
|
||||
delete item;
|
||||
}
|
||||
else {
|
||||
LogWrite(WORLD__ERROR, 0, "World", "HandleExamineInfoRequest: Unknown Item ID = %u", id);
|
||||
|
@ -8654,28 +8676,6 @@ bool Client::HandleHouseEntityCommands(Spawn* spawn, int32 spawnid, string comma
|
|||
}
|
||||
return true;
|
||||
}
|
||||
else if (!HasOwnerOrEditAccess())
|
||||
{
|
||||
//SimpleMessage(CHANNEL_COLOR_RED, "This is not your home!");
|
||||
return false;
|
||||
}
|
||||
else if (command == "house_spawn_move")
|
||||
{
|
||||
SendMoveObjectMode(spawn, 0);
|
||||
return true;
|
||||
}
|
||||
else if (command == "house_spawn_pickup" && spawn->GetPickupItemID())
|
||||
{
|
||||
AddItem(spawn->GetPickupItemID(), 1);
|
||||
|
||||
Query query;
|
||||
query.RunQuery2(Q_INSERT, "delete from spawn_instance_data where spawn_id = %u and spawn_location_id = %u and pickup_item_id = %u", spawn->GetDatabaseID(), spawn->GetSpawnLocationID(), spawn->GetPickupItemID());
|
||||
|
||||
if (database.RemoveSpawnFromSpawnLocation(spawn)) {
|
||||
GetCurrentZone()->RemoveSpawn(false, spawn, true, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -8741,13 +8741,14 @@ bool Client::PopulateHouseSpawnFinalize()
|
|||
int32 uniqueID = GetPlacementUniqueItemID();
|
||||
Item* uniqueItem = GetPlayer()->item_list.GetItemFromUniqueID(uniqueID);
|
||||
tmp->SetPickupItemID(uniqueItem->details.item_id);
|
||||
tmp->SetPickupUniqueItemID(uniqueID);
|
||||
|
||||
if (uniqueItem)
|
||||
{
|
||||
if (GetCurrentZone()->GetInstanceType() == PERSONAL_HOUSE_INSTANCE)
|
||||
{
|
||||
Query query;
|
||||
query.RunQuery2(Q_INSERT, "insert into spawn_instance_data set spawn_id = %u, spawn_location_id = %u, pickup_item_id = %u", tmp->GetDatabaseID(), tmp->GetSpawnLocationID(), tmp->GetPickupItemID());
|
||||
query.RunQuery2(Q_INSERT, "insert into spawn_instance_data set spawn_id = %u, spawn_location_id = %u, pickup_item_id = %u, pickup_unique_item_id = %u", tmp->GetDatabaseID(), tmp->GetSpawnLocationID(), tmp->GetPickupItemID(), uniqueID);
|
||||
}
|
||||
|
||||
database.DeleteItem(GetCharacterID(), uniqueItem, 0);
|
||||
|
|
|
@ -799,7 +799,7 @@ bool ZoneServer::AddCloseSpawnsToSpawnGroup(Spawn* spawn, float radius){
|
|||
|
||||
void ZoneServer::RepopSpawns(Client* client, Spawn* in_spawn){
|
||||
vector<Spawn*>* spawns = in_spawn->GetSpawnGroup();
|
||||
PacketStruct* packet = configReader.getStruct("WS_DestroyGhostCmd", client->GetVersion());;
|
||||
PacketStruct* packet = configReader.getStruct("WS_DestroyGhostCmd", client->GetVersion());
|
||||
if(spawns){
|
||||
if(!packet)
|
||||
return;
|
||||
|
@ -2903,9 +2903,9 @@ void ZoneServer::AddSpawn(Spawn* spawn) {
|
|||
if (GetInstanceType() == PERSONAL_HOUSE_INSTANCE && spawn->IsObject())
|
||||
{
|
||||
spawn->AddSecondaryEntityCommand("Examine", 20, "house_spawn_examine", "", 0, 0);
|
||||
spawn->AddSecondaryEntityCommand("Move", 20, "house_spawn_move", "", 0, 0);
|
||||
spawn->AddSecondaryEntityCommand("Move", 20, "move_item", "", 0, 0);
|
||||
spawn->AddSecondaryEntityCommand("Pack in Moving Crate", 20, "house_spawn_pack_in_moving_crate", "", 0, 0);
|
||||
spawn->AddSecondaryEntityCommand("Pick Up", 20, "house_spawn_pickup", "", 0, 0);
|
||||
spawn->AddSecondaryEntityCommand("Pick Up", 20, "pickup", "", 0, 0);
|
||||
spawn->SetShowCommandIcon(1);
|
||||
}
|
||||
|
||||
|
@ -7338,4 +7338,111 @@ void ZoneServer::SetSpawnScript(SpawnEntry* entry, Spawn* spawn)
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vector<HouseItem> ZoneServer::GetHouseItems(Client* client)
|
||||
{
|
||||
if (!client->GetCurrentZone()->GetInstanceID() || !client->HasOwnerOrEditAccess())
|
||||
return std::vector<HouseItem>();
|
||||
|
||||
PacketStruct* packet = configReader.getStruct("WS_HouseItemsList", client->GetVersion());
|
||||
|
||||
std::vector<HouseItem> items;
|
||||
map<int32, Spawn*>::iterator itr;
|
||||
Spawn* spawn = 0;
|
||||
MSpawnList.readlock(__FUNCTION__, __LINE__);
|
||||
for (itr = spawn_list.begin(); itr != spawn_list.end(); itr++) {
|
||||
spawn = itr->second;
|
||||
if (spawn && spawn->IsObject() && spawn->GetPickupItemID())
|
||||
{
|
||||
HouseItem tmpItem;
|
||||
tmpItem.item_id = spawn->GetPickupItemID();
|
||||
tmpItem.unique_id = spawn->GetPickupUniqueItemID();
|
||||
tmpItem.spawn_id = spawn->GetID();
|
||||
tmpItem.item = master_item_list.GetItem(spawn->GetPickupItemID());
|
||||
|
||||
if (!tmpItem.item)
|
||||
continue;
|
||||
|
||||
items.push_back(tmpItem);
|
||||
}
|
||||
}
|
||||
MSpawnList.releasereadlock(__FUNCTION__, __LINE__);
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
void ZoneServer::SendHouseItems(Client* client)
|
||||
{
|
||||
if (!client->GetCurrentZone()->GetInstanceID() || !client->HasOwnerOrEditAccess())
|
||||
return;
|
||||
|
||||
PacketStruct* packet = configReader.getStruct("WS_HouseItemsList", client->GetVersion());
|
||||
|
||||
std::vector<HouseItem> items = GetHouseItems(client);
|
||||
|
||||
// setting this to 1 puts it on the door widget
|
||||
packet->setDataByName("is_widget_door", 1);
|
||||
packet->setArrayLengthByName("num_items", items.size());
|
||||
for (int i = 0; i < items.size(); i++)
|
||||
{
|
||||
HouseItem tmpItem = items[i];
|
||||
packet->setArrayDataByName("unique_id", tmpItem.unique_id, i); // unique_id is in fact the item_id...
|
||||
packet->setArrayDataByName("item_name", tmpItem.item->name.c_str(), i);
|
||||
packet->setArrayDataByName("status_reduction", tmpItem.item->houseitem_info->status_rent_reduction, i);
|
||||
|
||||
// location, 0 = floor, 1 = ceiling
|
||||
//packet->setArrayDataByName("location", 1, i, 0);
|
||||
|
||||
// item_state int8
|
||||
// 0 = normal (cannot pick up item / move item / toggle visibility)
|
||||
// 1 = virtual (toggle visibility available, no move item)
|
||||
// 2 = hidden (cannot pick up item / move item / toggle visibility)
|
||||
// 3 = virtual/hidden/toggle visibility
|
||||
// 4 = none (cannot pick up item / move item / toggle visibility)
|
||||
// 5 = none, toggle visibility (cannot pick up item / move item)
|
||||
// 8 = none (cannot pick up item / move item / toggle visibility)
|
||||
//packet->setArrayDataByName("item_state", tmpvalue, i, 0);
|
||||
|
||||
// makes it so we don't have access to move item/retrieve item
|
||||
// cannot use in conjunction with ui_tab_flag1/ui_tab_flag2
|
||||
//packet->setArrayDataByName("tradeable", 1, i);
|
||||
//packet->setArrayDataByName("item_description", "failboat", i);
|
||||
|
||||
// access to move item/retrieve item, do not use in conjunction with tradeable
|
||||
packet->setArrayDataByName("ui_tab_flag1", 1, i, 0);
|
||||
packet->setArrayDataByName("ui_tab_flag2", 1, i, 0);
|
||||
|
||||
// both of these can serve as description fields (only one should be used they populate the same area below the item name)
|
||||
//packet->setArrayDataByName("first_item_description", "test", i);
|
||||
//packet->setArrayDataByName("second_item_description", "Description here!", i);
|
||||
|
||||
packet->setArrayDataByName("icon", tmpItem.item->details.icon, i);
|
||||
}
|
||||
|
||||
EQ2Packet* pack = packet->serialize();
|
||||
client->QueuePacket(pack);
|
||||
safe_delete(packet);
|
||||
}
|
||||
|
||||
Spawn* ZoneServer::GetSpawnFromUniqueItemID(int32 unique_id)
|
||||
{
|
||||
if (!GetInstanceID() || GetInstanceType() != Instance_Type::PERSONAL_HOUSE_INSTANCE)
|
||||
return nullptr;
|
||||
|
||||
map<int32, Spawn*>::iterator itr;
|
||||
Spawn* spawn = 0;
|
||||
MSpawnList.readlock(__FUNCTION__, __LINE__);
|
||||
for (itr = spawn_list.begin(); itr != spawn_list.end(); itr++) {
|
||||
spawn = itr->second;
|
||||
if (spawn && spawn->IsObject() && spawn->GetPickupUniqueItemID() == unique_id)
|
||||
{
|
||||
Spawn* tmpSpawn = spawn;
|
||||
MSpawnList.releasereadlock();
|
||||
return tmpSpawn;
|
||||
}
|
||||
}
|
||||
MSpawnList.releasereadlock();
|
||||
|
||||
return nullptr;
|
||||
}
|
|
@ -154,6 +154,13 @@ struct TrackedSpawn {
|
|||
float distance;
|
||||
};
|
||||
|
||||
struct HouseItem {
|
||||
int32 spawn_id;
|
||||
int32 item_id;
|
||||
int32 unique_id;
|
||||
Item* item;
|
||||
};
|
||||
|
||||
class Widget;
|
||||
class Client;
|
||||
class Sign;
|
||||
|
@ -625,6 +632,10 @@ public:
|
|||
return LoadingData;
|
||||
}
|
||||
|
||||
vector<HouseItem> GetHouseItems(Client* client);
|
||||
Spawn* GetSpawnFromUniqueItemID(int32 unique_id);
|
||||
void SendHouseItems(Client* client);
|
||||
|
||||
MutexMap<int32, int32> house_object_database_lookup; // 1st int32 = model type, 2nd int32 = spawn id
|
||||
private:
|
||||
/* Private Functions */
|
||||
|
|
|
@ -32975,6 +32975,30 @@ to zero and treated like placeholders." />
|
|||
</Data>
|
||||
<Data ElementName="unknown7" Type="int16" />
|
||||
</Struct>
|
||||
<Struct Name="WS_HouseItemsList" ClientVersion="60114" OpcodeName="OP_HouseItemsList">
|
||||
<Data ElementName="num_items" Type="int32" />
|
||||
<Data ElementName="items_array" Type="Array" ArraySizeVariable="num_items">
|
||||
<Data ElementName="unique_id" Type="int32" />
|
||||
<Data ElementName="item_name" Type="EQ2_16Bit_String" />
|
||||
<Data ElementName="status_reduction" Type="int32" />
|
||||
<Data ElementName="unknown1" Type="int32" />
|
||||
<Data ElementName="unknown2" Type="int32" />
|
||||
<Data ElementName="tradeable" Type="int8" /> <!-- when 0 should must? item_description -->
|
||||
<Data ElementName="is_notrade" Type="EQ2_16Bit_String" IfVariableNotEquals="tradeable_%i"/>
|
||||
<Data ElementName="unknown5" Type="int8"/>
|
||||
<Data ElementName="ui_tab_flag1" Type="int8"/>
|
||||
<Data ElementName="first_item_description" Type="EQ2_16Bit_String" IfVariableNotSet="ui_tab_flag1_%i"/>
|
||||
<Data ElementName="ui_tab_flag2" Type="int8"/>
|
||||
<Data ElementName="second_item_description" Type="EQ2_16Bit_String" IfVariableNotSet="ui_tab_flag2_%i"/>
|
||||
<Data ElementName="icon" Type="int16" />
|
||||
<Data ElementName="location" Type="int8" />
|
||||
<Data ElementName="item_state" Type="int8"/>
|
||||
<Data ElementName="item_state_extended" Type="int8" size="3" /> <!-- could be more of the item_state -->
|
||||
</Data>
|
||||
<Data ElementName="unknown7" Type="int8" />
|
||||
<!-- setting to 1 causes it to populate on the items tab with the widget door aka /house command. 0 its a popup (moving crate). -->
|
||||
<Data ElementName="is_widget_door" Type="int16" />
|
||||
</Struct>
|
||||
<Struct Name="WS_HouseItemsList" ClientVersion="63119" OpcodeName="OP_HouseItemsList">
|
||||
<Data ElementName="num_items" Type="int32" />
|
||||
<Data ElementName="items_array" Type="Array" ArraySizeVariable="num_items">
|
||||
|
|
Loading…
Reference in a new issue