/* * 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 */