//zilpin: pellet spread patterns externalized in XML #include "sgp.h" #include "FileMan.h" #include "math.h" #include "LOS.h" #include "Debug Control.h" #include "expat.h" #include "XML.h" #define LIST_BUFFER_LEN (32) #define LIST_BUFFER_SIZE (LIST_BUFFER_LEN * sizeof(t_SpreadPattern)) #define CALC_NEW_LIST_SIZE(c) ( LIST_BUFFER_SIZE * (1+ ((c) / LIST_BUFFER_LEN)) ) #define ARRAY_BUFFER_LEN (32) #define ARRAY_BUFFER_SIZE (ARRAY_BUFFER_LEN * sizeof(DOUBLE)) #define CALC_NEW_ARRAY_SIZE(c) ( ARRAY_BUFFER_SIZE * (1+ ((c) / ARRAY_BUFFER_LEN)) ) struct { PARSE_STAGE curElement; CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1]; UINT32 currentDepth; UINT32 maxReadDepth; } typedef spreadpatternParseData; static void XMLCALL spreadpatternStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts) { spreadpatternParseData * pData = (spreadpatternParseData *)userData; if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element? { if(strcmp(name, "SPREADPATTERNLIST") == 0 && pData->curElement == ELEMENT_NONE) { pData->curElement = ELEMENT_LIST; giSpreadPatternCount = 0; gpSpreadPattern = NULL; gpSpreadPattern = (t_SpreadPattern *)MemAlloc( LIST_BUFFER_SIZE ); Assert(gpSpreadPattern); memset( gpSpreadPattern, 0, LIST_BUFFER_SIZE ); pData->maxReadDepth++; //we are not skipping this element } else if(strcmp(name, "SPREADPATTERN") == 0 && pData->curElement == ELEMENT_LIST) { pData->curElement = ELEMENT_LIST; giSpreadPatternCount++; if( !(giSpreadPatternCount % LIST_BUFFER_LEN) ){ //End of buffer. Expand buffer. gpSpreadPattern = (t_SpreadPattern *)MemRealloc(gpSpreadPattern, CALC_NEW_LIST_SIZE(giSpreadPatternCount) ); Assert(gpSpreadPattern); } memset( &(gpSpreadPattern[giSpreadPatternCount-1]) , 0 , sizeof(t_SpreadPattern) ); gpSpreadPattern[giSpreadPatternCount-1].iCount = 0; gpSpreadPattern[giSpreadPatternCount-1].xspread = 0.0; gpSpreadPattern[giSpreadPatternCount-1].yspread = 0.0; gpSpreadPattern[giSpreadPatternCount-1].method = giSpreadPatternMethod_Default; gpSpreadPattern[giSpreadPatternCount-1].x = (DOUBLE *)MemAlloc( ARRAY_BUFFER_SIZE ); Assert( gpSpreadPattern[giSpreadPatternCount-1].x ); memset( gpSpreadPattern[giSpreadPatternCount-1].x , 0 , ARRAY_BUFFER_SIZE ); gpSpreadPattern[giSpreadPatternCount-1].y = (DOUBLE *)MemAlloc( ARRAY_BUFFER_SIZE ); Assert( gpSpreadPattern[giSpreadPatternCount-1].y ); memset( gpSpreadPattern[giSpreadPatternCount-1].y , 0 , ARRAY_BUFFER_SIZE ); pData->maxReadDepth++; //we are not skipping this element } else if(strcmp(name, "p") == 0 )//&& pData->curElement == ELEMENT_LIST) { pData->curElement = ELEMENT; gpSpreadPattern[giSpreadPatternCount-1].iCount++; if( !(gpSpreadPattern[giSpreadPatternCount-1].iCount % ARRAY_BUFFER_LEN ) ){ //End of buffer. Expand. gpSpreadPattern[giSpreadPatternCount-1].x = (DOUBLE *)MemRealloc(gpSpreadPattern[giSpreadPatternCount-1].x, CALC_NEW_ARRAY_SIZE(gpSpreadPattern[giSpreadPatternCount-1].iCount) ); Assert( gpSpreadPattern[giSpreadPatternCount-1].x ); gpSpreadPattern[giSpreadPatternCount-1].y = (DOUBLE *)MemRealloc(gpSpreadPattern[giSpreadPatternCount-1].y, CALC_NEW_ARRAY_SIZE(gpSpreadPattern[giSpreadPatternCount-1].iCount) ); Assert( gpSpreadPattern[giSpreadPatternCount-1].y ); } gpSpreadPattern[giSpreadPatternCount-1].x[ gpSpreadPattern[giSpreadPatternCount-1].iCount - 1 ] = 0.0; gpSpreadPattern[giSpreadPatternCount-1].y[ gpSpreadPattern[giSpreadPatternCount-1].iCount - 1 ] = 0.0; pData->maxReadDepth++; //we are not skipping this element } else if( //pData->curElement == ELEMENT && ( strcmp(name, "x") == 0 || strcmp(name, "y") == 0 || strcmp(name, "xspread") == 0 || strcmp(name, "yspread") == 0 || strcmp(name, "NAME") == 0 || strcmp(name, "method") == 0 )) { pData->curElement = ELEMENT_PROPERTY; pData->maxReadDepth++; //we are not skipping this element } pData->szCharData[0] = '\0'; } pData->currentDepth++; } static void XMLCALL spreadpatternCharacterDataHandle(void *userData, const XML_Char *str, int len) { spreadpatternParseData * pData = (spreadpatternParseData *)userData; if( (pData->currentDepth <= pData->maxReadDepth) && (strlen(pData->szCharData) < MAX_CHAR_DATA_LENGTH) && pData->curElement == ELEMENT_PROPERTY ){ strncat(pData->szCharData,str,__min((unsigned int)len,MAX_CHAR_DATA_LENGTH-strlen(pData->szCharData))); } } static void XMLCALL spreadpatternEndElementHandle(void *userData, const XML_Char *name) { DOUBLE d; spreadpatternParseData * pData = (spreadpatternParseData *)userData; if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading { if(strcmp(name, "SPREADPATTERNLIST") == 0) { pData->curElement = ELEMENT_NONE; } else if(strcmp(name, "SPREADPATTERN") == 0) { pData->curElement = ELEMENT_LIST; } else if(strcmp(name, "p") == 0) { //I would prefer the format to be: //

//but it's: //

0.10.1

0.20.2 //because the XML editor will probably have problems with using attributes instead of tags. pData->curElement = ELEMENT_LIST; } else if(strcmp(name, "x") == 0) { pData->curElement = ELEMENT; d = atof(pData->szCharData); gpSpreadPattern[giSpreadPatternCount-1].x[ gpSpreadPattern[giSpreadPatternCount-1].iCount-1 ] = d; } else if(strcmp(name, "y") == 0) { pData->curElement = ELEMENT; d = atof(pData->szCharData); gpSpreadPattern[giSpreadPatternCount-1].y[ gpSpreadPattern[giSpreadPatternCount-1].iCount-1 ] = d; } else if(strcmp(name, "xspread") == 0) { pData->curElement = ELEMENT; d = fabs( atof(pData->szCharData) ); gpSpreadPattern[giSpreadPatternCount-1].xspread = d; } else if(strcmp(name, "yspread") == 0) { pData->curElement = ELEMENT; d = fabs( atof(pData->szCharData) ); gpSpreadPattern[giSpreadPatternCount-1].yspread = d; } else if(strcmp(name, "NAME") == 0) { pData->curElement = ELEMENT; //Trim whitespace. while( pData->szCharData[0] == ' ' ) memmove( pData->szCharData , &pData->szCharData[1] , strlen(&pData->szCharData[1]) ); while( strlen(pData->szCharData)>0 && pData->szCharData[ strlen(pData->szCharData)-1 ] == ' ' ) pData->szCharData[ strlen(pData->szCharData)-1 ]=0; //Clean and copy. memset(gpSpreadPattern[giSpreadPatternCount-1].Name,0,SPREADPATTERN_NAME_SIZE); strncpy(gpSpreadPattern[giSpreadPatternCount-1].Name,pData->szCharData,SPREADPATTERN_NAME_SIZE-1); } else if(strcmp(name, "method") == 0) { pData->curElement = ELEMENT; //Trim whitespace. while( pData->szCharData[0] == ' ' ) memmove( pData->szCharData , &pData->szCharData[1] , strlen(&pData->szCharData[1]) ); while( strlen(pData->szCharData)>0 && pData->szCharData[ strlen(pData->szCharData)-1 ] == ' ' ) pData->szCharData[ strlen(pData->szCharData)-1 ]=0; //Find it. for(unsigned int i=0;iszCharData, gSpreadPatternMethodNames[i] ) == 0){ gpSpreadPattern[giSpreadPatternCount-1].method = i; break; } } } pData->maxReadDepth--; } pData->currentDepth--; } BOOLEAN ReadInSpreadPatterns(STR fileName) { HWFILE hFile; UINT32 uiBytesRead; UINT32 uiFSize; CHAR8 * lpcBuffer; XML_Parser parser = XML_ParserCreate(NULL); spreadpatternParseData pData; DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading SpreadPatterns.xml" ); // Open spread pattern file hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE ); if ( !hFile ) return( FALSE ); uiFSize = FileGetSize(hFile); lpcBuffer = (CHAR8 *) MemAlloc(uiFSize+1); //Read in block if ( !FileRead( hFile, lpcBuffer, uiFSize, &uiBytesRead ) ) { MemFree(lpcBuffer); return( FALSE ); } lpcBuffer[uiFSize] = 0; //add a null terminator FileClose( hFile ); XML_SetElementHandler(parser, spreadpatternStartElementHandle, spreadpatternEndElementHandle); XML_SetCharacterDataHandler(parser, spreadpatternCharacterDataHandle); memset(&pData,0,sizeof(pData)); //pData.maxArraySize = MAXITEMS; XML_SetUserData(parser, &pData); if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE)) { CHAR8 errorBuf[511]; sprintf(errorBuf, "XML Parser Error in SpreadPatterns.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser)); LiveMessage(errorBuf); MemFree(lpcBuffer); return FALSE; } MemFree(lpcBuffer); XML_ParserFree(parser); //Output for debugging //WriteSpreadPatterns(); return( TRUE ); } BOOLEAN WriteSpreadPatterns() { DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"WriteSpreadPatterns"); HWFILE hFile; //Debug code; make sure that what we got from the file is the same as what's there // Open a new file hFile = FileOpen( "TableData\\SpreadPatterns_out.xml", FILE_ACCESS_WRITE | FILE_CREATE_ALWAYS, FALSE ); if ( !hFile ) return( FALSE ); { FilePrintf(hFile,"\r\n"); FilePrintf(hFile,"\r\n", giSpreadPatternCount ); for(INT32 i = 0 ; i < giSpreadPatternCount; i++) { FilePrintf(hFile,"\t\r\n"); FilePrintf(hFile,"\t\r\n",i); FilePrintf(hFile,"\t%s\r\n",gpSpreadPattern[i].Name); FilePrintf(hFile,"\t%s \r\n",gSpreadPatternMethodNames[gpSpreadPattern[i].method], gpSpreadPattern[i].method); FilePrintf(hFile,"\t%2.4f",gpSpreadPattern[i].xspread); FilePrintf(hFile," %2.4f\r\n",gpSpreadPattern[i].yspread); FilePrintf(hFile,"\t\r\n",gpSpreadPattern[i].iCount); for(INT32 j=0;j"); FilePrintf(hFile,"%2.4f",gpSpreadPattern[i].x[j]); FilePrintf(hFile,"%2.4f",gpSpreadPattern[i].y[j]); FilePrintf(hFile,"

\r\n"); } FilePrintf(hFile,"\t
\r\n"); } FilePrintf(hFile,"\r\n"); FilePrintf(hFile,"\r\n"); } FileClose( hFile ); return( TRUE ); } //zilpin: pellet spread patterns externalized in XML //This function is used primarily by XML loaders for Items and AmmoTypes. //Given a string will determine if it is a SpreadPattern name or literal index, //and return an integer index of the spreadpattern in the gpSpreadPattern array. //If the name is not found, or the index was out of range, then return 0. int FindSpreadPatternIndex( const STR strName ) { UINT32 ui = 0; INT32 i,n=0; char str[SPREADPATTERN_NAME_SIZE]={}; //Copy search name sans leading and trailing space. strncpy(str,strName,SPREADPATTERN_NAME_SIZE-1); str[SPREADPATTERN_NAME_SIZE-1]=0; while( str[0] == ' ' ) memmove( str , &str[1] , strlen(&str[1]) ); while( strlen(str)>0 && str[ strlen(str)-1 ] == ' ' ) str[ strlen(str)-1 ]=0; //Named pattern or raw index? for(ui=0;ui=giSpreadPatternCount ) n=0; } return n; }