2016-01-28 14:52:40 +01:00
|
|
|
/** @file
|
|
|
|
|
*
|
|
|
|
|
* @par History
|
|
|
|
|
* - 2007/06/17 Shinigami: added config.world_data_path
|
|
|
|
|
* - 2008/12/17 MuadDib: Added item.tile_layer - returns layer entry from tiledata/tiles.cfg
|
|
|
|
|
* - 2009/09/14 MuadDib: Added slot support to equip_loaded_item() and add_loaded_item()
|
|
|
|
|
* - 2009/09/18 MuadDib: Spellbook rewrite to deal with only bits, not scrolls inside them.
|
|
|
|
|
*/
|
2016-02-11 22:54:43 +01:00
|
|
|
|
|
|
|
|
|
2018-01-29 21:55:48 +01:00
|
|
|
#include <stddef.h>
|
|
|
|
|
#include <string>
|
2016-02-11 22:54:43 +01:00
|
|
|
|
|
|
|
|
#include "../clib/cfgelem.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "../clib/cfgfile.h"
|
2016-02-11 22:54:43 +01:00
|
|
|
#include "../clib/fileutil.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "../clib/logfacility.h"
|
|
|
|
|
#include "../clib/rawtypes.h"
|
2016-02-11 22:54:43 +01:00
|
|
|
#include "../clib/strutil.h"
|
|
|
|
|
#include "../clib/timer.h"
|
2018-12-21 20:27:05 +01:00
|
|
|
#include "../plib/clidata.h"
|
2016-02-11 22:54:43 +01:00
|
|
|
#include "../plib/systemstate.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "containr.h"
|
|
|
|
|
#include "fnsearch.h"
|
|
|
|
|
#include "globals/object_storage.h"
|
|
|
|
|
#include "globals/state.h"
|
|
|
|
|
#include "item/item.h"
|
|
|
|
|
#include "loaddata.h"
|
|
|
|
|
#include "mobile/charactr.h"
|
|
|
|
|
#include "objecthash.h"
|
|
|
|
|
#include "polclass.h"
|
|
|
|
|
#include "spelbook.h"
|
|
|
|
|
#include "uobject.h"
|
2016-02-11 22:54:43 +01:00
|
|
|
|
2026-01-17 10:30:21 +01:00
|
|
|
|
|
|
|
|
namespace Pol::Core
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
void defer_item_insertion( Items::Item* item, pol_serial_t container_serial )
|
|
|
|
|
{
|
|
|
|
|
objStorageManager.deferred_insertions.insert( std::make_pair( container_serial, item ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void insert_deferred_items()
|
|
|
|
|
{
|
|
|
|
|
if ( objStorageManager.deferred_insertions.empty() )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
int num_until_dot = 1000;
|
|
|
|
|
unsigned int nobjects = 0;
|
|
|
|
|
Tools::Timer<> timer;
|
|
|
|
|
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINT( " deferred inserts:" );
|
2016-02-19 19:26:35 +01:00
|
|
|
|
2026-01-31 09:14:02 +01:00
|
|
|
for ( auto& deferred_insertion : objStorageManager.deferred_insertions )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
if ( --num_until_dot == 0 )
|
|
|
|
|
{
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINT( "." );
|
2016-02-19 19:26:35 +01:00
|
|
|
num_until_dot = 1000;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-31 09:14:02 +01:00
|
|
|
pol_serial_t container_serial = deferred_insertion.first;
|
|
|
|
|
UObject* obj = deferred_insertion.second;
|
2016-02-19 19:26:35 +01:00
|
|
|
|
|
|
|
|
if ( IsCharacter( container_serial ) )
|
|
|
|
|
{
|
|
|
|
|
Mobile::Character* chr = system_find_mobile( container_serial );
|
|
|
|
|
Items::Item* item = static_cast<Items::Item*>( obj );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( chr != nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
equip_loaded_item( chr, item );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-01-12 06:51:44 +01:00
|
|
|
ERROR_PRINTLN(
|
2024-05-05 09:13:12 +02:00
|
|
|
"Item {:#x} is supposed to be on Character {:#x}, but that character cannot be ",
|
2024-01-12 06:51:44 +01:00
|
|
|
item->serial, container_serial );
|
2016-02-19 19:26:35 +01:00
|
|
|
|
|
|
|
|
// Austin - Aug. 10, 2006
|
|
|
|
|
// Removes the object if ignore_load_errors is enabled and the character can't be found.
|
|
|
|
|
if ( !Plib::systemstate.config.ignore_load_errors )
|
|
|
|
|
throw std::runtime_error( "Data file integrity error" );
|
2026-01-18 09:35:52 +01:00
|
|
|
|
|
|
|
|
ERROR_PRINTLN( "Ignore load errors enabled. Removing object." );
|
|
|
|
|
obj->destroy();
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Items::Item* cont_item = system_find_item( container_serial );
|
|
|
|
|
Items::Item* item = static_cast<Items::Item*>( obj );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( cont_item != nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
add_loaded_item( cont_item, item );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-01-12 06:51:44 +01:00
|
|
|
ERROR_PRINTLN(
|
2024-05-05 09:13:12 +02:00
|
|
|
"Item {:#x} is supposed to be in container {:#x}, but that container cannot be found.",
|
2024-01-12 06:51:44 +01:00
|
|
|
item->serial, container_serial );
|
2016-02-19 19:26:35 +01:00
|
|
|
|
|
|
|
|
// Austin - Aug. 10, 2006
|
|
|
|
|
// Removes the object if ignore_load_errors is enabled and the character can't be found.
|
|
|
|
|
if ( !Plib::systemstate.config.ignore_load_errors )
|
|
|
|
|
throw std::runtime_error( "Data file integrity error" );
|
2026-01-18 09:35:52 +01:00
|
|
|
|
|
|
|
|
ERROR_PRINTLN( "Ignore load errors enabled. Removing object." );
|
|
|
|
|
obj->destroy();
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
++nobjects;
|
|
|
|
|
}
|
|
|
|
|
timer.stop();
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( " {} elements in {} ms.", nobjects, timer.ellapsed() );
|
2016-02-11 22:54:43 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
objStorageManager.deferred_insertions.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void equip_loaded_item( Mobile::Character* chr, Items::Item* item )
|
|
|
|
|
{
|
2018-12-22 00:32:47 +01:00
|
|
|
item->layer = Plib::tilelayer( item->graphic ); // adjust for tiledata changes
|
2024-01-10 18:29:10 +01:00
|
|
|
item->tile_layer = item->layer; // adjust for tiledata changes
|
2016-02-19 19:26:35 +01:00
|
|
|
|
|
|
|
|
if ( chr->equippable( item ) && item->check_equiptest_scripts( chr, true ) &&
|
|
|
|
|
item->check_equip_script( chr, true ) &&
|
|
|
|
|
!item->orphan() ) // dave added 1/28/3, item might be destroyed in RTC script
|
|
|
|
|
{
|
|
|
|
|
chr->equip( item );
|
|
|
|
|
item->clear_dirty(); // equipping sets dirty
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-01-18 09:35:52 +01:00
|
|
|
|
|
|
|
|
ERROR_PRINTLN(
|
|
|
|
|
"Item {:#x} is supposed to be equipped on Character {:#x}, but is not 'equippable' on that "
|
|
|
|
|
"character.",
|
|
|
|
|
item->serial, chr->serial );
|
|
|
|
|
UContainer* bp = chr->backpack();
|
|
|
|
|
if ( bp )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
2026-01-18 09:35:52 +01:00
|
|
|
stateManager.gflag_enforce_container_limits = false;
|
|
|
|
|
bool canadd = bp->can_add( *item );
|
|
|
|
|
u8 slotIndex = item->slot_index();
|
|
|
|
|
bool add_to_slot = bp->can_add_to_slot( slotIndex );
|
|
|
|
|
if ( canadd && add_to_slot && item->slot_index( slotIndex ) )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
2026-01-18 09:35:52 +01:00
|
|
|
bp->add_at_random_location( item );
|
|
|
|
|
// leaving dirty
|
|
|
|
|
stateManager.gflag_enforce_container_limits = true;
|
|
|
|
|
ERROR_PRINTLN( "I'm so cool, I put it in the character's backpack!" );
|
|
|
|
|
return;
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2026-01-18 09:35:52 +01:00
|
|
|
|
|
|
|
|
stateManager.gflag_enforce_container_limits = true;
|
|
|
|
|
ERROR_PRINTLN( "Tried to put it in the character's backpack, but it wouldn't fit." );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ERROR_PRINTLN(
|
|
|
|
|
"Tried to put it in the character's backpack, but there isn't one. That's naughty..." );
|
2016-02-11 22:54:43 +01:00
|
|
|
}
|
2026-01-18 09:35:52 +01:00
|
|
|
throw std::runtime_error( "Data file integrity error" );
|
2016-02-11 22:54:43 +01:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
|
|
|
|
|
void add_loaded_item( Items::Item* cont_item, Items::Item* item )
|
|
|
|
|
{
|
2016-12-12 22:21:59 +01:00
|
|
|
if ( cont_item->isa( UOBJ_CLASS::CLASS_CONTAINER ) )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
UContainer* cont = static_cast<UContainer*>( cont_item );
|
|
|
|
|
|
|
|
|
|
// Convert spellbook to use bitwise system, not scrolls.
|
|
|
|
|
if ( cont->script_isa( POLCLASS_SPELLBOOK ) )
|
|
|
|
|
{
|
|
|
|
|
// if can't add, means spell already there.
|
|
|
|
|
if ( !cont->can_add( *item ) )
|
|
|
|
|
{
|
|
|
|
|
item->destroy();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// this is an oldschool book, oldschool contents. We need to create the bitwise
|
|
|
|
|
// and handle for the first time before destroying the scrolls.
|
|
|
|
|
Spellbook* book = static_cast<Spellbook*>( cont );
|
|
|
|
|
|
|
|
|
|
u16 spellnum =
|
|
|
|
|
USpellScroll::convert_objtype_to_spellnum( item->objtype_, book->spell_school );
|
|
|
|
|
u8 spellslot = spellnum & 7;
|
|
|
|
|
if ( spellslot == 0 )
|
|
|
|
|
spellslot = 8;
|
|
|
|
|
book->bitwise_contents[( spellnum - 1 ) >> 3] |= 1 << ( spellslot - 1 );
|
|
|
|
|
item->destroy();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stateManager.gflag_enforce_container_limits = false;
|
|
|
|
|
bool canadd = cont->can_add( *item );
|
|
|
|
|
u8 slotIndex = item->slot_index();
|
|
|
|
|
bool add_to_slot = cont->can_add_to_slot( slotIndex );
|
|
|
|
|
if ( !canadd )
|
|
|
|
|
{
|
2024-05-05 09:13:12 +02:00
|
|
|
ERROR_PRINTLN( "Can't add Item {:#x} to container {:#x}", item->serial, cont->serial );
|
2016-02-19 19:26:35 +01:00
|
|
|
throw std::runtime_error( "Data file error" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( !add_to_slot || !item->slot_index( slotIndex ) )
|
|
|
|
|
{
|
2024-05-05 09:13:12 +02:00
|
|
|
ERROR_PRINTLN( "Can't add Item {:#x} to container {:#x} at slot {:#x}", item->serial,
|
2024-01-12 06:51:44 +01:00
|
|
|
cont->serial, slotIndex );
|
2016-02-19 19:26:35 +01:00
|
|
|
throw std::runtime_error( "Data file error" );
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-03 23:02:53 +01:00
|
|
|
cont->add( item, item->pos2d() );
|
2016-02-19 19:26:35 +01:00
|
|
|
item->clear_dirty(); // adding sets dirty
|
|
|
|
|
|
|
|
|
|
stateManager.gflag_enforce_container_limits = true;
|
|
|
|
|
|
|
|
|
|
// if (new_parent_cont)
|
2018-04-03 04:13:03 +02:00
|
|
|
// parent_conts.push( cont );
|
2016-02-19 19:26:35 +01:00
|
|
|
// if (item->isa( UObject::CLASS_CONTAINER ))
|
2018-04-03 04:13:03 +02:00
|
|
|
// parent_conts.push( static_cast<UContainer*>(item) );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Container type {:#x} contains items, but is not a container class",
|
2024-01-12 06:51:44 +01:00
|
|
|
cont_item->objtype_ );
|
2016-02-19 19:26:35 +01:00
|
|
|
throw std::runtime_error( "Config file error" );
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-01-17 10:30:21 +01:00
|
|
|
} // namespace Pol::Core
|