/*
* Copyright (C) 1995-1997 Christopher D. Granz
*
* This header may not be removed.
*
* Refer to the file "License" included in this package for further
* information and before using any of the following.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include "sapphire.h"
/*
* Defines
*/
#define STRING_HEADER_SIZE ( sizeof( struct string_header ) - 1 )
/*
* Structures
*/
struct string_header
{
struct string_header * pNext;
unsigned short int usiCount;
unsigned short int usiLen;
char cStr[5];
};
/*
* Globals
*/
char * pStrBuffersBegin;
char * pStrBuffers;
int iMaxStrBuffers;
int iNumStrBuffers;
static int iMappedFile;
int iMaxFragments;
static int iFragmented;
static struct string_header * pFirstHeader;
static struct string_header * pHeaderFree;
bool bStrComparing;
/*
* Functions
*/
void mem_init( void )
{
/*
* Thanks to Furey (Developer of Merc and Envy) help with
* mmap().
*/
if ( iMemoryMode == MEMORY_MODE_DISK )
{
char cBuf[MAX_STRING];
char c[MAX_STRING + 2];
int i, iTemp;
if ( lStringSpace <= 0 )
sap_fatal( "Cannot map 0 bytes from file for strings." );
if ( iMaxStrBuffers <= 0 )
sap_fatal( "Cannot map 0 string buffers from file." );
strcpy( cBuf, pTempDir );
strcat( cBuf, MEMORY_FILE );
if ( ( iMappedFile = open( cBuf, ( O_RDWR | O_CREAT ),
( S_IRUSR | S_IWUSR ) ) ) < 0 )
sap_fatal( "Open file: Map file: %s.", strerror( errno ) );
zero_out( c, ( MAX_STRING + 2 ) );
iTemp = ( ( lStringSpace / 512 ) + 1 );
for ( i = 0; i < iTemp; i++ )
write( iMappedFile, c, 512 );
for ( i = 0; i < iMaxStrBuffers; i++ )
write( iMappedFile, c, MAX_STRING );
pStrings = mmap( NULL, ( lStringSpace + ( MAX_STRING
* iMaxStrBuffers ) ), ( PROT_READ | PROT_WRITE ),
MAP_SHARED, iMappedFile, 0 );
if ( pStrings < 0 )
sap_fatal( "Map: %s.", strerror( errno ) );
pStringsEnd = ( pStrings + lStringSpace - 1 );
pStringsPos = pStrings;
pStrBuffers = ( pStrings + lStringSpace );
pStrBuffersBegin = pStrBuffers;
}
else
{
if ( lStringSpace <= 0 )
sap_fatal( "%s: Cannot allocate 0 bytes for strings." );
pStrings = calloc( lStringSpace, 1 );
if ( pStrings == NULL )
sap_fatal(
"Cannot allocate %ld bytes for strings.", lStringSpace );
pStringsEnd = ( pStrings + lStringSpace - 1 );
pStringsPos = pStrings;
if ( iMaxStrBuffers <= 0 )
sap_fatal( "Cannot allocate 0 string buffers." );
pStrBuffers = calloc( iMaxStrBuffers, MAX_STRING );
if ( pStrBuffers == NULL )
sap_fatal( "Cannot allocate %d string buffers.",
iMaxStrBuffers );
pStrBuffersBegin = pStrBuffers;
}
pFirstHeader = (struct string_header *) pStrings;
pHeaderFree = pFirstHeader;
pFirstHeader->usiLen = ( lStringSpace - STRING_HEADER_SIZE );
}
void mem_clean_up( void )
{
if ( iMemoryMode == MEMORY_MODE_DISK )
{
char cBuf[MAX_STRING];
munmap( pStrings, ( lStringSpace + ( MAX_STRING
* iMaxStrBuffers ) ) );
close( iMappedFile );
strcpy( cBuf, pTempDir );
strcat( cBuf, MEMORY_FILE );
unlink( cBuf );
}
else
{
free_mem( (void **) &pStrBuffers );
free_mem( (void **) &pStrings );
}
}
/*
* Allocates some memory and checks for failure.
*/
void *alloc_mem( register size_t rsMem )
{
register void *pMem;
if ( ( pMem = calloc( 1, rsMem ) ) == NULL )
{
lprintf( "**** [SYSTEM]:\n "
"Cannot allocate %ld bytes of memory.\n", (long) rsMem );
#ifdef DEBUG
abort( );
#else
exit( 1 );
#endif
}
return ( pMem );
}
/*
* Reallocates some memory and checks for failure.
*/
void *realloc_mem( register void *pMem, register size_t rsMem )
{
if ( ( pMem = realloc( pMem, rsMem ) ) == NULL )
{
lprintf( "**** [SYSTEM]:\n "
"Cannot reallocate %ld bytes of memory.\n", (long) rsMem );
#ifdef DEBUG
abort( );
#else
exit( 1 );
#endif
}
return ( pMem );
}
/*
* Free some memory and set the pointer to NULL.
*/
void free_mem( register void **ppMem )
{
if ( ppMem != NULL && *ppMem != NULL )
{
free( *ppMem );
*ppMem = NULL;
}
}
/*
* Initialize some memory.
*/
void zero_out( register void *pMem, register size_t rsMem )
{
register byte *pBMem = pMem;
register size_t rs = 0;
while ( rs < rsMem )
pBMem[rs++] = 0;
}
/*
* Duplicates a string in memory.
*/
char *str_dup( register char *pStr )
{
register int riLen;
if ( pStr == NULL || pStr[0] == '\0' )
return ( EMPTY_STRING );
riLen = strlen( pStr );
if ( riLen >= MAX_STRING )
riLen = ( MAX_STRING - 1 );
return ( strncpy( alloc_mem( riLen + 1 ), pStr, riLen ) );
}
/*
* Frees a string allocated by str_dup() and returns a buffered copy
* of it.
*
* No longer used as of Sapphire v0.3
*/
#if 0
char *unstr_dup( register char **ppStr )
{
register char *pOutput;
register int riLen;
if ( ppStr == NULL || *ppStr == NULL || *ppStr[0] == '\0' )
return ( EMPTY_STRING );
riLen = strlen( *ppStr );
if ( riLen >= MAX_STRING )
riLen = ( MAX_STRING - 1 );
pOutput = strncpy( new_buffer( ), *ppStr, riLen );
free_mem( (void **) ppStr );
return ( pOutput );
}
#endif
/*
* Allocates space for a string. Better then str_dup() for most
* things.
*/
string save_string( register char *pStr )
{
return ( str_dup( pStr ) );
#if 0
register struct string_header *p;
register int riLen;
if ( pStr == NULL || pStr[0] == '\0' )
return ( EMPTY_STRING );
if ( pStr > pStrings && pStr < pStringsEnd )
{
p = (struct string_header *) ( pStr - STRING_HEADER_SIZE );
p->usiCount++;
return ( pStr );
}
if ( iFragmented == iMaxFragments )
defrag_string_space( );
if ( pHeaderFree == NULL )
return ( str_dup( pStr ) );
riLen = ( strlen( pStr ) + 1 );
if ( riLen >= MAX_STRING )
riLen = ( MAX_STRING - 1 );
for ( p = pHeaderFree; p != NULL; p = p->pNext )
{
if ( p->usiCount == 0 && p->usiLen >= riLen )
break;
}
if ( p == NULL )
return ( str_dup( pStr ) );
if ( ( p->usiLen - riLen ) > STRING_HEADER_SIZE )
{
register struct string_header *pTemp;
pTemp = (struct string_header *) ( (char *) p + riLen
+ STRING_HEADER_SIZE );
pTemp->pNext = p->pNext;
pTemp->usiCount = 0;
pTemp->usiLen = p->usiLen - ( riLen + STRING_HEADER_SIZE );
p->usiLen = riLen;
p->pNext = pTemp;
if ( p == pHeaderFree )
pHeaderFree = pTemp;
}
else if ( p == pHeaderFree )
{
for ( pHeaderFree = pFirstHeader; pHeaderFree != NULL;
pHeaderFree = pHeaderFree->pNext )
{
if ( pHeaderFree->usiCount == 0 )
break;
}
}
strncpy( p->cStr, pStr, riLen );
p->usiCount++;
return ( p->cStr );
#endif
}
/*
* Frees a string allocated by save_string().
*/
void free_string( register string *pStr )
{
if ( pStr == NULL || *pStr == NULL || **pStr == '\0' )
return;
free_mem( (void **) pStr );
#if 0
register struct string_header *p;
if ( pStr == NULL || *pStr == NULL || **pStr == '\0' )
return;
if ( *pStr > pStrings && *pStr < pStringsEnd )
{
p = (struct string_header *) ( *pStr - STRING_HEADER_SIZE );
if ( --p->usiCount > 0 )
return;
if ( pHeaderFree > p )
pHeaderFree = p;
if ( p->pNext != NULL && p->pNext->usiCount == 0 )
{
p->usiLen += ( p->pNext->usiLen + STRING_HEADER_SIZE );
p->pNext = p->pNext->pNext;
}
iFragmented--;
*pStr = NULL;
}
else
free_mem( (void **) pStr );
#endif
}
/*
* Merges free blocks. Usually only called if save_string() cannot
* find a large enough free block.
*/
void defrag_string_space( void )
{
register struct string_header *p;
register struct string_header *pLast;
pLast = NULL;
pHeaderFree = NULL;
for ( p = pFirstHeader; p != NULL; p = p->pNext )
{
if ( p->usiCount > 0 )
{
pLast = NULL;
continue;
}
if ( pLast == NULL )
{
pLast = p;
if ( p > pHeaderFree )
pHeaderFree = p;
continue;
}
pLast->usiLen += ( p->usiLen + STRING_HEADER_SIZE );
pLast->pNext = p->pNext;
}
iFragmented = 0;
}
/*
* Clear all string buffers.
*/
void free_buffers( void )
{
pStrBuffers = pStrBuffersBegin;
iNumStrBuffers = 0;
}
/*
* Grab a new buffer.
*/
char *new_buffer( void )
{
register char *pNewBuffer;
if ( iNumStrBuffers == iMaxStrBuffers )
{
sap_warning( "No free string buffers; freeing." );
free_buffers( );
}
pNewBuffer = pStrBuffers;
pStrBuffers += MAX_STRING;
iNumStrBuffers++;
*pNewBuffer = '\0';
return ( pNewBuffer );
}
/*
* Create a new PC (Player Character).
*/
CHAR_DATA *new_pc( void )
{
CHAR_DATA *pCharNew;
if ( pCharFree == NULL )
{
pCharNew = alloc_mem( sizeof( *pCharNew ) );
zero_out( pCharNew, sizeof( *pCharNew ) );
}
else
{
pCharNew = pCharFree;
pCharFree = pCharFree->pNext;
}
pCharNew->pPCData = alloc_mem( sizeof( *pCharNew->pPCData ) );
zero_out( pCharNew->pPCData, sizeof( *pCharNew->pPCData ) );
pCharNew->pStats = alloc_mem( sizeof( *pCharNew->pStats ) );
zero_out( pCharNew->pStats, sizeof( *pCharNew->pStats ) );
pCharNew->iCharType = CHAR_PC;
pCharNew->sLongDesc = EMPTY_STRING;
pCharNew->pPCData->sPassword = EMPTY_STRING;
pCharNew->pPCData->sName = EMPTY_STRING;
pCharNew->pPCData->sPrompt = save_string( ">" );
pCharNew->pPCData->sGuild = EMPTY_STRING;
char_to_list( pCharNew );
return ( pCharNew );
}
/*
* Create a new instance of an NPC (Non-Player Character).
*/
CHAR_DATA *new_npc( NPC_INDEX_DATA *pNPCIndex, CHAR_DATA *pActor )
{
CHAR_DATA *pNewNPC;
PROGRAM_DATA *pProgram;
SCRIPT_DATA *pScript;
TRIGGER_DATA *pTrigger;
int i;
if ( pCharFree == NULL )
{
pNewNPC = alloc_mem( sizeof( *pNewNPC ) );
zero_out( pNewNPC, sizeof( *pNewNPC ) );
}
else
{
pNewNPC = pCharFree;
pCharFree = pCharFree->pNext;
}
pNewNPC->pNPCData = alloc_mem( sizeof( *pNewNPC->pNPCData ) );
zero_out( pNewNPC->pNPCData, sizeof( *pNewNPC->pNPCData ) );
pNewNPC->pStats = alloc_mem( sizeof( *pNewNPC->pStats ) );
pNewNPC->iCharType = CHAR_NPC;
pNewNPC->pNPCData->pNPCIndex = pNPCIndex;
if ( pNPCIndex->pProgram != NULL )
{
GENERIC_DATA *pGen;
GENERIC_DATA *pGen2;
QUEST_VAR_DATA *pVar;
QUEST_VAR_DATA *pVar2;
SCRIPT_DATA *pScript2;
TRIGGER_DATA *pTrigger2;
TRIGGER_ARG_DATA *pTriggerArg;
TRIGGER_ARG_DATA *pTriggerArg2;
pProgram = alloc_mem( sizeof( *pProgram ) );
pNewNPC->pNPCData->pProgram = pProgram;
for ( pGen = pNPCIndex->pProgram->pQuestDataList; pGen != NULL;
pGen = pGen->pNext )
{
pGen2 = alloc_mem( sizeof( *pGen2 ) );
pGen2->pData = pGen->pData;
pGen2->pNext = pProgram->pQuestDataList;
pProgram->pQuestDataList = pGen2;
}
for ( pVar = pNPCIndex->pProgram->pQuestVars; pVar != NULL;
pVar = pVar->pNext )
{
pVar2 = alloc_mem( sizeof( *pVar2 ) );
pVar2->iType = pVar->iType;
pVar2->sName = save_string( pVar->sName );
if ( pVar2->iType == NUMBER_VAR_STRING )
pVar2->uData.s = EMPTY_STRING;
pVar2->pNext = pProgram->pQuestVars;
pProgram->pQuestVars = pVar2;
}
for ( pScript = pNPCIndex->pProgram->pScripts; pScript != NULL;
pScript = pScript->pNext )
{
pScript2 = alloc_mem( sizeof( *pScript2 ) );
for ( pTrigger = pScript->pTriggers; pTrigger != NULL;
pTrigger = pTrigger->pNext )
{
pTrigger2 = alloc_mem( sizeof( *pTrigger2 ) );
for ( pTriggerArg = pTrigger->pArgs; pTriggerArg != NULL;
pTriggerArg = pTriggerArg->pNext )
{
pTriggerArg2 = alloc_mem( sizeof( *pTriggerArg2 ) );
pTriggerArg2->iType = pTriggerArg->iType;
switch ( pTrigger->iTrigger )
{
case NUMBER_NPC_TRIGGER_RANDOM:
pTriggerArg2->pArg = alloc_mem( 1 );
*pTriggerArg2->pArg = *pTriggerArg->pArg;
break;
default :
pTriggerArg2->pArg = str_dup(
pTriggerArg->pArg );
break;
}
pTriggerArg2->pNext = pTrigger2->pArgs;
pTrigger2->pArgs = pTriggerArg2;
}
pTrigger2->iTrigger = pTrigger->iTrigger;
pTrigger2->pNext = pScript2->pTriggers;
pScript2->pTriggers = pTrigger2;
}
pScript2->pScript = alloc_mem( pScript->iCodeSize );
memcpy( pScript2->pScript,
pScript->pScript, pScript->iCodeSize );
pScript2->iCodeSize = pScript->iCodeSize;
pScript2->pName = str_dup( pScript->pName );
pScript2->bDisabled = pScript->bDisabled;
pScript2->pNext = pProgram->pScripts;
pProgram->pScripts = pScript2;
}
}
/*
* Roll up this NPC's stats.
*/
pNewNPC->pStats->iStatStr = ( ( ( i = roll_dice(
pNPCIndex->VarStats.iStatStr[0],
pNPCIndex->VarStats.iStatStr[1] ) )
+ pNPCIndex->VarStats.iStatStr[2] )
> 99 ? 99 : i );
pNewNPC->pStats->iStatInt = ( ( ( i = roll_dice(
pNPCIndex->VarStats.iStatInt[0],
pNPCIndex->VarStats.iStatInt[1] ) )
+ pNPCIndex->VarStats.iStatInt[2] )
> 99 ? 99 : i );
pNewNPC->pStats->iStatWis = ( ( ( i = roll_dice(
pNPCIndex->VarStats.iStatWis[0],
pNPCIndex->VarStats.iStatWis[1] ) )
+ pNPCIndex->VarStats.iStatWis[2] )
> 99 ? 99 : i );
pNewNPC->pStats->iStatDex = ( ( ( i = roll_dice(
pNPCIndex->VarStats.iStatDex[0],
pNPCIndex->VarStats.iStatDex[1] ) )
+ pNPCIndex->VarStats.iStatDex[2] )
> 99 ? 99 : i );
pNewNPC->pStats->iStatCon = ( ( ( i = roll_dice(
pNPCIndex->VarStats.iStatCon[0],
pNPCIndex->VarStats.iStatCon[1] ) )
+ pNPCIndex->VarStats.iStatCon[2] )
> 99 ? 99 : i );
pNewNPC->pStats->iStatCha = ( ( ( i = roll_dice(
pNPCIndex->VarStats.iStatCha[0],
pNPCIndex->VarStats.iStatCha[1] ) )
+ pNPCIndex->VarStats.iStatCha[2] )
> 99 ? 99 : i );
pNewNPC->pStats->iStatLuc = ( ( ( i = roll_dice(
pNPCIndex->VarStats.iStatLuc[0],
pNPCIndex->VarStats.iStatLuc[1] ) )
+ pNPCIndex->VarStats.iStatLuc[2] )
> 99 ? 99 : i );
pNewNPC->pStats->iStatHP = ( ( ( i = roll_dice(
pNPCIndex->VarStats.iStatHP[0],
pNPCIndex->VarStats.iStatHP[1] ) )
+ pNPCIndex->VarStats.iStatHP[2] )
> 9999 ? 9999 : i );
pNewNPC->pStats->iStatMP = ( ( ( i = roll_dice(
pNPCIndex->VarStats.iStatMP[0],
pNPCIndex->VarStats.iStatMP[1] ) )
+ pNPCIndex->VarStats.iStatMP[2] )
> 9999 ? 9999 : i );
pNewNPC->pStats->iStatMV = ( ( ( i = roll_dice(
pNPCIndex->VarStats.iStatMV[0],
pNPCIndex->VarStats.iStatMV[1] ) )
+ pNPCIndex->VarStats.iStatMV[2] )
> 9999 ? 9999 : i );
for ( i = 0; pNPCIndex->pNameList[i] != NULL; i++ );
pNewNPC->pNPCData->pNameList = alloc_mem( sizeof( string )
* ( i + 1 ) );
for ( i = 0; pNPCIndex->pNameList[i] != NULL; i++ )
pNewNPC->pNPCData->pNameList[i] = save_string(
pNPCIndex->pNameList[i] );
pNewNPC->pNPCData->sShortDesc = save_string(
pNPCIndex->sShortDesc );
for ( i = 0; i < 5; i++ )
pNewNPC->pNPCData->sDescs[i] = save_string(
pNPCIndex->sDescs[i] );
for ( i = 0; i < 3; i++ )
pNewNPC->pNPCData->iDamage[i] = pNPCIndex->iDamage[i];
pNewNPC->pNPCData->iDamType = pNPCIndex->iDamType;
pNewNPC->pNPCData->iWander = pNPCIndex->iWander;
pNewNPC->pNPCData->fNPCFlags = pNPCIndex->fNPCFlags;
pNewNPC->sLongDesc = save_string( pNPCIndex->sLongDesc );
pNewNPC->fPartFlags = pNPCIndex->fPartFlags;
pNewNPC->fActFlags = pNPCIndex->fActFlags;
pNewNPC->iLevel = pNPCIndex->iLevel;
pNewNPC->iExp = ( ( ( i = roll_dice( pNPCIndex->iExp[0],
pNPCIndex->iExp[1] ) )
+ pNPCIndex->iExp[2] )
> 9999 ? 9999 : i );
pNewNPC->iAlignment = pNPCIndex->iAlignment;
pNewNPC->iRace = pNPCIndex->iRace;
pNewNPC->iSex = pNPCIndex->iSex;
pNewNPC->iHairColor = pNPCIndex->iHairColor;
pNewNPC->iEyeColor = pNPCIndex->iEyeColor;
pNewNPC->iHeight = pNPCIndex->iHeight;
pNewNPC->iWeight = pNPCIndex->iWeight;
pNewNPC->iMaxCarry = pNPCIndex->iMaxCarry;
pNewNPC->iGold = pNPCIndex->iGold;
pNewNPC->iHP = pNewNPC->pStats->iStatHP;
pNewNPC->iMP = pNewNPC->pStats->iStatMP;
pNewNPC->iMV = pNewNPC->pStats->iStatMV;
pNewNPC->iPosition = pNPCIndex->iPosition;
char_to_list( pNewNPC );
if ( ( pProgram = pNewNPC->pNPCData->pProgram ) != NULL )
{
for ( pScript = pProgram->pScripts; pScript != NULL;
pScript = pScript->pNext )
{
if ( pScript->bDisabled == TRUE
/* || pScript->bRunning == TRUE */ )
continue;
for ( pTrigger = pScript->pTriggers; pTrigger != NULL;
pTrigger = pTrigger->pNext )
{
if ( pTrigger->iTrigger == NUMBER_NPC_TRIGGER_CREATED )
{
execute_npc_script( pProgram, pScript, NULL, pNewNPC,
pActor, NULL );
break;
}
}
}
}
return ( pNewNPC );
}
/*
* Create a new object.
*/
OBJ_DATA *new_object( OBJ_INDEX_DATA *pObjIndex, CHAR_DATA *pActor )
{
OBJ_DATA *pNewObj;
int i;
if ( pObjFree == NULL )
pNewObj = alloc_mem( sizeof( *pNewObj ) );
else
{
pNewObj = pObjFree;
pObjFree = pObjFree->pNext;
}
pNewObj->pObjIndex = pObjIndex;
if ( pObjIndex->pProgram != NULL )
{
GENERIC_DATA *pGen;
GENERIC_DATA *pGen2;
QUEST_VAR_DATA *pVar;
QUEST_VAR_DATA *pVar2;
PROGRAM_DATA *pProgram;
SCRIPT_DATA *pScript;
SCRIPT_DATA *pScript2;
TRIGGER_DATA *pTrigger;
TRIGGER_DATA *pTrigger2;
TRIGGER_ARG_DATA *pTriggerArg;
TRIGGER_ARG_DATA *pTriggerArg2;
pProgram = alloc_mem( sizeof( *pProgram ) );
pNewObj->pProgram = pProgram;
for ( pGen = pObjIndex->pProgram->pQuestDataList; pGen != NULL;
pGen = pGen->pNext )
{
pGen2 = alloc_mem( sizeof( *pGen2 ) );
pGen2->pData = pGen->pData;
pGen2->pNext = pProgram->pQuestDataList;
pProgram->pQuestDataList = pGen2;
}
for ( pVar = pObjIndex->pProgram->pQuestVars; pVar != NULL;
pVar = pVar->pNext )
{
pVar2 = alloc_mem( sizeof( *pVar2 ) );
pVar2->iType = pVar->iType;
pVar2->sName = save_string( pVar->sName );
if ( pVar2->iType == NUMBER_VAR_STRING )
pVar2->uData.s = EMPTY_STRING;
pVar2->pNext = pProgram->pQuestVars;
pProgram->pQuestVars = pVar2;
}
for ( pScript = pObjIndex->pProgram->pScripts; pScript != NULL;
pScript = pScript->pNext )
{
pScript2 = alloc_mem( sizeof( *pScript2 ) );
for ( pTrigger = pScript->pTriggers; pTrigger != NULL;
pTrigger = pTrigger->pNext )
{
pTrigger2 = alloc_mem( sizeof( *pTrigger2 ) );
for ( pTriggerArg = pTrigger->pArgs; pTriggerArg != NULL;
pTriggerArg = pTriggerArg->pNext )
{
pTriggerArg2 = alloc_mem( sizeof( *pTriggerArg2 ) );
pTriggerArg2->iType = pTriggerArg->iType;
switch ( pTrigger->iTrigger )
{
case NUMBER_OBJ_TRIGGER_RANDOM:
pTriggerArg2->pArg = alloc_mem( 1 );
*pTriggerArg2->pArg = *pTriggerArg->pArg;
break;
default :
pTriggerArg2->pArg = str_dup(
pTriggerArg->pArg );
break;
}
pTriggerArg2->pNext = pTrigger2->pArgs;
pTrigger2->pArgs = pTriggerArg2;
}
pTrigger2->iTrigger = pTrigger->iTrigger;
pTrigger2->pNext = pScript2->pTriggers;
pScript2->pTriggers = pTrigger2;
}
pScript2->pScript = alloc_mem( pScript->iCodeSize );
memcpy( pScript2->pScript,
pScript->pScript, pScript->iCodeSize );
pScript2->iCodeSize = pScript->iCodeSize;
pScript2->pName = str_dup( pScript->pName );
pScript2->bDisabled = pScript->bDisabled;
pScript2->pNext = pProgram->pScripts;
pProgram->pScripts = pScript2;
}
}
for ( i = 0; pObjIndex->pNameList[i] != NULL; i++ );
pNewObj->pNameList = alloc_mem( sizeof( string ) * ( i + 1 ) );
for ( i = 0; pObjIndex->pNameList[i] != NULL; i++ )
pNewObj->pNameList[i] = save_string( pObjIndex->pNameList[i] );
pNewObj->sShortDesc = save_string( pObjIndex->sShortDesc );
pNewObj->sDesc = save_string( pObjIndex->sDesc );
pNewObj->sLongDesc = save_string( pObjIndex->sLongDesc );
pNewObj->fObjFlags = pObjIndex->fObjFlags;
pNewObj->iItemType = pObjIndex->iItemType;
pNewObj->iLevel = pObjIndex->iLevel;
pNewObj->iWeight = pObjIndex->iWeight;
pNewObj->iSize = pObjIndex->iSize;
pNewObj->iCost = pObjIndex->iCost;
pNewObj->iCondition = pObjIndex->iCondition;
pNewObj->iMaterial = pObjIndex->iMaterial;
for ( i = 0; i < 6; i++ )
pNewObj->iValues[i] = pObjIndex->iValues[i];
pNewObj->sValue = pObjIndex->sValue;
obj_to_list( pNewObj );
return ( pNewObj );
}
/*
* Free one character.
*/
void free_char( CHAR_DATA **ppChar )
{
CHAR_DATA *pChar = *ppChar;
OBJ_DATA *pObj;
OBJ_DATA *pObjNext;
QUEST_DATA *pQuestData;
QUEST_VAR_DATA *pVar;
RUNNING_SCRIPT_DATA *pRunning;
RUNNING_SCRIPT_DATA *pRunningNext;
int i;
char_from_list( pChar );
if ( pChar->pInRoom != NULL )
char_from_room( *ppChar );
if ( pChar->iCharType == CHAR_PC )
{
KNOWN_PERSON_DATA *pKnownPerson;
KNOWN_PERSON_DATA *pKnownPersonNext;
KNOWN_EXIT_DATA *pKnownExit;
KNOWN_EXIT_DATA *pKnownExitNext;
free_string( &pChar->pPCData->sPassword );
free_string( &pChar->pPCData->sName );
free_string( &pChar->pPCData->sPrompt );
for ( pKnownPerson = pChar->pPCData->pKnownPeople; pKnownPerson;
pKnownPerson = pKnownPersonNext )
{
pKnownPersonNext = pKnownPerson->pNext;
free_string( &pKnownPerson->sName );
free_mem( (void **) &pKnownPerson );
}
for ( pKnownExit = pChar->pPCData->pKnownExits; pKnownExit;
pKnownExit = pKnownExitNext )
{
pKnownExitNext = pKnownExit->pNext;
free_mem( (void **) &pKnownExit );
}
}
else if ( pChar->iCharType == CHAR_NPC )
{
PROGRAM_DATA *pProgram;
if ( pChar->pNPCData->pReset != NULL )
pChar->pNPCData->pReset->bAlive = FALSE;
if ( ( pProgram = pChar->pNPCData->pProgram ) != NULL )
{
GENERIC_DATA *pGen;
GENERIC_DATA *pGenNext;
SCRIPT_DATA *pScript;
SCRIPT_DATA *pScriptNext;
TRIGGER_DATA *pTrigger;
TRIGGER_DATA *pTriggerNext;
TRIGGER_ARG_DATA *pTriggerArg;
TRIGGER_ARG_DATA *pTriggerArgNext;
QUEST_VAR_DATA *pVarNext;
for ( pGen = pProgram->pQuestDataList; pGen; pGen = pGenNext )
{
pGenNext = pGen->pNext;
free_mem( (void **) &pGen );
}
for ( pVar = pProgram->pQuestVars; pVar; pVar = pVarNext )
{
pVarNext = pVar->pNext;
free_string( &pVar->sName );
if ( pVar->iType == NUMBER_VAR_STRING )
free_string( &pVar->uData.s );
free_mem( (void **) &pVar );
}
for ( pScript = pProgram->pScripts; pScript != NULL;
pScript = pScriptNext )
{
pScriptNext = pScript->pNext;
for ( pTrigger = pScript->pTriggers; pTrigger != NULL;
pTrigger = pTriggerNext )
{
pTriggerNext = pTrigger->pNext;
for ( pTriggerArg = pTrigger->pArgs; pTriggerArg;
pTriggerArg = pTriggerArgNext )
{
pTriggerArgNext = pTriggerArg->pNext;
switch ( pTrigger->iTrigger )
{
case NUMBER_NPC_TRIGGER_RANDOM:
free_mem( (void **) &pTriggerArg->pArg );
break;
default :
str_free( pTriggerArg->pArg );
break;
}
}
free_mem( (void **) &pTrigger );
}
str_free( pScript->pName );
free_mem( (void **) &pScript->pScript );
free_mem( (void **) &pScript );
}
free_mem( (void **) &pChar->pNPCData->pProgram );
}
for ( i = 0; pChar->pNPCData->pNameList[i] != NULL; i++ )
free_string( &pChar->pNPCData->pNameList[i] );
free_mem( (void **) &pChar->pNPCData->pNameList );
free_string( &pChar->pNPCData->sShortDesc );
for ( i = 0; i < 5; i++ )
free_string( &pChar->pNPCData->sDescs[i] );
}
free_mem( (void **) &pChar->pStats );
for ( pObj = pChar->pInven; pObj; pObj = pObjNext )
{
pObjNext = pObj->pNextContent;
free_obj( &pObj );
}
free_string( &pChar->sLongDesc );
zero_out( pChar, sizeof( *pChar ) );
/*
* ... This is a bit messy but we need to make sure scripts that
* are paused don't restart with bad pointers.
*/
for ( pQuestData = pQuestDataList; pQuestData != NULL;
pQuestData = pQuestData->pNext )
{
for ( pVar = pQuestData->pVars; pVar != NULL; pVar = pVar->pNext )
{
if ( pVar->iType == NUMBER_VAR_POINTER_CHAR
&& pVar->uData.p == pChar )
pVar->uData.p = NULL;
}
}
for ( pRunning = pRunningScriptList; pRunning != NULL;
pRunning = pRunningNext )
{
pRunningNext = pRunning->pNext;
if ( pRunning->iThisType == NUMBER_VAR_POINTER_CHAR
&& pChar == pRunning->pThis )
{
if ( pRunning == pRunningScriptList )
pRunningScriptList = pRunning->pNext;
else
{
RUNNING_SCRIPT_DATA *pPrev;
for ( pPrev = pRunningScriptList; pPrev != NULL;
pPrev = pPrev->pNext )
{
if ( pPrev->pNext == pRunning )
{
pPrev->pNext = pRunning->pNext;
break;
}
}
#ifdef DEBUG
if ( pPrev == NULL )
wcdebug( "Running script not found." );
#endif
}
free_mem( (void **) &pRunning );
continue;
}
for ( pVar = pRunning->pProgram->pQuestVars; pVar != NULL;
pVar = pVar->pNext )
{
if ( pVar->iType == NUMBER_VAR_POINTER_CHAR
&& pVar->uData.p == pChar )
pVar->uData.p = NULL;
}
if ( pChar == pRunning->pActor )
pRunning->pActor = NULL;
if ( pChar == pRunning->pThird )
pRunning->pThird = NULL;
}
pChar->pNext = pCharFree;
pCharFree = pChar;
*ppChar = NULL;
}
/*
* Free one object.
*/
void free_obj( OBJ_DATA **ppObj )
{
OBJ_DATA *pObj = *ppObj;
OBJ_DATA *pObjContent;
OBJ_DATA *pObjNext;
PROGRAM_DATA *pProgram;
RUNNING_SCRIPT_DATA *pRunning;
RUNNING_SCRIPT_DATA *pRunningNext;
QUEST_DATA *pQuestData;
QUEST_VAR_DATA *pVar;
int i;
obj_from_list( pObj );
if ( pObj->pInRoom != NULL )
obj_from_room( pObj );
else if ( pObj->pCarriedBy != NULL )
obj_from_char( pObj );
else if ( pObj->pInObj != NULL )
obj_from_obj( pObj );
if ( pObj->pReset != NULL )
pObj->pReset->bAlive = FALSE;
if ( ( pProgram = pObj->pProgram ) != NULL )
{
GENERIC_DATA *pGen;
GENERIC_DATA *pGenNext;
SCRIPT_DATA *pScript;
SCRIPT_DATA *pScriptNext;
TRIGGER_DATA *pTrigger;
TRIGGER_DATA *pTriggerNext;
TRIGGER_ARG_DATA *pTriggerArg;
TRIGGER_ARG_DATA *pTriggerArgNext;
QUEST_VAR_DATA *pVarNext;
for ( pGen = pProgram->pQuestDataList; pGen; pGen = pGenNext )
{
pGenNext = pGen->pNext;
free_mem( (void **) &pGen );
}
for ( pVar = pProgram->pQuestVars; pVar; pVar = pVarNext )
{
pVarNext = pVar->pNext;
free_string( &pVar->sName );
if ( pVar->iType == NUMBER_VAR_STRING )
free_string( &pVar->uData.s );
free_mem( (void **) &pVar );
}
for ( pScript = pProgram->pScripts; pScript != NULL;
pScript = pScriptNext )
{
pScriptNext = pScript->pNext;
for ( pTrigger = pScript->pTriggers; pTrigger != NULL;
pTrigger = pTriggerNext )
{
pTriggerNext = pTrigger->pNext;
for ( pTriggerArg = pTrigger->pArgs; pTriggerArg;
pTriggerArg = pTriggerArgNext )
{
pTriggerArgNext = pTriggerArg->pNext;
switch ( pTrigger->iTrigger )
{
case NUMBER_OBJ_TRIGGER_RANDOM:
free_mem( (void **) &pTriggerArg->pArg );
break;
default :
str_free( pTriggerArg->pArg );
break;
}
}
free_mem( (void **) &pTrigger );
}
str_free( pScript->pName );
free_mem( (void **) &pScript->pScript );
free_mem( (void **) &pScript );
}
free_mem( (void **) &pObj->pProgram );
}
for ( pObjContent = pObj->pContains; pObjContent != NULL;
pObjContent = pObjNext )
{
pObjNext = pObjContent->pNextContent;
free_obj( &pObjContent );
}
for ( i = 0; pObj->pNameList[i] != NULL; i++ )
free_string( &pObj->pNameList[i] );
free_mem( (void **) &pObj->pNameList );
free_string( &pObj->sShortDesc );
free_string( &pObj->sDesc );
free_string( &pObj->sLongDesc );
zero_out( pObj, sizeof( *pObj ) );
/*
* ... This is a bit messy but we need to make sure scripts that
* are paused don't restart with bad pointers.
*/
for ( pQuestData = pQuestDataList; pQuestData != NULL;
pQuestData = pQuestData->pNext )
{
for ( pVar = pQuestData->pVars; pVar; pVar = pVar->pNext )
{
if ( pVar->iType == NUMBER_VAR_POINTER_OBJ
&& pVar->uData.p == pObj )
pVar->uData.p = NULL;
}
}
for ( pRunning = pRunningScriptList; pRunning != NULL;
pRunning = pRunningNext )
{
pRunningNext = pRunning->pNext;
for ( pVar = pRunning->pProgram->pQuestVars; pVar != NULL;
pVar = pVar->pNext )
{
if ( pVar->iType == NUMBER_VAR_POINTER_OBJ
&& pVar->uData.p == pObj )
pVar->uData.p = NULL;
}
}
pObj->pNext = pObjFree;
pObjFree = pObj;
*ppObj = NULL;
}
/*
* End of memory.c
*/