2018-11-10 19:00:13 +01:00
# include "HousingMgr.h"
# include <Logging/Logger.h>
# include <Database/DatabaseDef.h>
# include <Exd/ExdDataGenerated.h>
2018-11-13 23:46:10 +01:00
# include <Network/PacketContainer.h>
# include <Network/PacketDef/Zone/ServerZoneDef.h>
# include <Network/PacketWrappers/ActorControlPacket142.h>
# include <Network/PacketWrappers/ActorControlPacket143.h>
# include <Network/CommonActorControl.h>
2018-11-10 19:00:13 +01:00
# include <unordered_map>
2018-11-27 21:45:29 +11:00
# include <cstring>
2018-11-10 19:00:13 +01:00
# include "Actor/Player.h"
2018-11-30 22:52:08 +11:00
# include "Actor/EventObject.h"
2018-12-11 23:40:47 +01:00
# include "Event/EventDefs.h"
2018-11-10 19:00:13 +01:00
2018-11-19 11:55:29 +01:00
# include "TerritoryMgr.h"
2018-12-01 00:27:16 +11:00
# include "Territory/Zone.h"
# include "Territory/HousingZone.h"
2018-12-05 19:58:43 +11:00
# include "Territory/Housing/HousingInteriorTerritory.h"
2018-11-10 19:00:13 +01:00
# include "HousingMgr.h"
2018-12-01 00:27:16 +11:00
# include "Territory/Land.h"
2018-11-10 19:00:13 +01:00
# include "Framework.h"
2018-11-20 21:32:13 +01:00
# include "ServerMgr.h"
2018-12-01 00:27:16 +11:00
# include "Territory/House.h"
2018-12-20 20:41:16 +11:00
# include "InventoryMgr.h"
2018-12-23 22:43:35 +11:00
# include "Inventory/HousingItem.h"
2018-12-22 15:58:54 +11:00
# include "Inventory/ItemContainer.h"
2018-12-26 18:11:18 +11:00
# include "Util/UtilMath.h"
2018-11-13 23:46:10 +01:00
2018-11-29 16:55:48 +01:00
using namespace Sapphire : : Common ;
using namespace Sapphire : : Network ;
using namespace Sapphire : : Network : : Packets ;
using namespace Sapphire : : Network : : Packets : : Server ;
2018-11-10 19:00:13 +01:00
2018-12-22 22:25:03 +01:00
Sapphire : : World : : Manager : : HousingMgr : : HousingMgr ( FrameworkPtr pFw ) :
BaseManager ( pFw )
2018-12-25 21:05:13 +11:00
{
m_containerMap [ 0 ] = std : : make_pair ( InventoryType : : HousingInteriorPlacedItems1 , InventoryType : : HousingInteriorStoreroom1 ) ;
2018-12-27 15:52:48 +11:00
m_containerMap [ 1 ] = std : : make_pair ( InventoryType : : HousingInteriorPlacedItems2 , InventoryType : : HousingInteriorStoreroom2 ) ;
m_containerMap [ 2 ] = std : : make_pair ( InventoryType : : HousingInteriorPlacedItems3 , InventoryType : : HousingInteriorStoreroom3 ) ;
m_containerMap [ 3 ] = std : : make_pair ( InventoryType : : HousingInteriorPlacedItems4 , InventoryType : : HousingInteriorStoreroom4 ) ;
m_containerMap [ 4 ] = std : : make_pair ( InventoryType : : HousingInteriorPlacedItems5 , InventoryType : : HousingInteriorStoreroom5 ) ;
m_containerMap [ 5 ] = std : : make_pair ( InventoryType : : HousingInteriorPlacedItems6 , InventoryType : : HousingInteriorStoreroom6 ) ;
m_containerMap [ 6 ] = std : : make_pair ( InventoryType : : HousingInteriorPlacedItems7 , InventoryType : : HousingInteriorStoreroom7 ) ;
m_containerMap [ 7 ] = std : : make_pair ( InventoryType : : HousingInteriorPlacedItems8 , InventoryType : : HousingInteriorStoreroom8 ) ;
2018-12-27 13:33:29 +11:00
m_internalPlacedItemContainers =
{
InventoryType : : HousingInteriorPlacedItems1 ,
InventoryType : : HousingInteriorPlacedItems2 ,
InventoryType : : HousingInteriorPlacedItems3 ,
InventoryType : : HousingInteriorPlacedItems4 ,
InventoryType : : HousingInteriorPlacedItems5 ,
InventoryType : : HousingInteriorPlacedItems6 ,
InventoryType : : HousingInteriorPlacedItems7 ,
InventoryType : : HousingInteriorPlacedItems8 ,
} ;
m_internalStoreroomContainers =
{
InventoryType : : HousingInteriorStoreroom1 ,
InventoryType : : HousingInteriorStoreroom2 ,
InventoryType : : HousingInteriorStoreroom3 ,
InventoryType : : HousingInteriorStoreroom4 ,
InventoryType : : HousingInteriorStoreroom5 ,
InventoryType : : HousingInteriorStoreroom6 ,
InventoryType : : HousingInteriorStoreroom7 ,
InventoryType : : HousingInteriorStoreroom8 ,
} ;
2018-12-25 21:05:13 +11:00
}
2018-12-22 11:33:21 +11:00
Sapphire : : World : : Manager : : HousingMgr : : ~ HousingMgr ( ) = default ;
bool Sapphire : : World : : Manager : : HousingMgr : : init ( )
2018-11-10 19:00:13 +01:00
{
2018-12-29 13:05:13 +11:00
Logger : : info ( " HousingMgr: Caching housing land init data " ) ;
2018-12-22 11:33:21 +11:00
//LAND_SEL_ALL
2018-11-10 19:00:13 +01:00
2018-12-22 11:33:21 +11:00
// 18 wards per territory, 4 territories
m_landCache . reserve ( 18 * 4 ) ;
2018-11-10 19:00:13 +01:00
2018-12-25 20:12:24 +11:00
initLandCache ( ) ;
2018-12-22 14:35:42 +11:00
2018-12-29 13:05:13 +11:00
Logger : : debug ( " HousingMgr: Checking land counts " ) ;
2018-12-22 14:35:42 +11:00
uint32_t houseCount = 0 ;
for ( auto & landSet : m_landCache )
{
auto count = landSet . second . size ( ) ;
houseCount + = count ;
if ( landSet . second . size ( ) ! = 60 )
{
2018-12-29 13:05:13 +11:00
Logger : : fatal ( " LandSet " + std : : to_string ( landSet . first ) + " is missing land entries. Only have " + std : : to_string ( count ) + " land entries. " ) ;
2018-12-22 14:35:42 +11:00
return false ;
}
}
2018-12-29 13:05:13 +11:00
Logger : : info ( " HousingMgr: Cached " + std : : to_string ( houseCount ) + " houses " ) ;
2018-12-22 14:35:42 +11:00
/////
if ( ! loadEstateInventories ( ) )
return false ;
return true ;
}
bool Sapphire : : World : : Manager : : HousingMgr : : loadEstateInventories ( )
{
2018-12-29 13:05:13 +11:00
Logger : : info ( " HousingMgr: Loading inventories for estates " ) ;
2018-12-22 14:35:42 +11:00
2018-12-29 13:05:13 +11:00
auto pDb = framework ( ) - > get < Db : : DbWorkerPool < Db : : ZoneDbConnection > > ( ) ;
2018-12-22 15:58:54 +11:00
auto stmt = pDb - > getPreparedStatement ( Db : : LAND_INV_SEL_ALL ) ;
auto res = pDb - > query ( stmt ) ;
uint32_t itemCount = 0 ;
while ( res - > next ( ) )
{
//uint64_t uId, uint32_t catalogId, uint64_t model1, uint64_t model2, bool isHq
2018-12-23 22:43:35 +11:00
auto ident = res - > getUInt64 ( " LandIdent " ) ;
auto containerId = res - > getUInt16 ( " ContainerId " ) ;
auto itemId = res - > getUInt64 ( " ItemId " ) ;
auto slot = res - > getUInt16 ( " SlotId " ) ;
auto catalogId = res - > getUInt ( " catalogId " ) ;
auto stain = res - > getUInt8 ( " stain " ) ;
auto characterId = res - > getUInt64 ( " CharacterId " ) ;
2018-12-29 13:05:13 +11:00
auto item = Inventory : : make_HousingItem ( itemId , catalogId , framework ( ) ) ;
2018-12-22 15:58:54 +11:00
item - > setStain ( stain ) ;
2018-12-25 22:59:13 +11:00
item - > setStackSize ( 1 ) ;
2018-12-22 15:58:54 +11:00
// todo: need to set the owner character id on the item
2018-12-25 20:12:24 +11:00
// set world pos on item if its in an placed item container
if ( isPlacedItemsInventory ( static_cast < Common : : InventoryType > ( containerId ) ) )
{
item - > setPos ( {
2018-12-26 19:22:30 +11:00
res - > getUInt16 ( " PosX " ) ,
res - > getUInt16 ( " PosY " ) ,
res - > getUInt16 ( " PosZ " )
2018-12-25 20:12:24 +11:00
} ) ;
2018-12-26 19:22:30 +11:00
item - > setRot ( res - > getUInt16 ( " Rotation " ) ) ;
2018-12-25 20:12:24 +11:00
}
2018-12-22 17:22:24 +11:00
ContainerIdToContainerMap & estateInv = m_estateInventories [ ident ] ;
2018-12-22 15:58:54 +11:00
2018-12-25 21:05:13 +11:00
// check if containerId exists, it always should - if it doesn't, something went wrong
2018-12-22 15:58:54 +11:00
auto container = estateInv . find ( containerId ) ;
2018-12-25 21:05:13 +11:00
assert ( container ! = estateInv . end ( ) ) ;
2018-12-22 15:58:54 +11:00
2018-12-25 21:05:13 +11:00
container - > second - > setItem ( slot , item ) ;
2018-12-22 15:58:54 +11:00
itemCount + + ;
}
2018-12-29 13:05:13 +11:00
Logger : : debug ( " HousingMgr: Loaded " + std : : to_string ( itemCount ) + " inventory items " ) ;
2018-12-22 15:58:54 +11:00
2018-12-22 14:35:42 +11:00
return true ;
}
2018-12-25 20:12:24 +11:00
void Sapphire : : World : : Manager : : HousingMgr : : initLandCache ( )
2018-12-22 14:35:42 +11:00
{
2018-12-29 13:05:13 +11:00
auto pDb = framework ( ) - > get < Db : : DbWorkerPool < Db : : ZoneDbConnection > > ( ) ;
2018-12-22 11:33:21 +11:00
auto stmt = pDb - > getPreparedStatement ( Db : : LAND_SEL_ALL ) ;
auto res = pDb - > query ( stmt ) ;
while ( res - > next ( ) )
{
LandCacheEntry entry ;
// land stuff
entry . m_landSetId = res - > getUInt64 ( " LandSetId " ) ;
2018-12-25 21:05:13 +11:00
entry . m_landId = res - > getUInt ( " LandId " ) ;
2018-12-22 11:33:21 +11:00
2018-12-22 12:00:03 +11:00
entry . m_type = static_cast < Common : : LandType > ( res - > getUInt ( " Type " ) ) ;
2018-12-22 11:33:21 +11:00
entry . m_size = res - > getUInt8 ( " Size " ) ;
entry . m_status = res - > getUInt8 ( " Status " ) ;
2018-12-22 12:00:03 +11:00
entry . m_currentPrice = res - > getUInt64 ( " LandPrice " ) ;
2018-12-22 11:33:21 +11:00
entry . m_updateTime = res - > getUInt64 ( " UpdateTime " ) ;
entry . m_ownerId = res - > getUInt64 ( " OwnerId " ) ;
entry . m_houseId = res - > getUInt64 ( " HouseId " ) ;
// house stuff
entry . m_estateWelcome = res - > getString ( " Welcome " ) ;
entry . m_estateComment = res - > getString ( " Comment " ) ;
2018-12-22 14:35:42 +11:00
entry . m_estateName = res - > getString ( " HouseName " ) ;
2018-12-22 11:33:21 +11:00
entry . m_buildTime = res - > getUInt64 ( " BuildTime " ) ;
entry . m_endorsements = res - > getUInt64 ( " Endorsements " ) ;
m_landCache [ entry . m_landSetId ] . push_back ( entry ) ;
2018-12-25 20:12:24 +11:00
uint16_t maxExternalItems = 0 ;
uint16_t maxInternalItems = 0 ;
// init inventory containers
switch ( entry . m_size )
{
case HouseSize : : Cottage :
2018-12-25 21:05:13 +11:00
entry . m_maxPlacedExternalItems = 20 ;
entry . m_maxPlacedInternalItems = 200 ;
2018-12-25 20:12:24 +11:00
break ;
case HouseSize : : House :
2018-12-25 21:05:13 +11:00
entry . m_maxPlacedExternalItems = 30 ;
entry . m_maxPlacedInternalItems = 300 ;
2018-12-25 20:12:24 +11:00
break ;
case HouseSize : : Mansion :
2018-12-25 21:05:13 +11:00
entry . m_maxPlacedExternalItems = 40 ;
entry . m_maxPlacedInternalItems = 400 ;
2018-12-25 20:12:24 +11:00
break ;
default :
// this should never ever happen, if it does the db is fucked
2018-12-29 13:05:13 +11:00
Logger : : error ( " HousingMgr: Plot " + std : : to_string ( entry . m_landId ) + " in landset " + std : : to_string ( entry . m_landSetId ) +
" has an invalid land size, defaulting to cottage. " ) ;
2018-12-25 21:05:13 +11:00
entry . m_maxPlacedExternalItems = 20 ;
entry . m_maxPlacedInternalItems = 200 ;
2018-12-25 20:12:24 +11:00
break ;
}
2018-12-25 21:05:13 +11:00
// setup containers
// todo: this is pretty garbage
Common : : LandIdent ident ;
ident . territoryTypeId = entry . m_landSetId > > 16 ;
ident . wardNum = entry . m_landSetId & 0xFFFF ;
ident . landId = entry . m_landId ;
ident . worldId = 67 ;
auto & containers = getEstateInventory ( ident ) ;
2018-12-29 13:05:13 +11:00
auto makeContainer = [ & containers , this ] ( Common : : InventoryType type , uint16_t size )
2018-12-25 21:05:13 +11:00
{
2018-12-29 13:05:13 +11:00
containers [ type ] = make_ItemContainer ( type , size , " houseiteminventory " , false , framework ( ) , false ) ;
2018-12-25 21:05:13 +11:00
} ;
uint16_t count = 0 ;
for ( int i = 0 ; i < 8 ; + + i )
{
2018-12-27 15:52:48 +11:00
if ( count > entry . m_maxPlacedInternalItems )
2018-12-25 21:05:13 +11:00
break ;
auto & pair = m_containerMap [ i ] ;
makeContainer ( pair . first , 50 ) ;
makeContainer ( pair . second , 50 ) ;
count + = 50 ;
}
// exterior
makeContainer ( InventoryType : : HousingExteriorPlacedItems , entry . m_maxPlacedExternalItems ) ;
makeContainer ( InventoryType : : HousingExteriorStoreroom , entry . m_maxPlacedExternalItems ) ;
// fixed containers
makeContainer ( InventoryType : : HousingInteriorAppearance , 10 ) ;
2018-12-28 18:45:08 +11:00
makeContainer ( InventoryType : : HousingExteriorAppearance , 9 ) ;
2018-12-25 21:05:13 +11:00
2018-12-22 11:33:21 +11:00
}
2018-11-10 19:00:13 +01:00
}
2018-12-23 19:13:30 +11:00
uint64_t Sapphire : : World : : Manager : : HousingMgr : : getNextHouseId ( )
{
2018-12-29 13:05:13 +11:00
auto pDb = framework ( ) - > get < Db : : DbWorkerPool < Db : : ZoneDbConnection > > ( ) ;
2018-12-23 19:13:30 +11:00
auto pQR = pDb - > query ( " SELECT MAX( HouseId ) FROM house " ) ;
if ( ! pQR - > next ( ) )
return 0 ;
return pQR - > getUInt64 ( 1 ) + 1 ;
}
2018-12-01 00:27:16 +11:00
uint32_t Sapphire : : World : : Manager : : HousingMgr : : toLandSetId ( uint16_t territoryTypeId , uint8_t wardId ) const
2018-11-16 17:07:22 +01:00
{
return ( static_cast < uint32_t > ( territoryTypeId ) < < 16 ) | wardId ;
}
2018-12-01 00:27:16 +11:00
Sapphire : : Data : : HousingZonePtr Sapphire : : World : : Manager : : HousingMgr : : getHousingZoneByLandSetId ( uint32_t id )
2018-11-10 19:00:13 +01:00
{
2018-12-22 22:25:03 +01:00
auto pTeriMgr = framework ( ) - > get < TerritoryMgr > ( ) ;
2018-11-19 11:55:29 +01:00
return std : : dynamic_pointer_cast < HousingZone > ( pTeriMgr - > getZoneByLandSetId ( id ) ) ;
2018-11-10 19:00:13 +01:00
}
2018-12-01 00:27:16 +11:00
Sapphire : : LandPtr Sapphire : : World : : Manager : : HousingMgr : : getLandByOwnerId ( uint32_t id )
2018-11-10 19:00:13 +01:00
{
2018-12-22 22:25:03 +01:00
auto pDb = framework ( ) - > get < Db : : DbWorkerPool < Db : : ZoneDbConnection > > ( ) ;
2018-11-19 11:55:29 +01:00
auto res = pDb - > query ( " SELECT LandSetId, LandId FROM land WHERE OwnerId = " + std : : to_string ( id ) ) ;
if ( ! res - > next ( ) )
2018-11-10 19:00:13 +01:00
return nullptr ;
2018-11-19 11:55:29 +01:00
auto hZone = getHousingZoneByLandSetId ( res - > getUInt ( 1 ) ) ;
2018-11-10 19:00:13 +01:00
2018-11-19 11:55:29 +01:00
if ( ! hZone )
return nullptr ;
2018-11-11 14:27:39 +01:00
2018-11-19 11:55:29 +01:00
return hZone - > getLand ( res - > getUInt ( 2 ) ) ;
2018-11-10 19:00:13 +01:00
}
2018-11-13 23:46:10 +01:00
2018-12-05 16:55:14 +11:00
void Sapphire : : World : : Manager : : HousingMgr : : sendLandSignOwned ( Entity : : Player & player , const Common : : LandIdent ident )
2018-11-13 23:46:10 +01:00
{
2018-12-05 16:55:14 +11:00
player . setActiveLand ( ident . landId , ident . wardNum ) ;
2018-11-13 23:46:10 +01:00
2018-12-05 16:55:14 +11:00
auto landSetId = toLandSetId ( ident . territoryTypeId , ident . wardNum ) ;
2018-11-16 17:07:22 +01:00
auto hZone = getHousingZoneByLandSetId ( landSetId ) ;
2018-11-13 23:46:10 +01:00
if ( ! hZone )
return ;
2018-12-05 16:55:14 +11:00
auto land = hZone - > getLand ( ident . landId ) ;
2018-11-13 23:46:10 +01:00
if ( ! land )
2018-12-19 00:54:25 +11:00
return ;
2018-11-13 23:46:10 +01:00
auto landInfoSignPacket = makeZonePacket < Server : : FFXIVIpcLandInfoSign > ( player . getId ( ) ) ;
2018-11-14 10:00:16 +01:00
landInfoSignPacket - > data ( ) . houseSize = land - > getSize ( ) ;
2018-11-13 23:46:10 +01:00
landInfoSignPacket - > data ( ) . houseType = static_cast < uint8_t > ( land - > getLandType ( ) ) ;
2018-12-05 16:55:14 +11:00
landInfoSignPacket - > data ( ) . landIdent = ident ;
2018-11-27 21:45:29 +11:00
landInfoSignPacket - > data ( ) . houseIconAdd = land - > getSharing ( ) ;
2018-12-19 00:54:25 +11:00
landInfoSignPacket - > data ( ) . ownerId = player . getContentId ( ) ; // todo: should be real owner contentId, not player.contentId()
2018-11-27 21:45:29 +11:00
if ( auto house = land - > getHouse ( ) )
{
std : : strcpy ( landInfoSignPacket - > data ( ) . estateName , house - > getHouseName ( ) . c_str ( ) ) ;
std : : strcpy ( landInfoSignPacket - > data ( ) . estateGreeting , house - > getHouseGreeting ( ) . c_str ( ) ) ;
}
2018-12-19 16:03:35 +11:00
uint32_t playerId = land - > getOwnerId ( ) ;
2018-12-22 22:25:03 +01:00
std : : string playerName = framework ( ) - > get < World : : ServerMgr > ( ) - > getPlayerNameFromDb ( playerId ) ;
2018-12-19 00:54:25 +11:00
2018-11-13 23:46:10 +01:00
memcpy ( & landInfoSignPacket - > data ( ) . ownerName , playerName . c_str ( ) , playerName . size ( ) ) ;
2018-11-26 23:15:42 +01:00
2018-11-13 23:46:10 +01:00
player . queuePacket ( landInfoSignPacket ) ;
}
2018-12-05 16:55:14 +11:00
void Sapphire : : World : : Manager : : HousingMgr : : sendLandSignFree ( Entity : : Player & player , const Common : : LandIdent ident )
2018-11-13 23:46:10 +01:00
{
2018-12-05 16:55:14 +11:00
player . setActiveLand ( ident . landId , ident . wardNum ) ;
2018-11-13 23:46:10 +01:00
2018-12-05 16:55:14 +11:00
auto landSetId = toLandSetId ( ident . territoryTypeId , ident . wardNum ) ;
2018-11-16 17:07:22 +01:00
auto hZone = getHousingZoneByLandSetId ( landSetId ) ;
2018-11-13 23:46:10 +01:00
if ( ! hZone )
return ;
2018-12-05 16:55:14 +11:00
auto land = hZone - > getLand ( ident . landId ) ;
2018-11-13 23:46:10 +01:00
auto plotPricePacket = makeZonePacket < Server : : FFXIVIpcLandPriceUpdate > ( player . getId ( ) ) ;
plotPricePacket - > data ( ) . price = land - > getCurrentPrice ( ) ;
plotPricePacket - > data ( ) . timeLeft = land - > getDevaluationTime ( ) ;
player . queuePacket ( plotPricePacket ) ;
}
2018-11-15 12:40:02 +01:00
2018-12-01 00:27:16 +11:00
Sapphire : : LandPurchaseResult Sapphire : : World : : Manager : : HousingMgr : : purchaseLand ( Entity : : Player & player , uint8_t plot , uint8_t state )
2018-11-15 12:40:02 +01:00
{
auto pHousing = std : : dynamic_pointer_cast < HousingZone > ( player . getCurrentZone ( ) ) ;
auto plotPrice = pHousing - > getLand ( plot ) - > getCurrentPrice ( ) ;
auto gilAvailable = player . getCurrency ( CurrencyType : : Gil ) ;
auto pLand = pHousing - > getLand ( plot ) ;
if ( ! pLand )
return LandPurchaseResult : : ERR_INTERNAL ;
if ( pLand - > getState ( ) ! = HouseState : : forSale )
return LandPurchaseResult : : ERR_NOT_AVAILABLE ;
2018-11-20 22:52:57 +11:00
2018-11-15 12:40:02 +01:00
if ( gilAvailable < plotPrice )
return LandPurchaseResult : : ERR_NOT_ENOUGH_GIL ;
2018-11-20 22:52:57 +11:00
2018-11-15 12:40:02 +01:00
switch ( static_cast < LandPurchaseMode > ( state ) )
{
case LandPurchaseMode : : FC :
player . sendDebug ( " Free company house purchase aren't supported at this time. " ) ;
return LandPurchaseResult : : ERR_INTERNAL ;
2018-11-20 22:52:57 +11:00
2018-11-15 12:40:02 +01:00
case LandPurchaseMode : : PRIVATE :
{
auto pOldLand = getLandByOwnerId ( player . getId ( ) ) ;
if ( pOldLand )
return LandPurchaseResult : : ERR_NO_MORE_LANDS_FOR_CHAR ;
2018-11-15 22:30:59 +01:00
2018-11-15 12:40:02 +01:00
player . removeCurrency ( CurrencyType : : Gil , plotPrice ) ;
2018-12-19 16:03:35 +11:00
pLand - > setOwnerId ( player . getId ( ) ) ;
2018-11-15 12:40:02 +01:00
pLand - > setState ( HouseState : : sold ) ;
pLand - > setLandType ( Common : : LandType : : Private ) ;
2018-11-15 22:30:59 +01:00
2018-12-21 22:23:49 +11:00
player . setLandFlags ( LandFlagsSlot : : Private , 0x00 , pLand - > getLandIdent ( ) ) ;
2018-11-15 22:30:59 +01:00
2018-11-28 23:29:55 +11:00
player . sendLandFlagsSlot ( LandFlagsSlot : : Private ) ;
2018-11-15 22:30:59 +01:00
2018-11-15 12:40:02 +01:00
//pLand->setLandName( "Private Estate" + std::to_string( pHousing->getWardNum() ) + "-" + std::to_string( plot ) );
pLand - > updateLandDb ( ) ;
2018-11-15 22:30:59 +01:00
2018-11-15 12:40:02 +01:00
pHousing - > sendLandUpdate ( plot ) ;
return LandPurchaseResult : : SUCCESS ;
}
2018-11-20 22:52:57 +11:00
2018-11-15 12:40:02 +01:00
default :
return LandPurchaseResult : : ERR_INTERNAL ;
}
2018-11-20 22:52:57 +11:00
2018-11-15 12:40:02 +01:00
}
2018-12-01 00:27:16 +11:00
bool Sapphire : : World : : Manager : : HousingMgr : : relinquishLand ( Entity : : Player & player , uint8_t plot )
2018-11-17 01:16:44 +01:00
{
// TODO: Fix "permissions" being sent incorrectly
// TODO: Add checks for land state before relinquishing
auto pHousing = std : : dynamic_pointer_cast < HousingZone > ( player . getCurrentZone ( ) ) ;
auto pLand = pHousing - > getLand ( plot ) ;
auto plotMaxPrice = pLand - > getCurrentPrice ( ) ;
2018-12-19 16:03:35 +11:00
auto landOwnerId = pLand - > getOwnerId ( ) ;
2018-11-20 21:21:22 +01:00
// can't relinquish when you are not the owner
// TODO: actually use permissions here for FC houses
if ( landOwnerId ! = player . getId ( ) )
{
auto msgPkt = makeActorControl143 ( player . getId ( ) , ActorControl : : LogMsg , 3304 , 0 ) ;
player . queuePacket ( msgPkt ) ;
return false ;
}
// unable to relinquish if there is a house built
// TODO: additionally check for yard items
if ( pLand - > getHouse ( ) )
{
auto msgPkt = makeActorControl143 ( player . getId ( ) , ActorControl : : LogMsg , 3315 , 0 ) ;
player . queuePacket ( msgPkt ) ;
return false ;
}
2018-11-17 01:16:44 +01:00
pLand - > setCurrentPrice ( pLand - > getMaxPrice ( ) ) ;
2018-12-19 16:03:35 +11:00
pLand - > setOwnerId ( 0 ) ;
2018-11-17 01:16:44 +01:00
pLand - > setState ( HouseState : : forSale ) ;
pLand - > setLandType ( Common : : LandType : : none ) ;
pLand - > updateLandDb ( ) ;
2018-12-21 22:23:49 +11:00
Common : : LandIdent ident { 0xFF , 0xFF , 0xFF , 0xFF } ;
player . setLandFlags ( LandFlagsSlot : : Private , 0x00 , ident ) ;
2018-11-17 01:16:44 +01:00
2018-11-28 23:29:55 +11:00
player . sendLandFlagsSlot ( LandFlagsSlot : : Private ) ;
2018-11-17 01:16:44 +01:00
auto screenMsgPkt2 = makeActorControl143 ( player . getId ( ) , ActorControl : : LogMsg , 3351 , 0x1AA ,
2018-12-21 22:08:05 +11:00
pLand - > getLandIdent ( ) . wardNum + 1 , plot + 1 ) ;
2018-11-17 01:16:44 +01:00
player . queuePacket ( screenMsgPkt2 ) ;
pHousing - > sendLandUpdate ( plot ) ;
return true ;
}
2018-12-01 00:27:16 +11:00
void Sapphire : : World : : Manager : : HousingMgr : : sendWardLandInfo ( Entity : : Player & player , uint8_t wardId , uint16_t territoryTypeId )
2018-11-20 22:52:57 +11:00
{
auto landSetId = toLandSetId ( territoryTypeId , wardId ) ;
auto hZone = getHousingZoneByLandSetId ( landSetId ) ;
if ( ! hZone )
return ;
auto wardInfoPacket = makeZonePacket < Server : : FFXIVIpcHousingWardInfo > ( player . getId ( ) ) ;
2018-11-26 23:15:42 +01:00
wardInfoPacket - > data ( ) . landIdent . wardNum = wardId ;
wardInfoPacket - > data ( ) . landIdent . territoryTypeId = territoryTypeId ;
2018-11-20 22:52:57 +11:00
2018-12-04 22:20:41 +11:00
// todo: properly get worldId
wardInfoPacket - > data ( ) . landIdent . worldId = 67 ;
2018-11-20 22:52:57 +11:00
for ( int i = 0 ; i < 60 ; i + + )
{
auto land = hZone - > getLand ( i ) ;
assert ( land ) ;
auto & entry = wardInfoPacket - > data ( ) . houseInfoEntry [ i ] ;
2018-11-23 17:45:37 +11:00
// retail always sends the house price in this packet, even after the house has been sold
// so I guess we do the same
2018-11-20 22:52:57 +11:00
entry . housePrice = land - > getCurrentPrice ( ) ;
2018-11-23 17:45:37 +11:00
if ( land - > getState ( ) = = Common : : HouseState : : forSale )
continue ;
2018-12-04 22:20:41 +11:00
if ( auto house = land - > getHouse ( ) )
{
if ( ! house - > getHouseGreeting ( ) . empty ( ) )
entry . infoFlags | = WardlandFlags : : HasEstateGreeting ;
}
2018-11-20 22:52:57 +11:00
switch ( land - > getLandType ( ) )
{
case LandType : : FreeCompany :
2018-12-04 22:20:41 +11:00
entry . infoFlags | = Common : : WardlandFlags : : IsEstateOwned | Common : : WardlandFlags : : IsFreeCompanyEstate ;
2018-11-20 22:52:57 +11:00
// todo: send FC name
break ;
case LandType : : Private :
2018-12-04 22:20:41 +11:00
entry . infoFlags | = Common : : WardlandFlags : : IsEstateOwned ;
2018-11-20 22:52:57 +11:00
2018-12-19 16:03:35 +11:00
auto owner = land - > getOwnerId ( ) ;
2018-12-22 22:25:03 +01:00
auto playerName = framework ( ) - > get < World : : ServerMgr > ( ) - > getPlayerNameFromDb ( owner ) ;
2018-11-20 22:52:57 +11:00
memcpy ( & entry . estateOwnerName , playerName . c_str ( ) , playerName . size ( ) ) ;
break ;
}
// todo: check we have an estate message and set the flag
// todo: check if estate allows public entry
}
player . queuePacket ( wardInfoPacket ) ;
}
2018-12-04 22:20:41 +11:00
void Sapphire : : World : : Manager : : HousingMgr : : sendEstateGreeting ( Entity : : Player & player , const Common : : LandIdent ident )
{
auto landSetId = toLandSetId ( ident . territoryTypeId , ident . wardNum ) ;
auto hZone = getHousingZoneByLandSetId ( landSetId ) ;
if ( ! hZone )
return ;
auto land = hZone - > getLand ( ident . landId ) ;
if ( ! land )
return ;
auto house = land - > getHouse ( ) ;
if ( ! house )
return ;
auto greetingPacket = makeZonePacket < FFXIVIpcHousingEstateGreeting > ( player . getId ( ) ) ;
greetingPacket - > data ( ) . landIdent = ident ;
auto greeting = house - > getHouseGreeting ( ) ;
memcpy ( & greetingPacket - > data ( ) . message , greeting . c_str ( ) , greeting . size ( ) ) ;
player . queuePacket ( greetingPacket ) ;
}
2018-12-23 19:13:30 +11:00
bool Sapphire : : World : : Manager : : HousingMgr : : initHouseModels ( Entity : : Player & player , LandPtr land , uint32_t presetCatalogId )
{
auto house = land - > getHouse ( ) ;
assert ( house ) ;
auto itemMax = land - > getInventoryItemMax ( ) ;
// type, maxSize, tableName, isMultiStorage
2018-12-29 13:05:13 +11:00
auto intContainer = make_ItemContainer ( InventoryType : : HousingInteriorAppearance , itemMax . second , " houseiteminventory " , true , framework ( ) ) ;
auto extContainer = make_ItemContainer ( InventoryType : : HousingExteriorAppearance , itemMax . first , " houseiteminventory " , true , framework ( ) ) ;
2018-12-23 19:13:30 +11:00
// add containers to inv collection
auto & houseInventory = getEstateInventory ( house - > getLandIdent ( ) ) ;
houseInventory [ InventoryType : : HousingInteriorAppearance ] = intContainer ;
houseInventory [ InventoryType : : HousingExteriorAppearance ] = extContainer ;
2018-12-29 13:05:13 +11:00
auto exdData = framework ( ) - > get < Sapphire : : Data : : ExdDataGenerated > ( ) ;
2018-12-23 19:13:30 +11:00
auto preset = exdData - > get < Sapphire : : Data : : HousingPreset > ( getItemAdditionalData ( presetCatalogId ) ) ;
if ( ! preset )
return false ;
// high iq shit
auto invMap = std : : map < uint16_t , std : : map < uint32_t , int32_t > >
{
// external
{
InventoryType : : HousingExteriorAppearance ,
{
{ HouseExteriorSlot : : ExteriorRoof , preset - > exteriorRoof } ,
{ HouseExteriorSlot : : ExteriorWall , preset - > exteriorWall } ,
{ HouseExteriorSlot : : ExteriorWindow , preset - > exteriorWindow } ,
{ HouseExteriorSlot : : ExteriorDoor , preset - > exteriorDoor }
}
} ,
// internal
{
InventoryType : : HousingInteriorAppearance ,
{
// lobby/middle floor
{ HousingInteriorSlot : : InteriorWall , preset - > interiorWall } ,
{ HousingInteriorSlot : : InteriorFloor , preset - > interiorFlooring } ,
{ HousingInteriorSlot : : InteriorLight , preset - > interiorLighting } ,
// attic
{ HousingInteriorSlot : : InteriorWall_Attic , preset - > otherFloorWall } ,
{ HousingInteriorSlot : : InteriorFloor_Attic , preset - > otherFloorFlooring } ,
{ HousingInteriorSlot : : InteriorLight_Attic , preset - > otherFloorLighting } ,
// basement
{ HousingInteriorSlot : : InteriorWall_Basement , preset - > basementWall } ,
{ HousingInteriorSlot : : InteriorFloor_Basement , preset - > basementFlooring } ,
{ HousingInteriorSlot : : InteriorLight_Basement , preset - > basementLighting } ,
}
}
} ;
2018-12-29 13:05:13 +11:00
auto invMgr = framework ( ) - > get < InventoryMgr > ( ) ;
2018-12-23 19:13:30 +11:00
// create and link items
for ( auto & destContainer : invMap )
{
auto container = houseInventory [ destContainer . first ] ;
for ( auto & item : destContainer . second )
{
2018-12-25 21:40:02 +11:00
// small houses attic is just 0, ignore them
if ( item . second = = 0 )
continue ;
2018-12-23 19:13:30 +11:00
auto pItem = invMgr - > createItem ( player , item . second ) ;
container - > setItem ( item . first , pItem ) ;
}
invMgr - > saveHousingContainer ( land - > getLandIdent ( ) , container ) ;
}
// lift off
updateHouseModels ( house ) ;
return true ;
}
2018-12-23 20:54:21 +11:00
void Sapphire : : World : : Manager : : HousingMgr : : createHouse ( Sapphire : : HousePtr house ) const
{
2018-12-29 13:05:13 +11:00
auto pDb = framework ( ) - > get < Db : : DbWorkerPool < Db : : ZoneDbConnection > > ( ) ;
2018-12-23 20:54:21 +11:00
auto stmt = pDb - > getPreparedStatement ( Db : : HOUSING_HOUSE_INS ) ;
// LandSetId, HouseId, HouseName
stmt - > setUInt ( 1 , house - > getLandSetId ( ) ) ;
stmt - > setUInt ( 2 , house - > getId ( ) ) ;
stmt - > setString ( 3 , house - > getHouseName ( ) ) ;
pDb - > execute ( stmt ) ;
}
2018-12-01 00:27:16 +11:00
void Sapphire : : World : : Manager : : HousingMgr : : buildPresetEstate ( Entity : : Player & player , uint8_t plotNum , uint32_t presetItem )
2018-11-24 15:17:18 +11:00
{
auto hZone = std : : dynamic_pointer_cast < HousingZone > ( player . getCurrentZone ( ) ) ;
if ( ! hZone )
return ;
auto pLand = hZone - > getLand ( plotNum ) ;
if ( ! pLand )
return ;
// todo: when doing FC houses, look up the type from the original purchase and check perms from FC and set state accordingly
2018-12-19 16:03:35 +11:00
if ( pLand - > getOwnerId ( ) ! = player . getId ( ) )
2018-11-24 15:17:18 +11:00
return ;
// todo: check if permit is in inventory and remove one
2018-12-23 19:13:30 +11:00
// create house
auto ident = pLand - > getLandIdent ( ) ;
auto house = make_House ( getNextHouseId ( ) , pLand - > getLandSetId ( ) , ident ,
2018-12-29 13:05:13 +11:00
" Estate # " + std : : to_string ( ident . landId + 1 ) , " " , framework ( ) ) ;
2018-12-23 19:13:30 +11:00
pLand - > setHouse ( house ) ;
// create inventory items
if ( ! initHouseModels ( player , pLand , presetItem ) )
2018-11-25 01:55:53 +11:00
return ;
2018-12-23 21:00:00 +11:00
createHouse ( house ) ;
2018-11-24 15:17:18 +11:00
pLand - > setState ( HouseState : : privateHouse ) ;
pLand - > setLandType ( LandType : : Private ) ;
hZone - > sendLandUpdate ( plotNum ) ;
auto pSuccessBuildingPacket = makeActorControl142 ( player . getId ( ) , ActorControl : : BuildPresetResponse , plotNum ) ;
player . queuePacket ( pSuccessBuildingPacket ) ;
2018-11-26 23:32:22 +11:00
pLand - > updateLandDb ( ) ;
// start house built event
// CmnDefHousingBuildHouse_00149
player . eventStart ( player . getId ( ) , 0x000B0095 , Event : : EventHandler : : EventType : : Housing , 1 , 1 ) ;
2018-12-11 23:40:47 +01:00
player . playScene ( 0x000B0095 , 0 , SET_BASE | HIDE_HOTBAR , 0 , 1 , plotNum , nullptr ) ;
2018-11-26 23:32:22 +11:00
2018-12-23 19:13:30 +11:00
player . setLandFlags ( LandFlagsSlot : : Private , EstateBuilt , ident ) ;
2018-11-28 23:29:55 +11:00
player . sendLandFlagsSlot ( LandFlagsSlot : : Private ) ;
2018-11-30 22:52:08 +11:00
2018-12-25 23:43:39 +11:00
hZone - > registerEstateEntranceEObj ( plotNum ) ;
2018-11-24 15:17:18 +11:00
}
2018-11-28 21:24:00 +11:00
2018-12-05 16:55:14 +11:00
void Sapphire : : World : : Manager : : HousingMgr : : requestEstateRename ( Entity : : Player & player , const Common : : LandIdent ident )
2018-11-28 21:24:00 +11:00
{
2018-12-05 16:55:14 +11:00
auto landSetId = toLandSetId ( ident . territoryTypeId , ident . wardNum ) ;
2018-11-28 21:24:00 +11:00
auto hZone = getHousingZoneByLandSetId ( landSetId ) ;
if ( ! hZone )
return ;
2018-12-05 16:55:14 +11:00
auto land = hZone - > getLand ( ident . landId ) ;
2018-11-28 21:24:00 +11:00
auto house = land - > getHouse ( ) ;
if ( ! house )
return ;
auto landRenamePacket = makeZonePacket < Server : : FFXIVIpcLandRename > ( player . getId ( ) ) ;
2018-12-05 16:55:14 +11:00
landRenamePacket - > data ( ) . landIdent = ident ;
2018-11-28 21:24:00 +11:00
memcpy ( & landRenamePacket - > data ( ) . houseName , house - > getHouseName ( ) . c_str ( ) , 20 ) ;
player . queuePacket ( landRenamePacket ) ;
}
2018-12-05 16:55:14 +11:00
void Sapphire : : World : : Manager : : HousingMgr : : requestEstateEditGreeting ( Entity : : Player & player , const Common : : LandIdent ident )
2018-11-28 21:24:00 +11:00
{
2018-12-05 16:55:14 +11:00
auto landSetId = toLandSetId ( ident . territoryTypeId , ident . wardNum ) ;
2018-11-28 21:24:00 +11:00
auto hZone = getHousingZoneByLandSetId ( landSetId ) ;
if ( ! hZone )
return ;
2018-12-05 16:55:14 +11:00
auto land = hZone - > getLand ( ident . landId ) ;
2018-11-28 21:24:00 +11:00
if ( ! land )
return ;
auto house = land - > getHouse ( ) ;
if ( ! house )
return ;
auto estateGreetingPacket = makeZonePacket < Server : : FFXIVIpcHousingEstateGreeting > ( player . getId ( ) ) ;
2018-12-05 16:55:14 +11:00
estateGreetingPacket - > data ( ) . landIdent = ident ;
2018-11-28 21:24:00 +11:00
memcpy ( & estateGreetingPacket - > data ( ) . message , house - > getHouseGreeting ( ) . c_str ( ) , sizeof ( estateGreetingPacket - > data ( ) . message ) ) ;
player . queuePacket ( estateGreetingPacket ) ;
}
2018-11-28 21:59:28 +11:00
2018-12-05 16:55:14 +11:00
void Sapphire : : World : : Manager : : HousingMgr : : updateEstateGreeting ( Entity : : Player & player , const Common : : LandIdent ident , const std : : string & greeting )
2018-11-28 21:59:28 +11:00
{
auto landSetId = toLandSetId ( ident . territoryTypeId , ident . wardNum ) ;
auto zone = getHousingZoneByLandSetId ( landSetId ) ;
if ( ! zone )
return ;
auto land = zone - > getLand ( ident . landId ) ;
if ( ! land )
return ;
// todo: implement proper permissions checks
2018-12-19 16:03:35 +11:00
if ( land - > getOwnerId ( ) ! = player . getId ( ) )
2018-11-28 21:59:28 +11:00
return ;
auto house = land - > getHouse ( ) ;
if ( ! house )
return ;
house - > setHouseGreeting ( greeting ) ;
2018-11-28 23:29:55 +11:00
// Greeting updated.
2018-11-28 21:59:28 +11:00
player . sendLogMessage ( 3381 ) ;
}
2018-11-29 00:19:37 +11:00
2018-12-05 16:55:14 +11:00
void Sapphire : : World : : Manager : : HousingMgr : : requestEstateEditGuestAccess ( Entity : : Player & player , const Common : : LandIdent ident )
2018-11-29 00:19:37 +11:00
{
2018-12-05 16:55:14 +11:00
auto landSetId = toLandSetId ( ident . territoryTypeId , ident . wardNum ) ;
2018-11-29 00:19:37 +11:00
auto hZone = getHousingZoneByLandSetId ( landSetId ) ;
if ( ! hZone )
return ;
2018-12-05 16:55:14 +11:00
auto land = hZone - > getLand ( ident . landId ) ;
2018-11-29 00:19:37 +11:00
if ( ! land )
return ;
// todo: add proper permission check
2018-12-19 16:03:35 +11:00
if ( land - > getOwnerId ( ) ! = player . getId ( ) )
2018-11-29 00:19:37 +11:00
return ;
auto packet = makeZonePacket < FFXIVIpcHousingShowEstateGuestAccess > ( player . getId ( ) ) ;
2018-12-05 16:55:14 +11:00
packet - > data ( ) . ident = ident ;
2018-11-29 00:19:37 +11:00
player . queuePacket ( packet ) ;
}
2018-12-05 16:55:14 +11:00
2018-12-19 01:03:41 +11:00
Sapphire : : Common : : LandIdent Sapphire : : World : : Manager : : HousingMgr : : clientTriggerParamsToLandIdent ( uint32_t param11 , uint32_t param12 , bool use16bits ) const
2018-12-05 16:55:14 +11:00
{
Common : : LandIdent ident ;
ident . worldId = param11 > > 16 ;
ident . territoryTypeId = param11 & 0xFFFF ;
2018-12-19 01:03:41 +11:00
if ( use16bits )
{
ident . wardNum = param12 > > 16 ;
ident . landId = param12 & 0xFFFF ;
}
else
{
ident . wardNum = ( param12 > > 8 ) & 0xFF ;
ident . landId = param12 & 0xFF ;
}
2018-12-05 16:55:14 +11:00
return ident ;
2018-12-05 19:58:43 +11:00
}
2018-12-22 11:33:21 +11:00
void Sapphire : : World : : Manager : : HousingMgr : : sendEstateInventory ( Entity : : Player & player , uint16_t inventoryType ,
uint8_t plotNum )
2018-12-05 19:58:43 +11:00
{
Sapphire : : LandPtr targetLand ;
// plotNum will be 255 in the event that it's an internal zone
// and we have to switch up our way of getting the LandPtr
if ( plotNum = = 255 )
{
auto internalZone = std : : dynamic_pointer_cast < Territory : : Housing : : HousingInteriorTerritory > ( player . getCurrentZone ( ) ) ;
if ( ! internalZone )
return ;
2018-12-26 19:22:30 +11:00
auto ident = internalZone - > getLandIdent ( ) ;
2018-12-05 19:58:43 +11:00
auto landSetId = toLandSetId ( ident . territoryTypeId , ident . wardNum ) ;
auto exteriorZone = getHousingZoneByLandSetId ( landSetId ) ;
if ( ! exteriorZone )
return ;
targetLand = exteriorZone - > getLand ( ident . landId ) ;
}
else
{
auto zone = std : : dynamic_pointer_cast < HousingZone > ( player . getCurrentZone ( ) ) ;
if ( ! zone )
return ;
targetLand = zone - > getLand ( plotNum ) ;
}
if ( ! targetLand )
return ;
// todo: add proper permissions checks
2018-12-19 16:03:35 +11:00
if ( targetLand - > getOwnerId ( ) ! = player . getId ( ) )
2018-12-05 19:58:43 +11:00
return ;
2018-12-23 22:43:35 +11:00
auto & containers = getEstateInventory ( targetLand - > getLandIdent ( ) ) ;
2018-12-28 17:12:24 +11:00
auto needle = containers . find ( inventoryType ) ;
if ( needle = = containers . end ( ) )
return ;
2018-12-20 20:41:16 +11:00
2018-12-29 13:05:13 +11:00
auto invMgr = framework ( ) - > get < Manager : : InventoryMgr > ( ) ;
2018-12-28 17:12:24 +11:00
invMgr - > sendInventoryContainer ( player , needle - > second ) ;
2018-12-22 11:33:21 +11:00
}
2018-12-22 14:35:42 +11:00
const Sapphire : : World : : Manager : : HousingMgr : : LandSetLandCacheMap &
2018-12-22 17:25:30 +11:00
Sapphire : : World : : Manager : : HousingMgr : : getLandCacheMap ( )
2018-12-22 11:33:21 +11:00
{
return m_landCache ;
2018-12-22 14:35:42 +11:00
}
2018-12-22 17:25:30 +11:00
Sapphire : : World : : Manager : : HousingMgr : : LandIdentToInventoryContainerMap &
Sapphire : : World : : Manager : : HousingMgr : : getEstateInventories ( )
2018-12-22 14:35:42 +11:00
{
return m_estateInventories ;
}
2018-12-22 17:25:30 +11:00
Sapphire : : World : : Manager : : HousingMgr : : ContainerIdToContainerMap &
Sapphire : : World : : Manager : : HousingMgr : : getEstateInventory ( uint64_t ident )
2018-12-22 14:35:42 +11:00
{
2018-12-23 19:13:30 +11:00
return m_estateInventories [ ident ] ;
2018-12-22 14:35:42 +11:00
}
2018-12-22 17:25:30 +11:00
Sapphire : : World : : Manager : : HousingMgr : : ContainerIdToContainerMap &
Sapphire : : World : : Manager : : HousingMgr : : getEstateInventory ( Sapphire : : Common : : LandIdent ident )
2018-12-22 14:35:42 +11:00
{
auto u64ident = * reinterpret_cast < uint64_t * > ( & ident ) ;
2018-12-22 17:54:56 +11:00
return getEstateInventory ( u64ident ) ;
2018-12-22 17:22:24 +11:00
}
2018-12-23 19:13:30 +11:00
void Sapphire : : World : : Manager : : HousingMgr : : updateHouseModels ( Sapphire : : HousePtr house )
2018-12-22 17:22:24 +11:00
{
assert ( house ) ;
2018-12-23 19:13:30 +11:00
auto & containers = getEstateInventory ( house - > getLandIdent ( ) ) ;
2018-12-22 17:22:24 +11:00
2018-12-23 19:13:30 +11:00
auto extContainer = containers . find ( static_cast < uint16_t > ( InventoryType : : HousingExteriorAppearance ) ) ;
2018-12-22 17:22:24 +11:00
if ( extContainer ! = containers . end ( ) )
{
for ( auto & item : extContainer - > second - > getItemMap ( ) )
{
2018-12-28 18:45:08 +11:00
// 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 ) ,
2018-12-23 19:13:30 +11:00
getItemAdditionalData ( item . second - > getId ( ) ) , item . second - > getStain ( ) ) ;
2018-12-22 17:22:24 +11:00
}
}
2018-12-22 21:20:12 +11:00
else
{
2018-12-29 13:05:13 +11:00
framework ( ) - > get < Logger > ( ) - > error ( " Plot " + std : : to_string ( house - > getLandIdent ( ) . landId ) + " has an invalid inventory configuration for outdoor appearance. " ) ;
2018-12-22 21:20:12 +11:00
}
2018-12-22 17:22:24 +11:00
auto intContainer = containers . find ( static_cast < uint16_t > ( InventoryType : : HousingInteriorAppearance ) ) ;
if ( intContainer ! = containers . end ( ) )
{
for ( auto & item : intContainer - > second - > getItemMap ( ) )
{
2018-12-23 15:23:22 +11:00
house - > setInteriorModel ( static_cast < Common : : HousingInteriorSlot > ( item . first ) ,
2018-12-23 19:13:30 +11:00
getItemAdditionalData ( item . second - > getId ( ) ) ) ;
2018-12-22 17:22:24 +11:00
}
}
2018-12-22 21:20:12 +11:00
else
{
2018-12-29 13:05:13 +11:00
framework ( ) - > get < Logger > ( ) - > error ( " Plot " + std : : to_string ( house - > getLandIdent ( ) . landId ) + " has an invalid inventory configuration for indoor appearance. " ) ;
2018-12-22 21:20:12 +11:00
}
2018-12-22 17:54:56 +11:00
}
2018-12-23 19:13:30 +11:00
uint32_t Sapphire : : World : : Manager : : HousingMgr : : getItemAdditionalData ( uint32_t catalogId )
{
2018-12-29 13:05:13 +11:00
auto pExdData = framework ( ) - > get < Data : : ExdDataGenerated > ( ) ;
2018-12-23 19:13:30 +11:00
auto info = pExdData - > get < Sapphire : : Data : : Item > ( catalogId ) ;
return info - > additionalData ;
2018-12-25 20:12:24 +11:00
}
bool Sapphire : : World : : Manager : : HousingMgr : : isPlacedItemsInventory ( Sapphire : : Common : : InventoryType type )
{
2018-12-26 18:11:18 +11:00
return type = = InventoryType : : HousingExteriorPlacedItems | |
2018-12-25 20:12:24 +11:00
type = = InventoryType : : HousingInteriorPlacedItems1 | |
type = = InventoryType : : HousingInteriorPlacedItems2 | |
type = = InventoryType : : HousingInteriorPlacedItems3 | |
type = = InventoryType : : HousingInteriorPlacedItems4 | |
type = = InventoryType : : HousingInteriorPlacedItems5 | |
type = = InventoryType : : HousingInteriorPlacedItems6 ;
2018-12-26 18:11:18 +11:00
}
void Sapphire : : World : : Manager : : HousingMgr : : reqPlaceHousingItem ( Sapphire : : Entity : : Player & player , uint16_t landId ,
uint16_t containerId , uint16_t slotId ,
Sapphire : : Common : : FFXIVARR_POSITION3 pos ,
float rotation )
{
// retail process is:
// - unlink item from current container
// - add it to destination container
// - resend container
// - send spawn packet
// - send actrl 3f3, all params are 0
LandPtr land ;
bool isOutside = false ;
// inside housing territory
if ( auto zone = std : : dynamic_pointer_cast < HousingZone > ( player . getCurrentZone ( ) ) )
{
land = zone - > getLand ( landId ) ;
isOutside = true ;
}
2018-12-26 19:22:30 +11:00
// otherwise, inside a house. landId is 0 when inside a plot
2018-12-27 00:36:47 +11:00
else if ( auto zone = std : : dynamic_pointer_cast < Territory : : Housing : : HousingInteriorTerritory > ( player . getCurrentZone ( ) ) )
2018-12-26 18:11:18 +11:00
{
// todo: this whole process is retarded and needs to be fixed
// perhaps maintain a list of estates by ident inside housingmgr?
2018-12-26 19:22:30 +11:00
auto ident = zone - > getLandIdent ( ) ;
2018-12-26 18:11:18 +11:00
auto landSet = toLandSetId ( ident . territoryTypeId , ident . wardNum ) ;
2018-12-27 00:36:47 +11:00
land = getHousingZoneByLandSetId ( landSet ) - > getLand ( ident . landId ) ;
2018-12-26 18:11:18 +11:00
}
// wtf?
else
return ;
if ( ! land )
return ;
// todo: add proper permissions checks
if ( land - > getOwnerId ( ) ! = player . getId ( ) )
return ;
2018-12-27 15:52:48 +11:00
// todo: check item position and make sure it's not outside the plot
// retail uses a radius based check
2018-12-26 18:11:18 +11:00
// unlink item
Inventory : : HousingItemPtr item ;
if ( containerId = = InventoryType : : Bag0 | |
containerId = = InventoryType : : Bag1 | |
containerId = = InventoryType : : Bag2 | |
containerId = = InventoryType : : Bag3 )
{
auto tmpItem = player . dropInventoryItem ( static_cast < Common : : InventoryType > ( containerId ) , slotId ) ;
2018-12-29 13:05:13 +11:00
item = Inventory : : make_HousingItem ( tmpItem - > getUId ( ) , tmpItem - > getId ( ) , framework ( ) ) ;
2018-12-26 18:11:18 +11:00
// set params
2018-12-26 19:22:30 +11:00
item - > setPos ( {
Util : : floatToUInt16 ( pos . x ) ,
Util : : floatToUInt16 ( pos . y ) ,
Util : : floatToUInt16 ( pos . z )
} ) ;
2018-12-26 18:11:18 +11:00
item - > setRot ( Util : : floatToUInt16Rot ( rotation ) ) ;
}
else
{
player . sendUrgent ( " The inventory you are using to place an item is not supported. " ) ;
return ;
}
auto ident = land - > getLandIdent ( ) ;
2018-12-27 22:28:31 +11:00
bool status = false ;
2018-12-26 18:11:18 +11:00
if ( isOutside )
2018-12-27 22:28:31 +11:00
status = placeExternalItem ( player , item , ident ) ;
2018-12-26 18:11:18 +11:00
else
2018-12-27 22:28:31 +11:00
status = placeInteriorItem ( player , item ) ;
if ( status )
player . queuePacket ( Server : : makeActorControl143 ( player . getId ( ) , 0x3f3 ) ) ;
else
player . sendUrgent ( " An internal error occurred when placing the item. " ) ;
2018-12-26 18:11:18 +11:00
}
bool Sapphire : : World : : Manager : : HousingMgr : : placeExternalItem ( Entity : : Player & player ,
Inventory : : HousingItemPtr item ,
Common : : LandIdent ident )
{
2018-12-29 13:05:13 +11:00
auto invMgr = framework ( ) - > get < InventoryMgr > ( ) ;
2018-12-26 18:11:18 +11:00
auto & container = getEstateInventory ( ident ) [ InventoryType : : HousingExteriorPlacedItems ] ;
auto freeSlot = container - > getFreeSlot ( ) ;
// todo: what happens when this fails? at the moment the player will just lose the item
if ( freeSlot = = - 1 )
return false ;
// add item to inv
container - > setItem ( freeSlot , item ) ;
// we need to save the item again as removing it from the container on the player will remove it from charaglobalitem
// todo: this needs to be handled a bit better as it might be possible to overwrite another item that is created in the meantime
invMgr - > saveItem ( player , item ) ;
invMgr - > sendInventoryContainer ( player , container ) ;
invMgr - > saveHousingContainer ( ident , container ) ;
invMgr - > updateHousingItemPosition ( item ) ;
// add to zone and spawn
auto zone = std : : dynamic_pointer_cast < HousingZone > ( player . getCurrentZone ( ) ) ;
2018-12-26 19:22:30 +11:00
assert ( zone ) ;
2018-12-26 18:11:18 +11:00
2018-12-27 22:28:31 +11:00
zone - > spawnYardObject ( ident . landId , freeSlot , * item ) ;
2018-12-26 18:11:18 +11:00
2018-12-26 19:22:30 +11:00
return true ;
}
bool Sapphire : : World : : Manager : : HousingMgr : : placeInteriorItem ( Entity : : Player & player ,
Inventory : : HousingItemPtr item )
{
2018-12-29 13:05:13 +11:00
auto invMgr = framework ( ) - > get < InventoryMgr > ( ) ;
2018-12-26 19:22:30 +11:00
auto zone = std : : dynamic_pointer_cast < Territory : : Housing : : HousingInteriorTerritory > ( player . getCurrentZone ( ) ) ;
assert ( zone ) ;
auto ident = zone - > getLandIdent ( ) ;
2018-12-27 15:52:48 +11:00
auto & containers = getEstateInventory ( ident ) ;
2018-12-26 19:22:30 +11:00
// find first free container
uint8_t containerIdx = 0 ;
2018-12-27 13:33:29 +11:00
for ( auto containerId : m_internalPlacedItemContainers )
2018-12-26 19:22:30 +11:00
{
2018-12-27 15:52:48 +11:00
auto needle = containers . find ( containerId ) ;
if ( needle = = containers . end ( ) )
continue ;
2018-12-26 19:22:30 +11:00
2018-12-27 15:52:48 +11:00
auto container = needle - > second ;
2018-12-26 19:22:30 +11:00
auto freeSlot = container - > getFreeSlot ( ) ;
if ( freeSlot = = - 1 )
{
containerIdx + + ;
continue ;
}
// have a free slot
container - > setItem ( freeSlot , item ) ;
// todo: see comment above in placeExternalItem where the same func is called
invMgr - > saveItem ( player , item ) ;
// resend container
invMgr - > sendInventoryContainer ( player , container ) ;
invMgr - > saveHousingContainer ( ident , container ) ;
invMgr - > updateHousingItemPosition ( item ) ;
2018-12-26 22:39:00 +11:00
auto zone = std : : dynamic_pointer_cast < Territory : : Housing : : HousingInteriorTerritory > ( player . getCurrentZone ( ) ) ;
assert ( zone ) ;
2018-12-27 22:28:31 +11:00
zone - > spawnHousingObject ( containerIdx , freeSlot , containerId , item ) ;
2018-12-26 22:39:00 +11:00
return true ;
2018-12-26 19:22:30 +11:00
}
2018-12-26 22:39:00 +11:00
return false ;
}
2018-12-27 22:28:31 +11:00
Sapphire : : Common : : HousingObject Sapphire : : World : : Manager : : HousingMgr : : getYardObjectForItem ( Inventory : : HousingItemPtr item ) const
2018-12-26 22:39:00 +11:00
{
2018-12-27 22:28:31 +11:00
Sapphire : : Common : : HousingObject obj { } ;
2018-12-26 22:39:00 +11:00
obj . pos = item - > getPos ( ) ;
obj . itemRotation = item - > getRot ( ) ;
obj . itemId = item - > getAdditionalData ( ) ;
2018-12-26 19:22:30 +11:00
2018-12-26 22:39:00 +11:00
return obj ;
2018-12-27 01:09:33 +11:00
}
void Sapphire : : World : : Manager : : HousingMgr : : sendInternalEstateInventoryBatch ( Sapphire : : Entity : : Player & player ,
bool storeroom )
{
auto zone = std : : dynamic_pointer_cast < Territory : : Housing : : HousingInteriorTerritory > ( player . getCurrentZone ( ) ) ;
if ( ! zone )
return ;
2018-12-28 02:17:29 +11:00
// todo: perms check
2018-12-28 11:49:12 +11:00
Inventory : : InventoryTypeList containerIds ;
2018-12-27 01:09:33 +11:00
2018-12-27 13:33:29 +11:00
if ( storeroom )
containerIds = m_internalStoreroomContainers ;
2018-12-27 01:09:33 +11:00
else
2018-12-27 13:33:29 +11:00
containerIds = m_internalPlacedItemContainers ;
2018-12-27 01:09:33 +11:00
2018-12-29 13:05:13 +11:00
auto invMgr = framework ( ) - > get < Manager : : InventoryMgr > ( ) ;
2018-12-27 01:09:33 +11:00
auto & containers = getEstateInventory ( zone - > getLandIdent ( ) ) ;
for ( auto containerId : containerIds )
{
auto container = containers . find ( containerId ) ;
if ( container = = containers . end ( ) )
break ;
invMgr - > sendInventoryContainer ( player , container - > second ) ;
}
2018-12-27 15:52:48 +11:00
}
void Sapphire : : World : : Manager : : HousingMgr : : reqMoveHousingItem ( Entity : : Player & player ,
Common : : LandIdent ident , uint16_t slot ,
Common : : FFXIVARR_POSITION3 pos , float rot )
{
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 ;
2018-12-27 17:12:01 +11:00
// todo: what happens when either of these fail? how does the server let the client know that the moment failed
// as is, if it does fail, the client will be locked and unable to move any item until reentering the territory
if ( auto terri = std : : dynamic_pointer_cast < Territory : : Housing : : HousingInteriorTerritory > ( player . getCurrentZone ( ) ) )
{
moveInternalItem ( player , ident , * terri , slot , pos , rot ) ;
}
else if ( auto terri = std : : dynamic_pointer_cast < HousingZone > ( player . getCurrentZone ( ) ) )
{
2018-12-27 22:28:31 +11:00
moveExternalItem ( player , ident , slot , * terri , pos , rot ) ;
2018-12-27 17:12:01 +11:00
}
}
bool Sapphire : : World : : Manager : : HousingMgr : : moveInternalItem ( Entity : : Player & player , Common : : LandIdent ident ,
Territory : : Housing : : HousingInteriorTerritory & terri , uint16_t slot ,
Common : : FFXIVARR_POSITION3 pos , float rot )
{
auto containerIdx = static_cast < uint16_t > ( slot / 50 ) ;
auto slotIdx = slot % 50 ;
uint16_t containerId = 0 ;
try
{
containerId = m_internalPlacedItemContainers . at ( containerIdx ) ;
}
catch ( const std : : out_of_range & ex )
{
return false ;
}
auto & containers = getEstateInventory ( ident ) ;
auto needle = containers . find ( containerId ) ;
if ( needle = = containers . end ( ) )
return false ;
auto container = needle - > second ;
2018-12-27 15:52:48 +11:00
2018-12-27 17:12:01 +11:00
auto item = std : : dynamic_pointer_cast < Inventory : : HousingItem > ( container - > getItem ( slotIdx ) ) ;
if ( ! item )
return false ;
item - > setPos ( {
Util : : floatToUInt16 ( pos . x ) ,
Util : : floatToUInt16 ( pos . y ) ,
Util : : floatToUInt16 ( pos . z )
} ) ;
item - > setRot ( Util : : floatToUInt16Rot ( rot ) ) ;
// save
2018-12-29 13:05:13 +11:00
auto invMgr = framework ( ) - > get < InventoryMgr > ( ) ;
2018-12-27 17:12:01 +11:00
invMgr - > updateHousingItemPosition ( item ) ;
2018-12-28 22:50:46 +11:00
terri . updateHousingObjectPosition ( player , slot , item - > getPos ( ) , item - > getRot ( ) ) ;
2018-12-27 17:12:01 +11:00
// send confirmation to player
uint32_t param1 = ( ident . landId < < 16 ) | containerId ;
player . queuePacket ( Server : : makeActorControl143 ( player . getId ( ) , ActorControl : : HousingItemMoveConfirm , param1 , slotIdx ) ) ;
return true ;
}
bool Sapphire : : World : : Manager : : HousingMgr : : moveExternalItem ( Entity : : Player & player ,
Common : : LandIdent ident , uint16_t slot ,
2018-12-27 22:28:31 +11:00
Sapphire : : HousingZone & terri , Common : : FFXIVARR_POSITION3 pos ,
float rot )
2018-12-27 17:12:01 +11:00
{
2018-12-27 22:28:31 +11:00
auto land = terri . getLand ( ident . landId ) ;
// todo: add proper perms check
if ( land - > getOwnerId ( ) ! = player . getId ( ) )
return false ;
auto & containers = getEstateInventory ( ident ) ;
auto needle = containers . find ( InventoryType : : HousingExteriorPlacedItems ) ;
if ( needle = = containers . end ( ) )
return false ;
auto container = needle - > second ;
auto item = std : : dynamic_pointer_cast < Inventory : : HousingItem > ( container - > getItem ( slot ) ) ;
if ( ! item )
return false ;
item - > setPos ( {
Util : : floatToUInt16 ( pos . x ) ,
Util : : floatToUInt16 ( pos . y ) ,
Util : : floatToUInt16 ( pos . z )
} ) ;
item - > setRot ( Util : : floatToUInt16Rot ( rot ) ) ;
2018-12-29 13:05:13 +11:00
auto invMgr = framework ( ) - > get < InventoryMgr > ( ) ;
2018-12-27 22:28:31 +11:00
invMgr - > updateHousingItemPosition ( item ) ;
2018-12-27 23:48:55 +11:00
terri . updateYardObjectPos ( player , slot , ident . landId , * item ) ;
2018-12-27 22:28:31 +11:00
2018-12-27 23:48:55 +11:00
uint32_t param1 = ( ident . landId < < 16 ) | InventoryType : : HousingExteriorPlacedItems ;
player . queuePacket ( Server : : makeActorControl143 ( player . getId ( ) , ActorControl : : HousingItemMoveConfirm , param1 , slot ) ) ;
2018-12-27 22:28:31 +11:00
2018-12-27 17:12:01 +11:00
return true ;
2018-12-28 02:17:29 +11:00
}
void Sapphire : : World : : Manager : : HousingMgr : : reqRemoveHousingItem ( Sapphire : : Entity : : Player & player , uint16_t plot ,
uint16_t containerId , uint16_t slot ,
bool sendToStoreroom )
{
if ( auto terri = std : : dynamic_pointer_cast < Territory : : Housing : : HousingInteriorTerritory > ( player . getCurrentZone ( ) ) )
{
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 ;
removeInternalItem ( player , * terri , containerId , slot , sendToStoreroom ) ;
}
else if ( auto terri = std : : dynamic_pointer_cast < HousingZone > ( player . getCurrentZone ( ) ) )
{
auto land = terri - > getLand ( plot ) ;
if ( ! land )
return ;
if ( land - > getOwnerId ( ) ! = player . getId ( ) )
return ;
2018-12-28 20:10:07 +11:00
auto containerType = static_cast < Common : : InventoryType > ( containerId ) ;
removeExternalItem ( player , * terri , * land , containerType , slot , sendToStoreroom ) ;
2018-12-28 02:17:29 +11:00
}
}
bool Sapphire : : World : : Manager : : HousingMgr : : removeInternalItem ( Entity : : Player & player ,
Territory : : Housing : : HousingInteriorTerritory & terri ,
uint16_t containerId , uint16_t slotId ,
bool sendToStoreroom )
{
auto & containers = getEstateInventory ( terri . getLandIdent ( ) ) ;
// validate the container id first
2018-12-28 20:10:07 +11:00
// we also need the idx of the container so we can get the slot offset
2018-12-28 02:17:29 +11:00
bool foundContainer = false ;
uint8_t containerIdx = 0 ;
for ( auto cId : m_internalPlacedItemContainers )
{
if ( containerId = = cId )
{
foundContainer = true ;
break ;
}
containerIdx + + ;
}
if ( ! foundContainer )
return false ;
auto needle = containers . find ( containerId ) ;
if ( needle = = containers . end ( ) )
return false ;
auto container = needle - > second ;
auto item = std : : dynamic_pointer_cast < Inventory : : HousingItem > ( container - > getItem ( slotId ) ) ;
if ( ! item )
return false ;
if ( ! sendToStoreroom )
{
// make sure the player has a free inv slot first
2018-12-28 11:49:12 +11:00
Inventory : : InventoryContainerPair containerPair ;
2018-12-28 02:17:29 +11:00
if ( ! player . getFreeInventoryContainerSlot ( containerPair ) )
return false ;
2018-12-29 13:05:13 +11:00
auto invMgr = framework ( ) - > get < InventoryMgr > ( ) ;
2018-12-28 02:17:29 +11:00
// remove it from housing inventory
container - > removeItem ( slotId ) ;
invMgr - > sendInventoryContainer ( player , container ) ;
invMgr - > removeHousingItemPosition ( * item ) ;
invMgr - > removeItemFromHousingContainer ( terri . getLandIdent ( ) , containerId , slotId ) ;
// add to player inv
player . insertInventoryItem ( containerPair . first , containerPair . second , item ) ;
// todo: set item as bound/unsellable/untradable
2018-12-28 11:49:12 +11:00
}
else
{
ItemContainerPtr freeContainer ;
Inventory : : InventoryContainerPair freeSlotPair ;
freeContainer = getFreeEstateInventorySlot ( terri . getLandIdent ( ) , freeSlotPair , m_internalStoreroomContainers ) ;
if ( ! freeContainer )
return false ;
2018-12-28 10:17:05 +11:00
2018-12-29 13:05:13 +11:00
auto invMgr = framework ( ) - > get < InventoryMgr > ( ) ;
2018-12-28 02:17:29 +11:00
2018-12-28 11:49:12 +11:00
container - > removeItem ( slotId ) ;
invMgr - > sendInventoryContainer ( player , container ) ;
invMgr - > removeHousingItemPosition ( * item ) ;
invMgr - > removeItemFromHousingContainer ( terri . getLandIdent ( ) , containerId , slotId ) ;
freeContainer - > setItem ( slotId , item ) ;
invMgr - > sendInventoryContainer ( player , freeContainer ) ;
invMgr - > saveHousingContainer ( terri . getLandIdent ( ) , freeContainer ) ;
2018-12-28 02:17:29 +11:00
}
2018-12-28 11:49:12 +11:00
// despawn
auto arraySlot = ( containerIdx * 50 ) + slotId ;
terri . removeHousingObject ( arraySlot ) ;
2018-12-28 02:17:29 +11:00
return true ;
}
2018-12-28 11:49:12 +11:00
bool Sapphire : : World : : Manager : : HousingMgr : : removeExternalItem ( Entity : : Player & player , HousingZone & terri , Land & land ,
2018-12-28 20:10:07 +11:00
Common : : InventoryType containerType , uint16_t slotId ,
bool sendToStoreroom )
2018-12-28 11:49:12 +11:00
{
auto & containers = getEstateInventory ( land . getLandIdent ( ) ) ;
2018-12-28 20:10:07 +11:00
auto needle = containers . find ( containerType ) ;
if ( needle = = containers . end ( ) )
return false ;
auto & sourceContainer = needle - > second ;
2018-12-28 11:49:12 +11:00
2018-12-28 20:10:07 +11:00
auto item = std : : dynamic_pointer_cast < Inventory : : HousingItem > ( sourceContainer - > getItem ( slotId ) ) ;
2018-12-28 11:49:12 +11:00
if ( ! item )
return false ;
2018-12-29 13:05:13 +11:00
auto invMgr = framework ( ) - > get < InventoryMgr > ( ) ;
2018-12-28 11:49:12 +11:00
if ( sendToStoreroom )
{
auto & storeroomContainer = containers [ InventoryType : : HousingExteriorStoreroom ] ;
auto freeSlot = storeroomContainer - > getFreeSlot ( ) ;
if ( freeSlot = = - 1 )
return false ;
2018-12-28 20:10:07 +11:00
sourceContainer - > removeItem ( slotId ) ;
invMgr - > sendInventoryContainer ( player , sourceContainer ) ;
2018-12-28 11:49:12 +11:00
invMgr - > removeHousingItemPosition ( * item ) ;
2018-12-28 20:10:07 +11:00
invMgr - > removeItemFromHousingContainer ( land . getLandIdent ( ) , sourceContainer - > getId ( ) , slotId ) ;
2018-12-28 11:49:12 +11:00
storeroomContainer - > setItem ( freeSlot , item ) ;
invMgr - > sendInventoryContainer ( player , storeroomContainer ) ;
invMgr - > saveHousingContainer ( land . getLandIdent ( ) , storeroomContainer ) ;
}
else
{
Inventory : : InventoryContainerPair containerPair ;
if ( ! player . getFreeInventoryContainerSlot ( containerPair ) )
return false ;
// remove from housing inv
2018-12-28 20:10:07 +11:00
sourceContainer - > removeItem ( slotId ) ;
invMgr - > sendInventoryContainer ( player , sourceContainer ) ;
2018-12-28 11:49:12 +11:00
invMgr - > removeHousingItemPosition ( * item ) ;
2018-12-28 20:10:07 +11:00
invMgr - > removeItemFromHousingContainer ( land . getLandIdent ( ) , sourceContainer - > getId ( ) , slotId ) ;
2018-12-28 11:49:12 +11:00
// add to player inv
player . insertInventoryItem ( containerPair . first , containerPair . second , item ) ;
}
terri . despawnYardObject ( land . getLandIdent ( ) . landId , slotId ) ;
2018-12-28 17:12:24 +11:00
2018-12-28 11:49:12 +11:00
return true ;
}
Sapphire : : ItemContainerPtr Sapphire : : World : : Manager : : HousingMgr : : getFreeEstateInventorySlot ( Common : : LandIdent ident ,
Inventory : : InventoryContainerPair & pair ,
Inventory : : InventoryTypeList bagList )
2018-12-28 02:17:29 +11:00
{
2018-12-28 11:49:12 +11:00
auto & estateContainers = getEstateInventory ( ident ) ;
for ( auto bag : bagList )
{
auto needle = estateContainers . find ( bag ) ;
if ( needle = = estateContainers . end ( ) )
continue ;
auto container = needle - > second ;
auto freeSlot = container - > getFreeSlot ( ) ;
if ( freeSlot = = - 1 )
continue ;
pair = std : : make_pair ( bag , freeSlot ) ;
return container ;
}
2018-12-28 02:17:29 +11:00
2018-12-28 11:49:12 +11:00
return nullptr ;
2018-12-28 18:45:08 +11:00
}
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 ;
2018-12-29 13:05:13 +11:00
auto invMgr = framework ( ) - > get < InventoryMgr > ( ) ;
2018-12-28 18:45:08 +11:00
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 ;
2018-12-29 13:05:13 +11:00
auto invMgr = framework ( ) - > get < InventoryMgr > ( ) ;
2018-12-28 18:45:08 +11:00
invMgr - > sendInventoryContainer ( player , needle - > second ) ;
auto pkt = Server : : makeActorControl143 ( player . getId ( ) , Network : : ActorControl : : ShowEstateInternalAppearanceUI ) ;
player . queuePacket ( pkt ) ;
2018-12-23 19:13:30 +11:00
}