2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
# include <StdAfx.h>
2018-03-29 17:01:57 -04:00
# include "Container.h"
# include "World.h"
# include "ObjectMsgs.h"
# include "ChatMsgs.h"
# include "Player.h"
# include "WeenieFactory.h"
# include "WorldLandBlock.h"
# include "Config.h"
2019-07-07 20:56:15 +00:00
# include "SpellcastingManager.h"
2018-03-29 17:01:57 -04:00
CContainerWeenie : : CContainerWeenie ( )
{
2019-07-07 20:56:15 +00:00
for ( uint32_t i = 0 ; i < MAX_WIELDED_COMBAT ; i + + )
2018-07-12 14:41:21 -07:00
m_WieldedCombat [ i ] = NULL ;
2018-03-29 17:01:57 -04:00
}
CContainerWeenie : : ~ CContainerWeenie ( )
{
2019-07-07 20:56:15 +00:00
for ( uint32_t i = 0 ; i < MAX_WIELDED_COMBAT ; i + + )
2018-07-12 14:41:21 -07:00
m_WieldedCombat [ i ] = NULL ;
2018-03-29 17:01:57 -04:00
for ( auto item : m_Wielded )
{
2018-07-12 14:41:21 -07:00
g_pWorld - > RemoveEntity ( item ) ;
2018-03-29 17:01:57 -04:00
}
m_Wielded . clear ( ) ;
for ( auto item : m_Items )
{
2018-07-12 14:41:21 -07:00
g_pWorld - > RemoveEntity ( item ) ;
2018-03-29 17:01:57 -04:00
}
m_Items . clear ( ) ;
for ( auto container : m_Packs )
{
2018-07-12 14:41:21 -07:00
g_pWorld - > RemoveEntity ( container ) ;
2018-03-29 17:01:57 -04:00
}
m_Packs . clear ( ) ;
}
void CContainerWeenie : : ApplyQualityOverrides ( )
{
CWeenieObject : : ApplyQualityOverrides ( ) ;
if ( m_Qualities . GetInt ( ITEM_TYPE_INT , 0 ) & TYPE_CONTAINER )
{
if ( GetItemsCapacity ( ) < 0 )
{
m_Qualities . SetInt ( ITEMS_CAPACITY_INT , 120 ) ;
}
if ( GetContainersCapacity ( ) < 0 )
{
m_Qualities . SetInt ( CONTAINERS_CAPACITY_INT , 10 ) ;
}
}
}
void CContainerWeenie : : PostSpawn ( )
{
CWeenieObject : : PostSpawn ( ) ;
m_bInitiallyLocked = IsLocked ( ) ;
}
int CContainerWeenie : : GetItemsCapacity ( )
{
return InqIntQuality ( ITEMS_CAPACITY_INT , 0 ) ;
}
int CContainerWeenie : : GetContainersCapacity ( )
{
return InqIntQuality ( CONTAINERS_CAPACITY_INT , 0 ) ;
}
2019-07-07 20:56:15 +00:00
CContainerWeenie * CContainerWeenie : : FindContainer ( uint32_t container_id )
2018-03-29 17:01:57 -04:00
{
if ( GetID ( ) = = container_id )
2018-07-12 14:41:21 -07:00
return this ;
2018-03-29 17:01:57 -04:00
for ( auto pack : m_Packs )
{
2018-07-12 14:41:21 -07:00
if ( pack - > GetID ( ) = = container_id )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
if ( CContainerWeenie * packContainer = pack - > AsContainer ( ) )
2018-03-29 17:01:57 -04:00
{
return packContainer ;
}
}
}
2018-07-12 14:41:21 -07:00
if ( CWeenieObject * externalObject = g_pWorld - > FindObject ( container_id ) )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
if ( CContainerWeenie * externalContainer = externalObject - > AsContainer ( ) )
2018-03-29 17:01:57 -04:00
{
if ( externalContainer - > _openedById = = GetTopLevelID ( ) )
{
return externalContainer ;
}
}
}
return NULL ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * CContainerWeenie : : GetWieldedCombat ( COMBAT_USE combatUse )
2018-03-29 17:01:57 -04:00
{
// The first entry is "Undef" so we omit that.
int index = combatUse - 1 ;
2018-11-09 13:39:05 -06:00
if ( index < 0 | | index > MAX_WIELDED_COMBAT )
2018-03-29 17:01:57 -04:00
return NULL ;
2018-11-09 13:39:05 -06:00
// OFFHAND is the shield slot
if ( combatUse = = COMBAT_USE_OFFHAND )
index = COMBAT_USE_SHIELD - 1 ;
2018-07-12 14:41:21 -07:00
return m_WieldedCombat [ index ] ;
2018-03-29 17:01:57 -04:00
}
2018-07-12 14:41:21 -07:00
void CContainerWeenie : : SetWieldedCombat ( CWeenieObject * wielded , COMBAT_USE combatUse )
2018-03-29 17:01:57 -04:00
{
// The first entry is "Undef" so we omit that.
int index = combatUse - 1 ;
2018-11-09 13:39:05 -06:00
if ( index < 0 | | index > MAX_WIELDED_COMBAT )
2018-03-29 17:01:57 -04:00
return ;
2018-11-09 13:39:05 -06:00
// OFFHAND is the shield slot
if ( combatUse = = COMBAT_USE_OFFHAND )
index = COMBAT_USE_SHIELD - 1 ;
2018-03-29 17:01:57 -04:00
m_WieldedCombat [ index ] = wielded ;
}
2020-09-15 00:20:23 +00:00
bool CContainerWeenie : : HasWielded ( )
{
CWeenieObject * wielded = GetWieldedCaster ( ) ;
if ( wielded )
return true ;
wielded = GetWieldedMelee ( ) ;
if ( wielded )
return true ;
wielded = GetWieldedMissile ( ) ;
if ( wielded )
return true ;
wielded = GetWieldedTwoHanded ( ) ;
if ( wielded )
return true ;
wielded = GetWieldedShield ( ) ;
if ( wielded )
return true ;
return false ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * CContainerWeenie : : GetWieldedMelee ( )
2018-03-29 17:01:57 -04:00
{
return GetWieldedCombat ( COMBAT_USE_MELEE ) ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * CContainerWeenie : : GetWieldedMissile ( )
2018-03-29 17:01:57 -04:00
{
return GetWieldedCombat ( COMBAT_USE_MISSILE ) ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * CContainerWeenie : : GetWieldedAmmo ( )
2018-03-29 17:01:57 -04:00
{
return GetWieldedCombat ( COMBAT_USE_AMMO ) ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * CContainerWeenie : : GetWieldedShield ( )
2018-03-29 17:01:57 -04:00
{
return GetWieldedCombat ( COMBAT_USE_SHIELD ) ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * CContainerWeenie : : GetWieldedTwoHanded ( )
2018-03-29 17:01:57 -04:00
{
return GetWieldedCombat ( COMBAT_USE_TWO_HANDED ) ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * CContainerWeenie : : GetWieldedCaster ( )
2018-03-29 17:01:57 -04:00
{
for ( auto item : m_Wielded )
{
2018-07-12 14:41:21 -07:00
if ( item - > AsCaster ( ) )
return item ;
2018-03-29 17:01:57 -04:00
}
return NULL ;
}
2019-07-07 20:56:15 +00:00
void CContainerWeenie : : Container_GetWieldedByMask ( std : : list < CWeenieObject * > & wielded , uint32_t inv_loc_mask )
2018-03-29 17:01:57 -04:00
{
for ( auto item : m_Wielded )
{
2018-07-12 14:41:21 -07:00
if ( item - > InqIntQuality ( CURRENT_WIELDED_LOCATION_INT , 0 , TRUE ) & inv_loc_mask )
wielded . push_back ( item ) ;
2018-03-29 17:01:57 -04:00
}
}
2018-07-12 14:41:21 -07:00
CWeenieObject * CContainerWeenie : : GetWielded ( INVENTORY_LOC slot )
2018-03-29 17:01:57 -04:00
{
for ( auto item : m_Wielded )
{
2018-07-12 14:41:21 -07:00
if ( item - > InqIntQuality ( CURRENT_WIELDED_LOCATION_INT , 0 , TRUE ) = = slot )
return item ;
2018-03-29 17:01:57 -04:00
}
return NULL ;
}
2018-07-12 14:41:21 -07:00
void CContainerWeenie : : ReleaseContainedItemRecursive ( CWeenieObject * item )
2018-03-29 17:01:57 -04:00
{
if ( ! item )
return ;
2019-07-07 20:56:15 +00:00
for ( uint32_t i = 0 ; i < MAX_WIELDED_COMBAT ; i + + )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
if ( item = = m_WieldedCombat [ i ] )
m_WieldedCombat [ i ] = NULL ;
2018-03-29 17:01:57 -04:00
}
2018-07-12 14:41:21 -07:00
for ( std : : vector < CWeenieObject * > : : iterator equipmentIterator = m_Wielded . begin ( ) ; equipmentIterator ! = m_Wielded . end ( ) ; )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
if ( * equipmentIterator ! = item )
2018-03-29 17:01:57 -04:00
{
equipmentIterator + + ;
continue ;
}
equipmentIterator = m_Wielded . erase ( equipmentIterator ) ;
}
2018-07-12 14:41:21 -07:00
for ( std : : vector < CWeenieObject * > : : iterator itemIterator = m_Items . begin ( ) ; itemIterator ! = m_Items . end ( ) ; )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
if ( * itemIterator ! = item )
2018-03-29 17:01:57 -04:00
{
itemIterator + + ;
continue ;
}
itemIterator = m_Items . erase ( itemIterator ) ;
}
2018-07-12 14:41:21 -07:00
for ( std : : vector < CWeenieObject * > : : iterator packIterator = m_Packs . begin ( ) ; packIterator ! = m_Packs . end ( ) ; )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
CWeenieObject * pack = * packIterator ;
2018-03-29 17:01:57 -04:00
if ( pack ! = item )
{
pack - > ReleaseContainedItemRecursive ( item ) ;
packIterator + + ;
continue ;
}
packIterator = m_Packs . erase ( packIterator ) ;
}
if ( item - > GetContainerID ( ) = = GetID ( ) )
{
item - > m_Qualities . SetInstanceID ( CONTAINER_IID , 0 ) ;
}
if ( item - > GetWielderID ( ) = = GetID ( ) )
{
item - > m_Qualities . SetInstanceID ( WIELDER_IID , 0 ) ;
}
item - > RecacheHasOwner ( ) ;
}
2019-07-07 20:56:15 +00:00
BOOL CContainerWeenie : : Container_CanEquip ( CWeenieObject * item , uint32_t location )
2018-03-29 17:01:57 -04:00
{
if ( ! item )
return FALSE ;
2018-11-09 13:39:05 -06:00
int possible = item - > InqIntQuality ( LOCATIONS_INT , 0 , TRUE ) ;
// weapons (right-hand) can go in the shield (left-hand) slot, too
if ( ( possible & location ) = = 0 & & ! ( location = = SHIELD_LOC & & possible = = MELEE_WEAPON_LOC ) )
2018-03-29 17:01:57 -04:00
return FALSE ;
2019-01-06 23:58:55 -06:00
// Don't check Valid Wield Location for Dual Wield
if ( ! ( location = = SHIELD_LOC & & possible = = MELEE_WEAPON_LOC ) )
{
if ( ! item - > IsValidWieldLocation ( location ) )
return FALSE ;
}
2018-11-09 13:39:05 -06:00
2018-03-29 17:01:57 -04:00
for ( auto wielded : m_Wielded )
{
2018-07-12 14:41:21 -07:00
if ( wielded = = item )
2018-03-29 17:01:57 -04:00
return TRUE ;
2018-07-12 14:41:21 -07:00
if ( ! wielded - > CanEquipWith ( item , location ) )
2018-03-29 17:01:57 -04:00
return FALSE ;
}
return TRUE ;
}
2019-07-07 20:56:15 +00:00
void CContainerWeenie : : Container_EquipItem ( uint32_t dwCell , CWeenieObject * item , uint32_t inv_loc , uint32_t child_location , uint32_t placement )
2018-03-29 17:01:57 -04:00
{
2018-11-09 13:39:05 -06:00
int combatUse = item - > InqIntQuality ( COMBAT_USE_INT , 0 , TRUE ) ;
if ( combatUse )
{
2018-11-15 23:24:23 -06:00
if ( combatUse = = COMBAT_USE_MELEE & & placement = = LeftWeapon )
2018-11-09 13:39:05 -06:00
combatUse = COMBAT_USE_OFFHAND ;
2018-03-29 17:01:57 -04:00
SetWieldedCombat ( item , ( COMBAT_USE ) combatUse ) ;
2018-11-09 13:39:05 -06:00
}
2018-03-29 17:01:57 -04:00
bool bAlreadyEquipped = false ;
for ( auto entry : m_Wielded )
{
2018-07-12 14:41:21 -07:00
if ( entry = = item )
2018-03-29 17:01:57 -04:00
{
bAlreadyEquipped = true ;
break ;
}
}
if ( ! bAlreadyEquipped )
{
m_Wielded . push_back ( item ) ;
}
if ( child_location & & placement )
{
item - > m_Qualities . SetInt ( PARENT_LOCATION_INT , child_location ) ;
2018-07-12 14:41:21 -07:00
item - > set_parent ( this , child_location ) ;
2018-03-29 17:01:57 -04:00
item - > SetPlacementFrame ( placement , FALSE ) ;
if ( m_bWorldIsAware )
{
2018-07-12 14:41:21 -07:00
if ( CWeenieObject * owner = GetWorldTopLevelOwner ( ) )
2018-03-29 17:01:57 -04:00
{
if ( owner - > GetBlock ( ) )
{
owner - > GetBlock ( ) - > ExchangePVS ( item , 0 ) ;
}
}
/*
BinaryWriter * writer = item - > CreateMessage ( ) ;
g_pWorld - > BroadcastPVS ( dwCell , writer - > GetData ( ) , writer - > GetSize ( ) , OBJECT_MSG , 0 , FALSE ) ;
delete writer ;
*/
BinaryWriter Blah ;
2019-07-07 20:56:15 +00:00
Blah . Write < uint32_t > ( 0xF749 ) ;
Blah . Write < uint32_t > ( GetID ( ) ) ;
Blah . Write < uint32_t > ( item - > GetID ( ) ) ;
Blah . Write < uint32_t > ( child_location ) ;
Blah . Write < uint32_t > ( placement ) ;
2018-03-29 17:01:57 -04:00
Blah . Write < WORD > ( GetPhysicsObj ( ) - > _instance_timestamp ) ;
Blah . Write < WORD > ( + + item - > _position_timestamp ) ;
2019-05-12 09:21:34 -07:00
g_pWorld - > BroadcastPVS ( dwCell , Blah . GetData ( ) , Blah . GetSize ( ) , OBJECT_MSG , false , false , true ) ;
2018-03-29 17:01:57 -04:00
}
}
else
{
if ( m_bWorldIsAware )
{
item - > _position_timestamp + + ;
BinaryWriter Blah ;
2019-07-07 20:56:15 +00:00
Blah . Write < uint32_t > ( 0xF74A ) ;
Blah . Write < uint32_t > ( item - > GetID ( ) ) ;
2018-03-29 17:01:57 -04:00
Blah . Write < WORD > ( item - > _instance_timestamp ) ;
Blah . Write < WORD > ( item - > _position_timestamp ) ;
g_pWorld - > BroadcastPVS ( dwCell , Blah . GetData ( ) , Blah . GetSize ( ) ) ;
}
}
}
2019-07-07 20:56:15 +00:00
CWeenieObject * CContainerWeenie : : FindContainedItem ( uint32_t object_id )
2018-03-29 17:01:57 -04:00
{
for ( auto item : m_Wielded )
{
2018-07-12 14:41:21 -07:00
if ( item - > GetID ( ) = = object_id )
return item ;
2018-03-29 17:01:57 -04:00
}
for ( auto item : m_Items )
{
2018-07-12 14:41:21 -07:00
if ( item - > GetID ( ) = = object_id )
return item ;
2018-03-29 17:01:57 -04:00
}
for ( auto item : m_Packs )
{
2018-07-12 14:41:21 -07:00
if ( item - > GetID ( ) = = object_id )
return item ;
2018-03-29 17:01:57 -04:00
2018-07-12 14:41:21 -07:00
if ( auto subitem = item - > FindContainedItem ( object_id ) )
2018-03-29 17:01:57 -04:00
return subitem ;
}
return NULL ;
}
2019-07-07 20:56:15 +00:00
uint32_t CContainerWeenie : : Container_GetNumFreeMainPackSlots ( )
2018-03-29 17:01:57 -04:00
{
2019-07-07 20:56:15 +00:00
return ( uint32_t ) max ( 0 , GetItemsCapacity ( ) - ( signed ) m_Items . size ( ) ) ;
2018-03-29 17:01:57 -04:00
}
2018-07-12 14:41:21 -07:00
BOOL CContainerWeenie : : Container_CanStore ( CWeenieObject * pItem )
2018-03-29 17:01:57 -04:00
{
return Container_CanStore ( pItem , pItem - > RequiresPackSlot ( ) ) ;
}
BOOL CContainerWeenie : : IsItemsCapacityFull ( )
{
int capacity = GetItemsCapacity ( ) ;
if ( capacity > = 0 )
{
if ( m_Items . size ( ) < capacity )
2019-02-18 06:07:36 -06:00
return FALSE ;
2018-03-29 17:01:57 -04:00
2019-02-18 06:07:36 -06:00
return TRUE ;
2018-03-29 17:01:57 -04:00
}
return TRUE ;
}
BOOL CContainerWeenie : : IsContainersCapacityFull ( )
{
int capacity = GetContainersCapacity ( ) ;
if ( capacity > = 0 )
{
if ( m_Packs . size ( ) < capacity )
2019-02-18 06:07:36 -06:00
return FALSE ;
2018-03-29 17:01:57 -04:00
2019-02-18 06:07:36 -06:00
return TRUE ;
2018-03-29 17:01:57 -04:00
}
return TRUE ;
}
2018-07-12 14:41:21 -07:00
BOOL CContainerWeenie : : Container_CanStore ( CWeenieObject * pItem , bool bPackSlot )
2018-03-29 17:01:57 -04:00
{
// TODO handle: pItem->InqBoolQuality(REQUIRES_BACKPACK_SLOT_BOOL, FALSE)
if ( bPackSlot )
{
if ( ! pItem - > RequiresPackSlot ( ) )
return FALSE ;
int capacity = GetContainersCapacity ( ) ;
if ( capacity > = 0 )
{
if ( m_Packs . size ( ) < capacity )
return TRUE ;
for ( auto container : m_Packs )
{
2018-07-12 14:41:21 -07:00
if ( container = = pItem )
2018-03-29 17:01:57 -04:00
return TRUE ;
2020-06-05 23:41:06 +00:00
}
2018-03-29 17:01:57 -04:00
}
2020-06-05 23:41:06 +00:00
return FALSE ;
//else
//{
// if (InqBoolQuality(AI_ACCEPT_EVERYTHING_BOOL, FALSE))
// return TRUE;
2018-03-29 17:01:57 -04:00
2020-06-05 23:41:06 +00:00
// // check emote item acceptance here
2018-03-29 17:01:57 -04:00
2020-06-05 23:41:06 +00:00
// return FALSE;
//}
2018-03-29 17:01:57 -04:00
}
else
{
if ( pItem - > RequiresPackSlot ( ) )
return FALSE ;
int capacity = GetItemsCapacity ( ) ;
if ( capacity > = 0 )
{
if ( m_Items . size ( ) < capacity )
return TRUE ;
for ( auto container : m_Items )
{
2018-07-12 14:41:21 -07:00
if ( container = = pItem )
2018-03-29 17:01:57 -04:00
return TRUE ;
}
}
2020-06-05 23:41:06 +00:00
return FALSE ;
//else
//{
// if (InqBoolQuality(AI_ACCEPT_EVERYTHING_BOOL, FALSE))
// return TRUE;
// // check Give and Refuse emote item acceptance here
// if (m_Qualities._emote_table)
// {
// if (HasEmoteForID(Give_EmoteCategory, pItem->m_Qualities.id) || HasEmoteForID(Refuse_EmoteCategory, pItem->m_Qualities.id))
// return TRUE;
// }
// return FALSE;
//}
2018-03-29 17:01:57 -04:00
}
}
2019-07-07 20:56:15 +00:00
void CContainerWeenie : : Container_DeleteItem ( uint32_t item_id )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
CWeenieObject * item = FindContainedItem ( item_id ) ;
2018-03-29 17:01:57 -04:00
if ( ! item )
return ;
bool bWielded = item - > IsWielded ( ) ? true : false ;
// take it out of whatever slot it is in
ReleaseContainedItemRecursive ( item ) ;
item - > SetWeenieContainer ( 0 ) ;
item - > SetWielderID ( 0 ) ;
item - > SetWieldedLocation ( INVENTORY_LOC : : NONE_LOC ) ;
if ( bWielded & & item - > AsClothing ( ) )
{
2018-12-18 17:02:31 -06:00
if ( m_Qualities . GetInt ( HERITAGE_GROUP_INT , 1 ) ! = Gearknight_HeritageGroup ) // TODO: Update JUST cloak on gearknight unequip rather than whole model.
UpdateModel ( ) ;
2018-03-29 17:01:57 -04:00
}
2019-07-07 20:56:15 +00:00
uint32_t RemoveObject [ 3 ] ;
2018-03-29 17:01:57 -04:00
RemoveObject [ 0 ] = 0xF747 ;
RemoveObject [ 1 ] = item - > GetID ( ) ;
RemoveObject [ 2 ] = item - > _instance_timestamp ;
2018-07-12 14:41:21 -07:00
g_pWorld - > BroadcastPVS ( this , RemoveObject , sizeof ( RemoveObject ) ) ;
2018-03-29 17:01:57 -04:00
g_pWorld - > RemoveEntity ( item ) ;
}
2019-07-07 20:56:15 +00:00
uint32_t CContainerWeenie : : Container_InsertInventoryItem ( uint32_t dwCell , CWeenieObject * item , uint32_t slot )
2018-03-29 17:01:57 -04:00
{
// You should check if the inventory is full before calling this.
if ( ! item - > RequiresPackSlot ( ) )
{
2019-07-07 20:56:15 +00:00
if ( slot > ( uint32_t ) m_Items . size ( ) )
slot = ( uint32_t ) m_Items . size ( ) ;
2018-03-29 17:01:57 -04:00
m_Items . insert ( m_Items . begin ( ) + slot , item ) ;
}
else
{
2019-07-07 20:56:15 +00:00
if ( slot > ( uint32_t ) m_Packs . size ( ) )
slot = ( uint32_t ) m_Packs . size ( ) ;
2018-03-29 17:01:57 -04:00
m_Packs . insert ( m_Packs . begin ( ) + slot , item ) ;
}
if ( dwCell & & m_bWorldIsAware )
{
item - > _position_timestamp + + ;
BinaryWriter Blah ;
2019-07-07 20:56:15 +00:00
Blah . Write < uint32_t > ( 0xF74A ) ;
Blah . Write < uint32_t > ( item - > GetID ( ) ) ;
2018-03-29 17:01:57 -04:00
Blah . Write < WORD > ( item - > _instance_timestamp ) ;
Blah . Write < WORD > ( item - > _position_timestamp ) ;
g_pWorld - > BroadcastPVS ( dwCell , Blah . GetData ( ) , Blah . GetSize ( ) ) ;
}
item - > m_Qualities . SetInt ( PARENT_LOCATION_INT , 0 ) ;
2018-08-23 01:36:18 -05:00
item - > NotifyIntStatUpdated ( PARENT_LOCATION_INT , 0 ) ;
2018-03-29 17:01:57 -04:00
item - > unset_parent ( ) ;
item - > leave_world ( ) ;
RecalculateEncumbrance ( ) ;
return slot ;
}
bool CContainerWeenie : : SpawnTreasureInContainer ( eTreasureCategory category , int tier , int workmanship )
{
2018-07-12 14:41:21 -07:00
CWeenieObject * treasure = g_pTreasureFactory - > GenerateTreasure ( tier , category ) ;
2018-03-29 17:01:57 -04:00
if ( ! treasure )
return false ;
if ( workmanship > 0 )
{
workmanship = min ( max ( workmanship , 1 ) , 10 ) ;
treasure - > m_Qualities . SetInt ( ITEM_WORKMANSHIP_INT , workmanship ) ;
}
else if ( workmanship = = 0 )
treasure - > m_Qualities . RemoveInt ( ITEM_WORKMANSHIP_INT ) ;
return SpawnInContainer ( treasure ) ;
}
2019-07-07 20:56:15 +00:00
bool CContainerWeenie : : SpawnInContainer ( uint32_t wcid , int amount , int ptid , float shade , bool sendEnvent )
2018-03-29 17:01:57 -04:00
{
if ( amount < 1 )
return false ;
2018-07-12 14:41:21 -07:00
CWeenieObject * item = g_pWeenieFactory - > CreateWeenieByClassID ( wcid , NULL , false ) ;
2018-03-29 17:01:57 -04:00
if ( ! item )
return false ;
if ( ptid )
item - > m_Qualities . SetInt ( PALETTE_TEMPLATE_INT , ptid ) ;
if ( shade > 0.0 )
item - > m_Qualities . SetFloat ( SHADE_FLOAT , shade ) ;
int maxStackSize = item - > m_Qualities . GetInt ( MAX_STACK_SIZE_INT , 1 ) ;
if ( maxStackSize > 1 )
{
//If we're stackable, first let's try stacking to existing items.
for ( auto possibleMatch : m_Items )
{
2018-07-12 14:41:21 -07:00
if ( item - > m_Qualities . id ! = possibleMatch - > m_Qualities . id )
2018-03-29 17:01:57 -04:00
continue ;
2018-07-12 14:41:21 -07:00
if ( ptid ! = 0 & & possibleMatch - > InqIntQuality ( PALETTE_TEMPLATE_INT , 0 ) ! = ptid )
2018-03-29 17:01:57 -04:00
continue ;
2018-07-12 14:41:21 -07:00
if ( shade > = 0.0 & & possibleMatch - > InqFloatQuality ( SHADE_FLOAT , 0 ) ! = shade )
2018-03-29 17:01:57 -04:00
continue ;
2018-07-12 14:41:21 -07:00
int possibleMatchStackSize = possibleMatch - > InqIntQuality ( STACK_SIZE_INT , 1 ) ;
2018-03-29 17:01:57 -04:00
if ( possibleMatchStackSize < maxStackSize )
{
//we have room.
int roomFor = maxStackSize - possibleMatchStackSize ;
if ( roomFor > = amount )
{
//room for everything!
2018-07-12 14:41:21 -07:00
possibleMatch - > SetStackSize ( possibleMatchStackSize + amount ) ;
delete item ;
2018-03-29 17:01:57 -04:00
return true ;
}
else
{
//room for some.
amount - = roomFor ;
2018-07-12 14:41:21 -07:00
possibleMatch - > SetStackSize ( maxStackSize ) ;
2018-03-29 17:01:57 -04:00
}
}
}
}
//We're done stacking and we still have enough for a new item.
2019-07-07 20:56:15 +00:00
uint32_t totalSlotsRequired = 0 ;
2018-03-29 17:01:57 -04:00
if ( maxStackSize < 1 )
maxStackSize = 1 ;
totalSlotsRequired = amount / maxStackSize ;
if ( Container_GetNumFreeMainPackSlots ( ) < totalSlotsRequired )
return false ;
if ( amount > 1 )
{
int maxStackSize = item - > m_Qualities . GetInt ( MAX_STACK_SIZE_INT , 1 ) ;
if ( amount < = maxStackSize )
item - > SetStackSize ( amount ) ;
else
{
int amountOfStacks = amount / maxStackSize ;
int restStackSize = amount % maxStackSize ;
for ( int i = 0 ; i < amountOfStacks ; i + + )
SpawnInContainer ( wcid , maxStackSize , ptid , shade ) ;
if ( restStackSize > 0 )
item - > SetStackSize ( restStackSize ) ;
else
{
2018-07-12 14:41:21 -07:00
delete item ;
2018-03-29 17:01:57 -04:00
return true ;
}
}
}
SpawnInContainer ( item , sendEnvent ) ;
return true ;
}
2018-07-12 14:41:21 -07:00
bool CContainerWeenie : : SpawnCloneInContainer ( CWeenieObject * itemToClone , int amount , bool sendEnvent )
2018-03-29 17:01:57 -04:00
{
2019-11-13 20:40:06 +00:00
if ( ! itemToClone )
2018-03-29 17:01:57 -04:00
return false ;
2019-11-13 20:40:06 +00:00
if ( amount < 1 )
2018-03-29 17:01:57 -04:00
return false ;
2019-11-13 20:40:06 +00:00
int maxStackSize = itemToClone - > m_Qualities . GetInt ( MAX_STACK_SIZE_INT , 1 ) ;
int amountOfStacks = 0 ;
int restStackSize = 0 ;
if ( amount < = maxStackSize )
2018-03-29 17:01:57 -04:00
{
2019-11-13 20:40:06 +00:00
restStackSize = amount ;
}
else
{
amountOfStacks = amount / maxStackSize ;
restStackSize = amount % maxStackSize ;
2018-03-29 17:01:57 -04:00
}
2019-11-13 20:40:06 +00:00
int numStacks = amountOfStacks + ( restStackSize > 0 ? 1 : 0 ) ;
2018-03-29 17:01:57 -04:00
2019-11-13 20:40:06 +00:00
for ( int i = numStacks ; i > 0 ; i - - )
2018-03-29 17:01:57 -04:00
{
2019-11-13 20:40:06 +00:00
CWeenieObject * item = g_pWeenieFactory - > CloneWeenie ( itemToClone ) ;
if ( ! item )
return false ;
if ( ( i = = 1 ) & & ( restStackSize > 0 ) )
{
item - > SetStackSize ( restStackSize ) ;
}
else
{
item - > SetStackSize ( maxStackSize ) ;
}
if ( ! SpawnInContainer ( item , sendEnvent , false ) )
2018-03-29 17:01:57 -04:00
{
2019-11-13 20:40:06 +00:00
CWeenieObject * owner = this - > GetWorldTopLevelOwner ( ) ;
if ( owner )
{
item - > SetInitialPosition ( owner - > m_Position ) ;
2018-03-29 17:01:57 -04:00
2019-11-13 20:40:06 +00:00
if ( g_pWorld - > CreateEntity ( item ) )
{
item - > _timeToRot = Timer : : cur_time + 300.0 ;
item - > _beganRot = false ;
item - > m_Qualities . SetFloat ( TIME_TO_ROT_FLOAT , item - > _timeToRot ) ;
}
}
else
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
delete item ;
2019-11-13 20:40:06 +00:00
continue ;
2018-03-29 17:01:57 -04:00
}
}
}
return true ;
}
2018-07-12 14:41:21 -07:00
bool CContainerWeenie : : SpawnInContainer ( CWeenieObject * item , bool sendEnvent , bool deleteItemOnFailure )
2018-03-29 17:01:57 -04:00
{
2018-12-24 00:49:50 -06:00
if ( item )
2018-03-29 17:01:57 -04:00
{
2018-12-24 00:49:50 -06:00
item - > SetID ( g_pWorld - > GenerateGUID ( eDynamicGUID ) ) ;
if ( ! Container_CanStore ( item ) )
{
if ( sendEnvent )
NotifyInventoryFailedEvent ( item - > GetID ( ) , WERROR_GIVE_NOT_ALLOWED ) ;
2018-03-29 17:01:57 -04:00
2018-12-24 00:49:50 -06:00
if ( deleteItemOnFailure )
delete item ;
return false ;
}
2018-03-29 17:01:57 -04:00
2018-12-24 00:49:50 -06:00
if ( ! g_pWorld - > CreateEntity ( item ) )
{
if ( sendEnvent )
NotifyInventoryFailedEvent ( item - > GetID ( ) , WERROR_GIVE_NOT_ALLOWED ) ;
if ( deleteItemOnFailure )
delete item ;
return false ;
}
2018-03-29 17:01:57 -04:00
2018-12-24 00:49:50 -06:00
if ( sendEnvent )
2018-03-29 17:01:57 -04:00
{
2018-12-24 00:49:50 -06:00
SendNetMessage ( InventoryMove ( item - > GetID ( ) , GetID ( ) , 0 , item - > RequiresPackSlot ( ) ? 1 : 0 ) , PRIVATE_MSG , TRUE ) ;
if ( item - > AsContainer ( ) )
item - > AsContainer ( ) - > MakeAwareViewContent ( this ) ;
MakeAware ( item , true ) ;
2018-03-29 17:01:57 -04:00
2018-12-24 00:49:50 -06:00
if ( _openedById ! = 0 )
2018-03-29 17:01:57 -04:00
{
2018-12-24 00:49:50 -06:00
CWeenieObject * openedBy = g_pWorld - > FindObject ( _openedById ) ;
if ( openedBy )
{
openedBy - > SendNetMessage ( InventoryMove ( item - > GetID ( ) , GetID ( ) , 0 , item - > RequiresPackSlot ( ) ? 1 : 0 ) , PRIVATE_MSG , TRUE ) ;
if ( item - > AsContainer ( ) )
item - > AsContainer ( ) - > MakeAwareViewContent ( this ) ;
openedBy - > MakeAware ( item , true ) ;
}
2018-03-29 17:01:57 -04:00
}
}
2018-12-24 00:49:50 -06:00
OnReceiveInventoryItem ( this , item , 0 ) ;
return true ;
}
else
return false ;
2018-03-29 17:01:57 -04:00
}
2019-07-07 20:56:15 +00:00
uint32_t CContainerWeenie : : OnReceiveInventoryItem ( CWeenieObject * source , CWeenieObject * item , uint32_t desired_slot )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
if ( source ! = this )
2018-03-29 17:01:57 -04:00
{
// By default, if we receive things just delete them... creatures can override this
g_pWorld - > RemoveEntity ( item ) ;
return 0 ;
}
else
{
// Unless the source is ourselves, that means the item is spawning.
item - > ReleaseFromAnyWeenieParent ( false , true ) ;
item - > SetWieldedLocation ( INVENTORY_LOC : : NONE_LOC ) ;
item - > SetWeenieContainer ( GetID ( ) ) ;
item - > ReleaseFromBlock ( ) ;
return Container_InsertInventoryItem ( 0 , item , desired_slot ) ;
}
}
2019-07-07 20:56:15 +00:00
CWeenieObject * CContainerWeenie : : FindContained ( uint32_t object_id )
2018-03-29 17:01:57 -04:00
{
return FindContainedItem ( object_id ) ;
}
void CContainerWeenie : : InitPhysicsObj ( )
{
CWeenieObject : : InitPhysicsObj ( ) ;
2018-07-12 14:41:21 -07:00
if ( ! _phys_obj )
2018-03-29 17:01:57 -04:00
return ;
for ( auto item : m_Wielded )
{
# ifdef _DEBUG
2018-07-12 14:41:21 -07:00
assert ( item - > GetWielderID ( ) = = GetID ( ) ) ;
2018-03-29 17:01:57 -04:00
# endif
2018-07-12 14:41:21 -07:00
int parentLocation = item - > InqIntQuality ( PARENT_LOCATION_INT , PARENT_ENUM : : PARENT_NONE ) ;
2018-03-29 17:01:57 -04:00
if ( parentLocation ! = PARENT_ENUM : : PARENT_NONE )
{
2018-07-12 14:41:21 -07:00
item - > set_parent ( this , parentLocation ) ;
2018-03-29 17:01:57 -04:00
2018-07-12 14:41:21 -07:00
int placement = item - > InqIntQuality ( PLACEMENT_POSITION_INT , 0 ) ;
2018-03-29 17:01:57 -04:00
assert ( placement ) ;
2018-07-12 14:41:21 -07:00
item - > SetPlacementFrame ( placement , FALSE ) ;
2018-03-29 17:01:57 -04:00
}
}
# ifdef _DEBUG
for ( auto item : m_Items )
{
2018-07-12 14:41:21 -07:00
assert ( item - > InqIntQuality ( PARENT_LOCATION_INT , PARENT_ENUM : : PARENT_NONE ) = = PARENT_ENUM : : PARENT_NONE ) ;
2018-03-29 17:01:57 -04:00
}
for ( auto pack : m_Packs )
{
2018-07-12 14:41:21 -07:00
assert ( pack - > InqIntQuality ( PARENT_LOCATION_INT , PARENT_ENUM : : PARENT_NONE ) = = PARENT_ENUM : : PARENT_NONE ) ;
2018-03-29 17:01:57 -04:00
}
# endif
}
void CContainerWeenie : : SaveEx ( class CWeenieSave & save )
{
CWeenieObject : : SaveEx ( save ) ;
for ( auto item : m_Wielded )
{
2018-07-12 14:41:21 -07:00
save . _equipment . push_back ( item - > GetID ( ) ) ;
item - > Save ( ) ;
2018-03-29 17:01:57 -04:00
}
for ( auto item : m_Items )
{
2018-07-12 14:41:21 -07:00
save . _inventory . push_back ( item - > GetID ( ) ) ;
item - > Save ( ) ;
2018-03-29 17:01:57 -04:00
}
for ( auto item : m_Packs )
{
2018-07-12 14:41:21 -07:00
save . _packs . push_back ( item - > GetID ( ) ) ;
item - > Save ( ) ;
2018-03-29 17:01:57 -04:00
}
}
void CContainerWeenie : : LoadEx ( class CWeenieSave & save )
{
CWeenieObject : : LoadEx ( save ) ;
for ( auto item : save . _equipment )
{
2018-07-12 14:41:21 -07:00
CWeenieObject * weenie = CWeenieObject : : Load ( item ) ;
2018-03-29 17:01:57 -04:00
if ( weenie )
{
if ( weenie - > RequiresPackSlot ( ) )
{
2018-07-12 14:41:21 -07:00
delete weenie ;
2018-03-29 17:01:57 -04:00
continue ;
}
2019-06-12 04:15:28 +00:00
//assert(weenie->IsWielded());
//assert(!weenie->IsContained());
2018-03-29 17:01:57 -04:00
// make sure it has the right settings (shouldn't be necessary)
weenie - > SetWielderID ( GetID ( ) ) ;
weenie - > SetWeenieContainer ( 0 ) ;
weenie - > m_Qualities . RemovePosition ( INSTANTIATION_POSITION ) ;
weenie - > m_Qualities . RemovePosition ( LOCATION_POSITION ) ;
if ( g_pWorld - > CreateEntity ( weenie , false ) )
{
m_Wielded . push_back ( weenie ) ;
if ( int combatUse = weenie - > InqIntQuality ( COMBAT_USE_INT , 0 , TRUE ) )
2018-11-10 09:45:18 -06:00
{
2018-11-21 19:37:14 -06:00
int frame = weenie - > InqIntQuality ( PLACEMENT_POSITION_INT , 0 , TRUE ) ;
if ( combatUse = = COMBAT_USE_MELEE & & frame = = LeftWeapon )
2018-11-10 09:45:18 -06:00
combatUse = COMBAT_USE_OFFHAND ;
2018-03-29 17:01:57 -04:00
SetWieldedCombat ( weenie , ( COMBAT_USE ) combatUse ) ;
2018-11-10 09:45:18 -06:00
}
2018-03-29 17:01:57 -04:00
assert ( weenie - > IsWielded ( ) ) ;
assert ( ! weenie - > IsContained ( ) ) ;
}
else
{
// remove any enchantments associated with this item that we failed to wield...
if ( m_Qualities . _enchantment_reg )
{
2019-07-07 20:56:15 +00:00
PackableListWithJson < uint32_t > spells_to_remove ;
2018-03-29 17:01:57 -04:00
if ( m_Qualities . _enchantment_reg - > _add_list )
{
for ( const auto & entry : * m_Qualities . _enchantment_reg - > _add_list )
{
if ( entry . _caster = = item )
{
spells_to_remove . push_back ( entry . _id ) ;
}
}
}
if ( m_Qualities . _enchantment_reg - > _mult_list )
{
for ( const auto & entry : * m_Qualities . _enchantment_reg - > _mult_list )
{
if ( entry . _caster = = item )
{
spells_to_remove . push_back ( entry . _id ) ;
}
}
}
if ( m_Qualities . _enchantment_reg - > _cooldown_list )
{
for ( const auto & entry : * m_Qualities . _enchantment_reg - > _cooldown_list )
{
if ( entry . _caster = = item )
{
spells_to_remove . push_back ( entry . _id ) ;
}
}
}
if ( ! spells_to_remove . empty ( ) )
{
m_Qualities . _enchantment_reg - > RemoveEnchantments ( & spells_to_remove ) ;
}
}
}
}
}
for ( auto item : save . _inventory )
{
2018-07-12 14:41:21 -07:00
CWeenieObject * weenie = CWeenieObject : : Load ( item ) ;
2018-03-29 17:01:57 -04:00
if ( weenie )
{
2019-07-07 20:56:15 +00:00
uint32_t correct_container_iid = weenie - > m_Qualities . GetIID ( CONTAINER_IID , 0 ) ;
2018-03-29 17:01:57 -04:00
if ( weenie - > RequiresPackSlot ( ) | | ( correct_container_iid & & correct_container_iid ! = GetID ( ) ) )
{
2018-07-12 14:41:21 -07:00
delete weenie ;
2018-03-29 17:01:57 -04:00
continue ;
}
assert ( ! weenie - > IsWielded ( ) ) ;
assert ( weenie - > IsContained ( ) ) ;
assert ( ! weenie - > InqIntQuality ( PARENT_LOCATION_INT , 0 ) ) ;
// make sure it has the right settings (shouldn't be necessary)
weenie - > SetWielderID ( 0 ) ;
weenie - > m_Qualities . SetInt ( PARENT_LOCATION_INT , 0 ) ;
weenie - > SetWeenieContainer ( GetID ( ) ) ;
weenie - > m_Qualities . RemovePosition ( INSTANTIATION_POSITION ) ;
weenie - > m_Qualities . RemovePosition ( LOCATION_POSITION ) ;
if ( g_pWorld - > CreateEntity ( weenie , false ) )
{
m_Items . push_back ( weenie ) ;
assert ( ! weenie - > IsWielded ( ) ) ;
assert ( weenie - > IsContained ( ) ) ;
}
}
}
for ( auto item : save . _packs )
{
2018-07-12 14:41:21 -07:00
CWeenieObject * weenie = CWeenieObject : : Load ( item ) ;
2018-03-29 17:01:57 -04:00
if ( weenie )
{
2019-07-07 20:56:15 +00:00
uint32_t correct_container_iid = weenie - > m_Qualities . GetIID ( CONTAINER_IID , 0 ) ;
2018-03-29 17:01:57 -04:00
if ( ! weenie - > RequiresPackSlot ( ) | | ( correct_container_iid & & correct_container_iid ! = GetID ( ) ) )
{
2018-07-12 14:41:21 -07:00
delete weenie ;
2018-03-29 17:01:57 -04:00
continue ;
}
assert ( ! weenie - > IsWielded ( ) ) ;
assert ( weenie - > IsContained ( ) ) ;
assert ( ! weenie - > InqIntQuality ( PARENT_LOCATION_INT , 0 ) ) ;
// make sure it has the right settings (shouldn't be necessary)
weenie - > SetWielderID ( 0 ) ;
weenie - > m_Qualities . SetInt ( PARENT_LOCATION_INT , 0 ) ;
weenie - > SetWeenieContainer ( GetID ( ) ) ;
weenie - > m_Qualities . RemovePosition ( INSTANTIATION_POSITION ) ;
weenie - > m_Qualities . RemovePosition ( LOCATION_POSITION ) ;
if ( g_pWorld - > CreateEntity ( weenie , false ) )
{
m_Packs . push_back ( weenie ) ;
assert ( ! weenie - > IsWielded ( ) ) ;
assert ( weenie - > IsContained ( ) ) ;
}
}
}
}
2018-07-12 14:41:21 -07:00
void CContainerWeenie : : MakeAwareViewContent ( CWeenieObject * other )
2018-03-29 17:01:57 -04:00
{
//start from the bottom of the tree so the packs have their fill bar correctly populated.
for ( auto pack : m_Packs )
{
2018-07-12 14:41:21 -07:00
if ( pack - > AsContainer ( ) )
pack - > AsContainer ( ) - > MakeAwareViewContent ( other ) ;
other - > MakeAware ( pack , true ) ;
2018-03-29 17:01:57 -04:00
}
for ( auto item : m_Items )
{
2018-07-12 14:41:21 -07:00
other - > MakeAware ( item , true ) ;
2018-03-29 17:01:57 -04:00
}
PackableList < ContentProfile > inventoryList ;
for ( auto item : m_Items )
{
ContentProfile prof ;
2018-07-12 14:41:21 -07:00
prof . m_iid = item - > GetID ( ) ;
2018-03-29 17:01:57 -04:00
prof . m_uContainerProperties = 0 ;
inventoryList . push_back ( prof ) ;
}
for ( auto pack : m_Packs )
{
ContentProfile prof ;
2018-07-12 14:41:21 -07:00
prof . m_iid = pack - > GetID ( ) ;
2018-03-29 17:01:57 -04:00
prof . m_uContainerProperties = 1 ; //todo: what about foci? Do they need a different value here?
inventoryList . push_back ( prof ) ;
}
BinaryWriter viewContent ;
2019-07-07 20:56:15 +00:00
viewContent . Write < uint32_t > ( 0x196 ) ;
viewContent . Write < uint32_t > ( GetID ( ) ) ;
2018-03-29 17:01:57 -04:00
inventoryList . Pack ( & viewContent ) ;
other - > SendNetMessage ( & viewContent , PRIVATE_MSG , TRUE , FALSE ) ;
}
bool CContainerWeenie : : IsGroundContainer ( )
{
if ( HasOwner ( ) )
return false ;
2018-10-26 14:18:40 -05:00
if ( ! m_Qualities . m_PositionStats | | m_Qualities . m_PositionStats - > empty ( ) )
2018-03-29 17:01:57 -04:00
return false ;
return true ;
}
2018-07-12 14:41:21 -07:00
bool CContainerWeenie : : IsInOpenRange ( CWeenieObject * other )
2018-03-29 17:01:57 -04:00
{
if ( ! IsGroundContainer ( ) )
return false ;
if ( DistanceTo ( other , true ) > = InqFloatQuality ( USE_RADIUS_FLOAT , 1.0 ) )
return false ;
return true ;
}
2018-07-12 14:41:21 -07:00
void CContainerWeenie : : OnContainerOpened ( CWeenieObject * other )
2018-03-29 17:01:57 -04:00
{
if ( other & & other - > _lastOpenedRemoteContainerId & & other - > _lastOpenedRemoteContainerId ! = GetID ( ) )
{
2018-07-12 14:41:21 -07:00
if ( CWeenieObject * otherContainerObj = g_pWorld - > FindObject ( other - > _lastOpenedRemoteContainerId ) )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
if ( CContainerWeenie * otherContainer = otherContainerObj - > AsContainer ( ) )
2018-03-29 17:01:57 -04:00
{
if ( otherContainer - > _openedById = = other - > GetID ( ) )
otherContainer - > OnContainerClosed ( ) ;
}
}
}
MakeAwareViewContent ( other ) ;
_openedById = other - > GetID ( ) ;
other - > _lastOpenedRemoteContainerId = GetID ( ) ;
_failedPreviousCheckToClose = false ;
2019-01-25 21:31:39 -06:00
2019-07-07 20:56:15 +00:00
uint32_t spell = 0 ;
2019-01-25 21:31:39 -06:00
if ( m_Qualities . InqDataID ( SPELL_DID , spell ) )
MakeSpellcastingManager ( ) - > CastSpellInstant ( _openedById , spell ) ;
2018-03-29 17:01:57 -04:00
}
2018-07-12 14:41:21 -07:00
void CContainerWeenie : : OnContainerClosed ( CWeenieObject * requestedBy )
2018-03-29 17:01:57 -04:00
{
if ( requestedBy )
{
BinaryWriter closeContent ;
2019-07-07 20:56:15 +00:00
closeContent . Write < uint32_t > ( 0x52 ) ;
closeContent . Write < uint32_t > ( GetID ( ) ) ;
2018-03-29 17:01:57 -04:00
requestedBy - > SendNetMessage ( & closeContent , PRIVATE_MSG , TRUE , FALSE ) ;
}
_openedById = 0 ;
if ( InqStringQuality ( QUEST_STRING , " " ) ! = " " )
ResetToInitialState ( ) ; //quest chests reset instantly
2019-01-19 22:45:18 -06:00
else if ( _nextReset < 0 | | InqIIDQuality ( LAST_UNLOCKER_IID , 0 ) )
2018-03-29 17:01:57 -04:00
{
2019-01-19 22:45:18 -06:00
// Use the chest's built in regen or reset interval after it's been closed.
2018-03-29 17:01:57 -04:00
if ( double resetInterval = InqFloatQuality ( RESET_INTERVAL_FLOAT , 0 ) )
_nextReset = Timer : : cur_time + ( resetInterval * g_pConfig - > RespawnTimeMultiplier ( ) ) ;
else if ( double regenInterval = InqFloatQuality ( REGENERATION_INTERVAL_FLOAT , 0 ) ) //if we don't have a reset interval, fall back to regen interval
_nextReset = Timer : : cur_time + ( regenInterval * g_pConfig - > RespawnTimeMultiplier ( ) ) ;
2019-01-19 22:45:18 -06:00
// Open the chest for everyone.
m_Qualities . RemoveInstanceID ( LAST_UNLOCKER_IID ) ;
2018-03-29 17:01:57 -04:00
}
}
2018-07-12 14:41:21 -07:00
void CContainerWeenie : : NotifyGeneratedPickedUp ( CWeenieObject * weenie )
2018-03-29 17:01:57 -04:00
{
//container contents do not regenerate individually. Instead once the container is closed we start a reset timer.
weenie - > m_Qualities . RemoveInstanceID ( GENERATOR_IID ) ;
}
void CContainerWeenie : : ResetToInitialState ( )
{
m_Qualities . RemoveInstanceID ( OWNER_IID ) ;
2019-01-19 19:55:46 -06:00
m_Qualities . RemoveInstanceID ( LAST_UNLOCKER_IID ) ;
2018-03-29 17:01:57 -04:00
2019-01-19 22:45:18 -06:00
if ( _openedById )
OnContainerClosed ( g_pWorld - > FindObject ( _openedById ) ) ;
2018-03-29 17:01:57 -04:00
SetLocked ( m_bInitiallyLocked ? TRUE : FALSE ) ;
while ( ! m_Wielded . empty ( ) )
2018-07-12 14:41:21 -07:00
Container_DeleteItem ( ( * m_Wielded . begin ( ) ) - > GetID ( ) ) ;
2018-03-29 17:01:57 -04:00
while ( ! m_Items . empty ( ) )
2018-07-12 14:41:21 -07:00
Container_DeleteItem ( ( * m_Items . begin ( ) ) - > GetID ( ) ) ;
2018-03-29 17:01:57 -04:00
while ( ! m_Packs . empty ( ) )
2018-07-12 14:41:21 -07:00
Container_DeleteItem ( ( * m_Packs . begin ( ) ) - > GetID ( ) ) ;
2018-03-29 17:01:57 -04:00
if ( m_Qualities . _generator_table )
{
if ( m_Qualities . _generator_registry | | m_Qualities . _generator_queue )
{
for ( auto & entry : m_Qualities . _generator_table - > _profile_list )
{
if ( entry . whereCreate & Contain_RegenLocationType )
{
if ( m_Qualities . _generator_registry )
{
2019-07-07 20:56:15 +00:00
for ( PackableHashTable < uint32_t , GeneratorRegistryNode > : : iterator i = m_Qualities . _generator_registry - > _registry . begin ( ) ; i ! = m_Qualities . _generator_registry - > _registry . end ( ) ; )
2018-03-29 17:01:57 -04:00
{
if ( entry . slot = = i - > second . slot )
i = m_Qualities . _generator_registry - > _registry . erase ( i ) ;
else
i + + ;
}
}
if ( m_Qualities . _generator_queue )
{
for ( auto i = m_Qualities . _generator_queue - > _queue . begin ( ) ; i ! = m_Qualities . _generator_queue - > _queue . end ( ) ; )
{
if ( entry . slot = = i - > slot )
i = m_Qualities . _generator_queue - > _queue . erase ( i ) ;
else
i + + ;
}
}
2018-12-06 19:17:48 -06:00
if ( m_GeneratorSpawns . size ( ) > 0 )
m_GeneratorSpawns . clear ( ) ;
2018-03-29 17:01:57 -04:00
}
}
}
else
{
if ( m_Qualities . _generator_registry )
m_Qualities . _generator_registry - > _registry . clear ( ) ;
if ( m_Qualities . _generator_queue )
m_Qualities . _generator_queue - > _queue . clear ( ) ;
2018-12-06 19:17:48 -06:00
if ( m_GeneratorSpawns . size ( ) > 0 )
m_GeneratorSpawns . clear ( ) ;
2018-03-29 17:01:57 -04:00
}
}
InitCreateGenerator ( ) ;
}
2018-07-12 14:41:21 -07:00
int CContainerWeenie : : DoUseResponse ( CWeenieObject * other )
2018-03-29 17:01:57 -04:00
{
if ( IsBusyOrInAction ( ) )
return WERROR_NONE ;
if ( ! ( GetItemType ( ) & ITEM_TYPE : : TYPE_CONTAINER ) )
return WERROR_NONE ;
if ( ! IsGroundContainer ( ) )
return WERROR_NONE ;
if ( ! IsInOpenRange ( other ) )
return WERROR_NONE ;
if ( IsLocked ( ) )
{
EmitSound ( Sound_OpenFailDueToLock , 1.0f ) ;
return WERROR_NONE ;
}
int openError = CheckOpenContainer ( other ) ;
if ( openError )
return WERROR_NONE ;
if ( _openedById )
{
if ( _openedById = = other - > GetID ( ) )
{
//this is actually a close container request.
OnContainerClosed ( other ) ;
return WERROR_NONE ;
}
else
return WERROR_CHEST_ALREADY_OPEN ;
}
2019-07-07 20:56:15 +00:00
if ( uint32_t unlocker = InqIIDQuality ( LAST_UNLOCKER_IID , 0 ) )
2019-01-19 19:55:46 -06:00
{
2019-01-21 03:58:44 -06:00
// Unopened and unlocked chests are open to everyone after 30 seconds.
if ( unlocker ! = other - > GetID ( ) & & _nextReset - 570 > = Timer : : cur_time )
2019-01-19 19:55:46 -06:00
{
other - > SendText ( csprintf ( " This chest is claimed by the person who unlocked it. " ) , LTT_DEFAULT ) ;
return WERROR_NONE ;
}
}
2018-03-29 17:01:57 -04:00
std : : string questString ;
if ( m_Qualities . InqString ( QUEST_STRING , questString ) & & ! questString . empty ( ) )
{
2019-07-07 20:56:15 +00:00
if ( uint32_t owner = InqIIDQuality ( OWNER_IID , 0 ) )
2018-03-29 17:01:57 -04:00
{
if ( owner ! = other - > GetID ( ) )
{
other - > SendText ( csprintf ( " This chest is claimed by the person who lockpicked it. " ) , LTT_DEFAULT ) ;
return WERROR_NONE ;
}
}
else
{
if ( other - > InqQuest ( questString . c_str ( ) ) )
{
int timeTilOkay = other - > InqTimeUntilOkayToComplete ( questString . c_str ( ) ) ;
if ( timeTilOkay > 0 )
{
int secs = timeTilOkay % 60 ;
timeTilOkay / = 60 ;
int mins = timeTilOkay % 60 ;
timeTilOkay / = 60 ;
int hours = timeTilOkay % 24 ;
timeTilOkay / = 24 ;
int days = timeTilOkay ;
other - > SendText ( csprintf ( " You cannot open this for another %dd %dh %dm %ds. " , days , hours , mins , secs ) , LTT_DEFAULT ) ;
}
return WERROR_CHEST_USED_TOO_RECENTLY ;
}
other - > StampQuest ( questString . c_str ( ) ) ;
}
}
OnContainerOpened ( other ) ;
2019-09-03 14:18:02 +00:00
return CWeenieObject : : DoUseResponse ( other ) ;
2018-03-29 17:01:57 -04:00
}
void CContainerWeenie : : InventoryTick ( )
{
CWeenieObject : : InventoryTick ( ) ;
2018-07-12 14:41:21 -07:00
for ( auto wielded : m_Wielded )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
wielded - > WieldedTick ( ) ;
2018-03-29 17:01:57 -04:00
2019-01-13 10:55:05 -06:00
//#ifdef _DEBUG
// wielded->DebugValidate();
//#endif
2018-03-29 17:01:57 -04:00
}
2018-07-12 14:41:21 -07:00
for ( auto item : m_Items )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
item - > InventoryTick ( ) ;
2018-03-29 17:01:57 -04:00
2019-01-13 10:55:05 -06:00
//#ifdef _DEBUG
// item->DebugValidate();
//#endif
2018-03-29 17:01:57 -04:00
}
2018-07-12 14:41:21 -07:00
for ( auto pack : m_Packs )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
pack - > InventoryTick ( ) ;
2018-03-29 17:01:57 -04:00
2019-01-13 10:55:05 -06:00
//#ifdef _DEBUG
// pack->DebugValidate();
//#endif
2018-03-29 17:01:57 -04:00
}
}
void CContainerWeenie : : Tick ( )
{
CWeenieObject : : Tick ( ) ;
if ( _openedById )
{
CheckToClose ( ) ;
}
if ( Timer : : cur_time < _nextInventoryTick )
{
return ;
}
2018-07-12 14:41:21 -07:00
for ( auto wielded : m_Wielded )
{
wielded - > WieldedTick ( ) ;
2019-01-13 10:55:05 -06:00
//#ifdef _DEBUG
// wielded->DebugValidate();
//#endif
2018-07-12 14:41:21 -07:00
}
for ( auto item : m_Items )
{
2019-11-13 20:40:06 +00:00
if ( item )
2019-02-26 22:24:48 +00:00
item - > InventoryTick ( ) ;
2018-07-12 14:41:21 -07:00
2019-01-13 10:55:05 -06:00
//#ifdef _DEBUG
// item->DebugValidate();
//#endif
2018-07-12 14:41:21 -07:00
}
for ( auto pack : m_Packs )
{
pack - > InventoryTick ( ) ;
2019-01-13 10:55:05 -06:00
//#ifdef _DEBUG
// pack->DebugValidate();
//#endif
2018-07-12 14:41:21 -07:00
}
2018-03-29 17:01:57 -04:00
_nextInventoryTick = Timer : : cur_time + Random : : GenFloat ( 0.4 , 0.6 ) ;
}
void CContainerWeenie : : CheckToClose ( )
{
if ( _nextCheckToClose > Timer : : cur_time )
{
return ;
}
_nextCheckToClose = Timer : : cur_time + 1.0 ;
2018-07-12 14:41:21 -07:00
if ( CWeenieObject * other = g_pWorld - > FindObject ( _openedById ) )
2018-03-29 17:01:57 -04:00
{
if ( other - > IsDead ( ) | | ! IsInOpenRange ( other ) )
{
if ( _failedPreviousCheckToClose )
OnContainerClosed ( ) ;
else
{
_failedPreviousCheckToClose = true ; //give the client a moment to send the chest close message or we might interpret it as a open request(both use the use packet)
_nextCheckToClose = Timer : : cur_time + 2.0 ;
}
}
else
_failedPreviousCheckToClose = false ;
}
else
{
OnContainerClosed ( ) ;
}
}
2018-07-12 14:41:21 -07:00
int CContainerWeenie : : CheckOpenContainer ( CWeenieObject * other )
2018-03-29 17:01:57 -04:00
{
if ( _openedById )
{
if ( _openedById = = other - > GetID ( ) )
{
return WERROR_NONE ;
}
return WERROR_CHEST_ALREADY_OPEN ;
}
return WERROR_NONE ;
}
2018-07-12 14:41:21 -07:00
void CContainerWeenie : : HandleNoLongerViewing ( CWeenieObject * other )
2018-03-29 17:01:57 -04:00
{
if ( ! _openedById | | _openedById ! = other - > GetID ( ) )
return ;
OnContainerClosed ( ) ;
}
void CContainerWeenie : : DebugValidate ( )
{
CWeenieObject : : DebugValidate ( ) ;
2018-07-12 14:41:21 -07:00
# ifdef _DEBUG
assert ( ! GetWielderID ( ) ) ;
for ( auto wielded : m_Wielded )
{
assert ( wielded - > GetWielderID ( ) = = GetID ( ) ) ;
wielded - > DebugValidate ( ) ;
}
for ( auto item : m_Items )
{
2019-11-13 20:40:06 +00:00
if ( item - > GetContainerID ( ) ! = GetID ( ) )
2018-07-12 14:41:21 -07:00
assert ( item - > GetContainerID ( ) = = GetID ( ) ) ;
item - > DebugValidate ( ) ;
}
for ( auto pack : m_Packs )
{
assert ( pack - > GetContainerID ( ) = = GetID ( ) ) ;
pack - > DebugValidate ( ) ;
}
# endif
2018-03-29 17:01:57 -04:00
}
2019-07-07 20:56:15 +00:00
uint32_t CContainerWeenie : : RecalculateCoinAmount ( int currencyid )
2018-03-29 17:01:57 -04:00
{
int coinAmount = 0 ;
for ( auto item : m_Items )
{
2018-08-08 19:51:43 -05:00
if ( item - > m_Qualities . id = = currencyid )
2018-07-12 14:41:21 -07:00
coinAmount + = item - > InqIntQuality ( STACK_SIZE_INT , 1 , true ) ;
2018-03-29 17:01:57 -04:00
}
for ( auto pack : m_Packs )
2018-08-08 19:51:43 -05:00
coinAmount + = pack - > RecalculateCoinAmount ( currencyid ) ;
2018-03-29 17:01:57 -04:00
2019-10-27 17:56:23 +00:00
if ( AsPlayer ( ) & & currencyid = = W_COINSTACK_CLASS ) {
m_Qualities . SetInt ( COIN_VALUE_INT , coinAmount ) ;
NotifyIntStatUpdated ( COIN_VALUE_INT ) ;
}
2018-03-29 17:01:57 -04:00
return coinAmount ;
}
2018-04-15 02:21:51 -05:00
2019-07-07 20:56:15 +00:00
uint32_t CContainerWeenie : : ConsumeCoin ( int amountToConsume , int currencyid )
2018-03-29 17:01:57 -04:00
{
if ( amountToConsume < 1 )
return 0 ;
if ( AsPlayer ( ) ) //we don't need to recalculate this if we're a subcontainer
{
2018-08-08 19:51:43 -05:00
if ( RecalculateCoinAmount ( currencyid ) < amountToConsume ) //force recalculate our coin amount and check so we don't even try to consume if we don't have enough.
2018-04-15 02:21:51 -05:00
return 0 ;
}
2018-07-12 14:41:21 -07:00
std : : list < CWeenieObject * > removeList ;
2018-04-15 02:21:51 -05:00
2019-07-07 20:56:15 +00:00
uint32_t amountConsumed = 0 ;
2018-04-15 02:21:51 -05:00
for ( auto item : m_Items )
{
2018-07-12 14:41:21 -07:00
if ( item - > m_Qualities . id = = currencyid )
2018-04-15 02:21:51 -05:00
{
2018-07-12 14:41:21 -07:00
int stackSize = item - > InqIntQuality ( STACK_SIZE_INT , 1 , true ) ;
2018-04-15 02:21:51 -05:00
if ( stackSize < = amountToConsume )
{
2018-07-12 14:41:21 -07:00
removeList . push_back ( item ) ;
2018-04-15 02:21:51 -05:00
amountToConsume - = stackSize ;
amountConsumed + = stackSize ;
}
else
{
2018-07-12 14:41:21 -07:00
item - > SetStackSize ( stackSize - amountToConsume ) ;
2018-04-15 02:21:51 -05:00
amountConsumed + = amountToConsume ;
2019-10-27 17:57:21 +00:00
amountToConsume = 0 ;
2018-04-15 02:21:51 -05:00
break ;
}
}
}
for ( auto item : removeList )
item - > Remove ( ) ;
if ( amountToConsume > 0 )
{
for ( auto pack : m_Packs )
{
2019-07-07 20:56:15 +00:00
uint32_t amountFromPack = pack - > ConsumeCoin ( amountToConsume , currencyid ) ;
2018-04-15 02:21:51 -05:00
amountToConsume - = amountFromPack ;
amountConsumed + = amountFromPack ;
if ( amountToConsume < = 0 )
break ;
}
}
2019-10-27 17:56:23 +00:00
if ( AsPlayer ( ) & & currencyid = = W_COINSTACK_CLASS )
RecalculateCoinAmount ( W_COINSTACK_CLASS ) ;
2018-04-15 02:21:51 -05:00
return amountConsumed ;
}
2018-03-29 17:01:57 -04:00
void CContainerWeenie : : RecalculateEncumbrance ( )
{
int oldValue = InqIntQuality ( ENCUMB_VAL_INT , 0 ) ;
int newValue = 0 ;
for ( auto wielded : m_Wielded )
{
2018-07-12 14:41:21 -07:00
newValue + = wielded - > InqIntQuality ( ENCUMB_VAL_INT , 0 ) ;
2018-03-29 17:01:57 -04:00
}
for ( auto item : m_Items )
{
2018-07-12 14:41:21 -07:00
newValue + = item - > InqIntQuality ( ENCUMB_VAL_INT , 0 ) ;
2018-03-29 17:01:57 -04:00
}
for ( auto pack : m_Packs )
{
2018-07-12 14:41:21 -07:00
pack - > RecalculateEncumbrance ( ) ;
newValue + = pack - > InqIntQuality ( ENCUMB_VAL_INT , 0 ) ;
2018-03-29 17:01:57 -04:00
}
if ( oldValue ! = newValue )
{
2018-11-23 01:21:41 -06:00
if ( m_Qualities . m_WeenieType = = Corpse_WeenieType | | m_Qualities . m_WeenieType = = Chest_WeenieType )
{
CWeenieDefaults * defaults = g_pWeenieFactory - > GetWeenieDefaults ( m_Qualities . id ) ;
if ( defaults )
newValue + = defaults - > m_Qualities . GetInt ( ENCUMB_VAL_INT , 0 ) ;
}
2018-03-29 17:01:57 -04:00
m_Qualities . SetInt ( ENCUMB_VAL_INT , newValue ) ;
NotifyIntStatUpdated ( ENCUMB_VAL_INT , true ) ;
}
}
bool CContainerWeenie : : IsAttunedOrContainsAttuned ( )
{
for ( auto wielded : m_Wielded )
{
2018-07-12 14:41:21 -07:00
if ( wielded - > IsAttunedOrContainsAttuned ( ) )
2018-03-29 17:01:57 -04:00
return true ;
}
for ( auto item : m_Items )
{
2018-07-12 14:41:21 -07:00
if ( item - > IsAttunedOrContainsAttuned ( ) )
2018-03-29 17:01:57 -04:00
return true ;
}
for ( auto pack : m_Packs )
{
2018-07-12 14:41:21 -07:00
if ( pack - > IsAttunedOrContainsAttuned ( ) )
2018-03-29 17:01:57 -04:00
return true ;
}
return CWeenieObject : : IsAttunedOrContainsAttuned ( ) ;
}
bool CContainerWeenie : : HasContainerContents ( )
{
if ( ! m_Wielded . empty ( ) | | ! m_Items . empty ( ) | | ! m_Packs . empty ( ) )
return true ;
return CWeenieObject : : HasContainerContents ( ) ;
}
void CContainerWeenie : : AdjustToNewCombatMode ( )
{
2018-07-12 14:41:21 -07:00
std : : list < CWeenieObject * > wielded ;
2018-03-29 17:01:57 -04:00
Container_GetWieldedByMask ( wielded , WEAPON_LOC | HELD_LOC ) ;
COMBAT_MODE newCombatMode = COMBAT_MODE : : UNDEF_COMBAT_MODE ;
for ( auto item : wielded )
{
newCombatMode = item - > GetEquippedCombatMode ( ) ;
if ( newCombatMode ! = COMBAT_MODE : : UNDEF_COMBAT_MODE )
break ;
}
if ( newCombatMode = = COMBAT_MODE : : UNDEF_COMBAT_MODE )
newCombatMode = COMBAT_MODE : : MELEE_COMBAT_MODE ;
ChangeCombatMode ( newCombatMode , false ) ;
2018-09-17 22:55:33 -05:00
}
2019-07-07 20:56:15 +00:00
uint32_t CContainerWeenie : : GetItemCount ( int itemid )
2018-09-17 22:55:33 -05:00
{
int itemAmount = 0 ;
for ( auto item : m_Items )
{
if ( item - > m_Qualities . id = = itemid )
itemAmount + = item - > InqIntQuality ( STACK_SIZE_INT , 1 , true ) ;
}
for ( auto pack : m_Packs )
itemAmount + = pack - > GetItemCount ( itemid ) ;
return itemAmount ;
}
2019-07-07 20:56:15 +00:00
uint32_t CContainerWeenie : : ConsumeItem ( int amountToConsume , int itemid )
2018-09-17 22:55:33 -05:00
{
if ( amountToConsume < 1 )
return 0 ;
if ( AsPlayer ( ) ) //we don't need to recalculate this if we're a subcontainer
{
if ( GetItemCount ( itemid ) < amountToConsume ) //force recalculate our coin amount and check so we don't even try to consume if we don't have enough.
return 0 ;
}
std : : list < CWeenieObject * > removeList ;
2019-07-07 20:56:15 +00:00
uint32_t amountConsumed = 0 ;
2018-09-17 22:55:33 -05:00
for ( auto item : m_Items )
{
if ( item - > m_Qualities . id = = itemid )
{
int stackSize = item - > InqIntQuality ( STACK_SIZE_INT , 1 , true ) ;
if ( stackSize < = amountToConsume )
{
removeList . push_back ( item ) ;
amountToConsume - = stackSize ;
amountConsumed + = stackSize ;
}
else
{
item - > SetStackSize ( stackSize - amountToConsume ) ;
//amountToConsume -= stackSize;
amountConsumed + = amountToConsume ;
break ;
}
}
}
for ( auto item : removeList )
item - > Remove ( ) ;
if ( amountToConsume > 0 )
{
for ( auto pack : m_Packs )
{
2019-07-07 20:56:15 +00:00
uint32_t amountFromPack = pack - > ConsumeItem ( amountToConsume , itemid ) ;
2018-09-17 22:55:33 -05:00
amountToConsume - = amountFromPack ;
amountConsumed + = amountFromPack ;
if ( amountToConsume < = 0 )
break ;
}
}
return amountConsumed ;
2019-09-03 14:18:02 +00:00
}