diff --git a/src/common/Common.h b/src/common/Common.h index d777a9e2..fdb52426 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -780,6 +780,7 @@ namespace Sapphire::Common enum HouseExteriorSlot { + HousePermit, ExteriorRoof, ExteriorWall, ExteriorWindow, diff --git a/src/common/Network/CommonActorControl.h b/src/common/Network/CommonActorControl.h index 5f5f615d..9c03d685 100644 --- a/src/common/Network/CommonActorControl.h +++ b/src/common/Network/CommonActorControl.h @@ -213,6 +213,11 @@ enum ActorControlType : uint16_t // Housing ShowHousingItemUI = 0x3F7, ShowBuildPresetUI = 0x3E9, + /*! + * param1 = plot id + */ + ShowEstateExternalAppearanceUI = 0x3EA, + ShowEstateInternalAppearanceUI = 0x3EB, BuildPresetResponse = 0x3ED, /*! @@ -327,6 +332,8 @@ enum ActorControlType : uint16_t SetEstateLightingLevel = 0x40B, // param1 = light level 0 - 5 maps to UI val 5-0 RequestHousingBuildPreset = 0x44C, + RequestEstateExteriorRemodel = 0x044D, // param11 = land id + RequestEstateInteriorRemodel = 0x44E, RequestEstateHallRemoval = 0x44F, RequestBuildPreset = 0x450, // no idea what this is, it gets sent with BuildPresetHandler and has the plot id in param1 RequestLandSignFree = 0x451, diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index ea86382c..c51e7640 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -264,7 +264,7 @@ void Sapphire::World::Manager::HousingMgr::initLandCache() // fixed containers makeContainer( InventoryType::HousingInteriorAppearance, 10 ); - makeContainer( InventoryType::HousingExteriorAppearance, 8 ); + makeContainer( InventoryType::HousingExteriorAppearance, 9 ); } } @@ -896,7 +896,15 @@ void Sapphire::World::Manager::HousingMgr::updateHouseModels( Sapphire::HousePtr { for( auto& item : extContainer->second->getItemMap() ) { - house->setExteriorModel( static_cast< Common::HouseExteriorSlot >( item.first ), + // in the Slot array, the first slot is actually the permit + // but the models array starts from the 2nd entry of the enum + // so we skip the first one, and then any subsequent entries is slotid - 1 + + auto slotId = item.first - 1; + if( slotId < 0 ) + continue; + + house->setExteriorModel( static_cast< Common::HouseExteriorSlot >( slotId ), getItemAdditionalData( item.second->getId() ), item.second->getStain() ); } } @@ -1461,4 +1469,62 @@ Sapphire::ItemContainerPtr Sapphire::World::Manager::HousingMgr::getFreeEstateIn } return nullptr; +} + +void Sapphire::World::Manager::HousingMgr::reqEstateExteriorRemodel( Sapphire::Entity::Player& player, uint16_t plot ) +{ + auto terri = std::dynamic_pointer_cast< HousingZone >( player.getCurrentZone() ); + if( !terri ) + return; + + auto land = terri->getLand( plot ); + if( !land ) + return; + + // todo: proper perms checks + if( land->getOwnerId() != player.getId() ) + return; + + auto& inv = getEstateInventory( land->getLandIdent() ); + auto needle = inv.find( InventoryType::HousingExteriorAppearance ); + if( needle == inv.end() ) + return; + + auto invMgr = g_fw.get< InventoryMgr >(); + + invMgr->sendInventoryContainer( player, needle->second ); + + auto pkt = Server::makeActorControl143( player.getId(), Network::ActorControl::ShowEstateExternalAppearanceUI, plot ); + player.queuePacket( pkt ); + +} + +void Sapphire::World::Manager::HousingMgr::reqEstateInteriorRemodel( Sapphire::Entity::Player& player ) +{ + auto terri = std::dynamic_pointer_cast< Territory::Housing::HousingInteriorTerritory >( player.getCurrentZone() ); + if( !terri ) + return; + + auto ident = terri->getLandIdent(); + auto landSet = toLandSetId( ident.territoryTypeId, ident.wardNum ); + auto land = getHousingZoneByLandSetId( landSet )->getLand( ident.landId ); + + if( !land ) + return; + + // todo: proper perms checks + if( land->getOwnerId() != player.getId() ) + return; + + auto& inv = getEstateInventory( land->getLandIdent() ); + auto needle = inv.find( InventoryType::HousingInteriorAppearance ); + if( needle == inv.end() ) + return; + + auto invMgr = g_fw.get< InventoryMgr >(); + + invMgr->sendInventoryContainer( player, needle->second ); + + auto pkt = Server::makeActorControl143( player.getId(), Network::ActorControl::ShowEstateInternalAppearanceUI ); + player.queuePacket( pkt ); } \ No newline at end of file diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index 804420e2..512a7a05 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -172,6 +172,10 @@ namespace Sapphire::World::Manager uint16_t containerId, uint16_t slot, bool sendToStoreroom ); + void reqEstateExteriorRemodel( Entity::Player& player, uint16_t plot ); + + void reqEstateInteriorRemodel( Entity::Player& player ); + private: ItemContainerPtr getFreeEstateInventorySlot( Common::LandIdent ident, diff --git a/src/world/Network/Handlers/ClientTriggerHandler.cpp b/src/world/Network/Handlers/ClientTriggerHandler.cpp index df9409f4..28249ee8 100644 --- a/src/world/Network/Handlers/ClientTriggerHandler.cpp +++ b/src/world/Network/Handlers/ClientTriggerHandler.cpp @@ -469,6 +469,22 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX break; } + case ClientTriggerType::RequestEstateExteriorRemodel: + { + auto housingMgr = g_fw.get< HousingMgr >(); + + housingMgr->reqEstateExteriorRemodel( player, param11 ); + + break; + } + case ClientTriggerType::RequestEstateInteriorRemodel: + { + auto housingMgr = g_fw.get< HousingMgr >(); + + housingMgr->reqEstateInteriorRemodel( player ); + + break; + } default: {