/*
* Seven Kingdoms: Ancient Adversaries
*
* Copyright 1997,1998 Enlight Software Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
//Filename : ODYNARRB.CPP
//Description : Object Dynamic Array Version B
#include
#include
//----------------------------------------------------------//
//
// Version B is different from Version A as :
//
// - when linkout() it doesn't not physically shift the memory
// upwards.
//
// - when linkin() it will search for empty rooms in the array
// before appending space at the end of the array.
//
//----------------------------------------------------------//
#define EMPTY_ROOM_ALLOC_STEP 5
//--------- BEGIN OF FUNCTION DynArrayB::DynArrayB -------//
//
// eleSize = size of each element
// [int] blockNum = number of entity of each block of element
// increased ( default : 30 )
// [int] reuseIntervalDays = no. of game days deleted records needed to be kept before reusing them.
// (default: 0)
//
DynArrayB::DynArrayB(int eleSize,int blockNum,int reuseIntervalDays) : DynArray(eleSize, blockNum)
{
empty_room_array = NULL;
empty_room_num = 0;
empty_room_count = 0;
reuse_interval_days = reuseIntervalDays;
}
//----------- END OF FUNCTION DynArrayB::DynArrayB -----//
//--------- BEGIN OF FUNCTION DynArrayB::~DynArrayB -------//
//
DynArrayB::~DynArrayB()
{
if( empty_room_array )
mem_del( empty_room_array );
}
//----------- END OF FUNCTION DynArrayB::DynArrayB -----//
//---------- BEGIN OF FUNCTION DynArrayB::linkin -----------//
//
// ent
//
//
// - when linkin() it will search for empty rooms in the array
// before appending space at the end of the array.
//
// - If found, then it will use that room
//
// - Otherwise, it will link a record at the END of the array
//
// WARNING : After calling linkin() all pointers to the linklist body
// should be updated, because mem_resize() will move the body memory
//
void DynArrayB::linkin(void* ent)
{
//------- detect for empty rooms --------//
int reusedFlag=0;
if( empty_room_count > 0 )
{
if( reuse_interval_days )
{
//------ first in, first out approach -----//
if( info.game_date >= empty_room_array[0].deleted_game_date + reuse_interval_days )
{
cur_pos = empty_room_array[0].recno;
memmove( empty_room_array, empty_room_array+1, sizeof(empty_room_array[0]) * (empty_room_count-1) );
empty_room_count--;
reusedFlag = 1;
}
}
else
{
//------ last in, first out approach -----//
cur_pos = empty_room_array[empty_room_count-1].recno;
empty_room_count--;
reusedFlag = 1;
}
}
if( !reusedFlag )
{
last_ele++;
cur_pos=last_ele;
}
//---------- regular link in -----------//
if ( last_ele > ele_num ) // not enough empty element left to hold the new entity
resize( ele_num + block_num );
if ( ent )
memcpy(body_buf+(cur_pos-1)*ele_size, ent, ele_size );
else
*(body_buf+(cur_pos-1)*ele_size) = NULL;
}
//---------- END OF FUNCTION DynArrayB::linkin ------------//
//----------- BEGIN OF FUNCTION DynArrayB::linkout ---------//
//
// - when linkout() it doesn't not physically shift the memory
// upwards.
//
// - it record the address of this empty room at empty room list
//
// [int] delPos = the position (recno) of the item to be deleted
// ( default : recno() current record no. )
//
void DynArrayB::linkout(int delPos)
{
if( delPos < 0 )
delPos = cur_pos;
if( delPos == 0 || delPos > last_ele )
return;
//-------- add to the empty room list ---------//
if( ++empty_room_count > empty_room_num )
{
empty_room_array = (EmptyRoom*) mem_resize( empty_room_array,
(empty_room_num+EMPTY_ROOM_ALLOC_STEP) * sizeof(*empty_room_array) );
empty_room_num += EMPTY_ROOM_ALLOC_STEP;
}
empty_room_array[empty_room_count-1].recno = delPos;
empty_room_array[empty_room_count-1].deleted_game_date = info.game_date;
memset( body_buf+(delPos-1)*ele_size, 0, ele_size );
}
//------------ END OF FUNCTION DynArrayB::linkout ----------//
//---------- Begin of function DynArrayB::write_file -------------//
//
// Write current dynamic array into file,
// read_file() can be used to retrieve it.
//
// writeFile = the pointer to the writing file
//
// Return : 1 - write successfully
// 0 - writing error
//
int DynArrayB::write_file(File* filePtr)
{
if( !filePtr->file_write( this, sizeof(DynArray) ) )
return 0;
//---------- write body_buf ---------//
if( last_ele > 0 )
{
if( !filePtr->file_write( body_buf, ele_size*last_ele ) )
return 0;
}
//---------- write empty_room_array ---------//
write_empty_room(filePtr);
return 1;
}
//------------- End of function DynArrayB::write_file --------------//
//---------- Begin of function DynArrayB::read_file -------------//
//
// Read a saved dynamic array from file, it must be saved with write_file()
//
// readFile = the pointer to the writing file
//
// Return : 1 - read successfully
// 0 - writing error
//
int DynArrayB::read_file(File* filePtr)
{
char* bodyBuf = body_buf; // preserve body_buf which has been allocated
if( !filePtr->file_read( this, sizeof(DynArray) ) )
return 0;
//---------- read body_buf ---------//
body_buf = mem_resize( bodyBuf, ele_size*ele_num );
if( last_ele > 0 )
{
if( !filePtr->file_read( body_buf, ele_size*last_ele ) )
return 0;
}
//---------- read empty_room_array ---------//
read_empty_room(filePtr);
//------------------------------------------//
start(); // go top
return 1;
}
//------------- End of function DynArrayB::read_file --------------//
//---------- Begin of function DynArrayB::write_empty_room -------------//
//
// Write current dynamic array into file,
// read_file() can be used to retrieve it.
//
// writeFile = the pointer to the writing file
//
// Return : 1 - write successfully
// 0 - writing error
//
int DynArrayB::write_empty_room(File* filePtr)
{
filePtr->file_put_short( empty_room_count );
//---------- write empty_room_array ---------//
if( empty_room_count > 0 )
{
if( !filePtr->file_write( empty_room_array,
sizeof(EmptyRoom) * empty_room_count ) )
{
return 0;
}
}
return 1;
}
//------------- End of function DynArrayB::write_empty_room --------------//
//---------- Begin of function DynArrayB::read_empty_room -------------//
//
// Read a saved dynamic array from file, it must be saved with write_file()
//
// readFile = the pointer to the writing file
//
// Return : 1 - read successfully
// 0 - writing error
//
int DynArrayB::read_empty_room(File* filePtr)
{
empty_room_num = empty_room_count = filePtr->file_get_short(); // set both to the same
//---------- read empty_room_array ---------//
if( empty_room_count > 0 )
{
empty_room_array = (EmptyRoom*) mem_resize( empty_room_array,
sizeof(EmptyRoom) * empty_room_count );
if( !filePtr->file_read( empty_room_array,
sizeof(*empty_room_array) * empty_room_count ) )
{
return 0;
}
}
else // when empty_room_count == 0
{
if( empty_room_array )
{
mem_del( empty_room_array );
empty_room_array = NULL;
}
}
//------------------------------------------//
return 1;
}
//------------- End of function DynArrayB::read_empty_room --------------//
//---------- Begin of function DynArrayB::packed_recno -------------//
//
// Given the recno unpacked, it returns the recno packed.
//
// packed_recno() is the recno when the array is packed
// (deleted record are actually removed)
//
// recNo = given the recno unpacked
//
// return : the recno when packed
//
int DynArrayB::packed_recno(int recNo)
{
int i, packedRecno = recNo;
for( i=0 ; i filePtr - pointer to the file object.
// objectSize - size of the objects pointed to by the pointers.
//
int DynArrayB::write_ptr_array(File* filePtr, int objectSize)
{
int i;
char* elePtr;
filePtr->file_put_short( size() );
for( i=1; i<=size() ; i++ )
{
elePtr = (char*) get_ptr(i);
//----- write 0 if the monster is deleted -----//
if( !elePtr ) // the monster is deleted
{
filePtr->file_put_short(0);
}
else
{
filePtr->file_put_short(1); // the monster exists
if( !filePtr->file_write(elePtr, objectSize) )
return 0;
}
}
//------- write empty room array --------//
write_empty_room(filePtr);
return 1;
}
//--------- End of function DynArrayB::write_ptr_array ---------------//
//-------- Start of function DynArrayB::read_ptr_array -------------//
//
// Read a DynArrayB with pointer data elements previously saved by
// write_ptr_array().
//
// filePtr - pointer to the file object.
// objectSize - size of the objects pointed to by the pointers.
// createEleFunc - function for creating a blank object.
//
int DynArrayB::read_ptr_array(File* filePtr, int objectSize, CreateEleFP createEleFunc)
{
int i;
char* elePtr;
int eleCount = filePtr->file_get_short(); // get no. of monsters from file
for( i=1 ; i<=eleCount ; i++ )
{
if( filePtr->file_get_short()==0 ) // the monster has been deleted
{
add_blank(1); // it's a DynArrayB function
}
else
{
elePtr = (*createEleFunc)();
if( !filePtr->file_read(elePtr, objectSize) )
return 0;
}
}
//-------- linkout() those record added by add_blank() ----------//
//-- So they will be marked deleted in DynArrayB and can be -----//
//-- undeleted and used when a new record is going to be added --//
for( i=size() ; i>0 ; i-- )
{
DynArrayB::go(i); // since DynArrayB has its own go() which will call GroupArray::go()
if( get_ptr() == NULL ) // add_blank() record
linkout();
}
//------- read empty room array --------//
read_empty_room(filePtr);
return 1;
}
//--------- End of function DynArrayB::read_ptr_array ---------------//