mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
Added support for Russian city names and Items Fixed contract length exploit (hire merc for 2 weeks for the price of 1 day) Fixed insurance emails repeating when you choose "delete" but then say no Corrected UTF-8 to wide char translation on Windows platforms (Windows doesn't handle mbstowcs correctly) Moved UTF-8 to Wide Char translation for item descriptions and names so it happens at XML load time (fix bug that Russian has half the description space) Fix overflow when combining two items with high counts (such as 200-round boxes of ammo) Path AI fixes Fixed issues with non-interruptable animations causing infinite clock Fixed some issues with soldiers not reaching their plotted destination Fixed escorted players who were cowering, being unable to move after joining party Only allow militia to climb roofs if their orders allow them to move Fix bug where AI might climb the wrong roof on the way to the destination roof Allow AI who have gone outside their patrol grid, to return to the Grid git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@1702 3b4a5df2-a311-0410-b5c6-a8a6f20db521
355 lines
8.1 KiB
C++
355 lines
8.1 KiB
C++
#ifdef PRECOMPILEDHEADERS
|
|
#include "Tactical All.h"
|
|
#else
|
|
#include "sgp.h"
|
|
#include "overhead types.h"
|
|
#include "Sound Control.h"
|
|
#include "Soldier Control.h"
|
|
#include "overhead.h"
|
|
#include "Event Pump.h"
|
|
#include "weapons.h"
|
|
#include "Animation Control.h"
|
|
#include "sys globals.h"
|
|
#include "Handle UI.h"
|
|
#include "Isometric Utils.h"
|
|
#include "worldman.h"
|
|
#include "math.h"
|
|
#include "points.h"
|
|
#include "ai.h"
|
|
#include "los.h"
|
|
#include "renderworld.h"
|
|
#include "opplist.h"
|
|
#include "interface.h"
|
|
#include "message.h"
|
|
#include "campaign.h"
|
|
#include "items.h"
|
|
#include "text.h"
|
|
#include "Soldier Profile.h"
|
|
#include "tile animation.h"
|
|
#include "Dialogue Control.h"
|
|
#include "SkillCheck.h"
|
|
#include "explosion control.h"
|
|
#include "Quests.h"
|
|
#include "Physics.h"
|
|
#include "Random.h"
|
|
#include "Vehicles.h"
|
|
#include "bullets.h"
|
|
#include "morale.h"
|
|
#include "meanwhile.h"
|
|
#include "SkillCheck.h"
|
|
#include "gamesettings.h"
|
|
#include "SaveLoadMap.h"
|
|
#include "Debug Control.h"
|
|
#include "expat.h"
|
|
#include "XML.h"
|
|
#endif
|
|
|
|
struct
|
|
{
|
|
PARSE_STAGE curElement;
|
|
|
|
CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1];
|
|
|
|
UINT32 maxArraySize;
|
|
UINT32 curIndex;
|
|
UINT32 currentDepth;
|
|
UINT32 maxReadDepth;
|
|
}
|
|
typedef ammoParseData;
|
|
|
|
static void XMLCALL
|
|
ammoStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts)
|
|
{
|
|
ammoParseData * pData = (ammoParseData *)userData;
|
|
|
|
if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element?
|
|
{
|
|
if(strcmp(name, "AMMOLIST") == 0 && pData->curElement == ELEMENT_NONE)
|
|
{
|
|
pData->curElement = ELEMENT_LIST;
|
|
|
|
pData->maxReadDepth++; //we are not skipping this element
|
|
}
|
|
else if(strcmp(name, "AMMO") == 0 && pData->curElement == ELEMENT_LIST)
|
|
{
|
|
pData->curElement = ELEMENT;
|
|
|
|
pData->maxReadDepth++; //we are not skipping this element
|
|
pData->curIndex++;
|
|
}
|
|
else if(pData->curElement == ELEMENT &&
|
|
(strcmp(name, "AmmoCaliber") == 0 ||
|
|
strcmp(name, "BRCaliber") == 0 ))
|
|
{
|
|
pData->curElement = ELEMENT_PROPERTY;
|
|
|
|
pData->maxReadDepth++; //we are not skipping this element
|
|
}
|
|
|
|
pData->szCharData[0] = '\0';
|
|
}
|
|
|
|
pData->currentDepth++;
|
|
|
|
}
|
|
|
|
static void XMLCALL
|
|
ammoCharacterDataHandle(void *userData, const XML_Char *str, int len)
|
|
{
|
|
ammoParseData * pData = (ammoParseData *)userData;
|
|
|
|
if( (pData->currentDepth <= pData->maxReadDepth) &&
|
|
(strlen(pData->szCharData) < MAX_CHAR_DATA_LENGTH)
|
|
){
|
|
strncat(pData->szCharData,str,__min((unsigned int)len,MAX_CHAR_DATA_LENGTH-strlen(pData->szCharData)));
|
|
}
|
|
}
|
|
|
|
|
|
static void XMLCALL
|
|
ammoEndElementHandle(void *userData, const XML_Char *name)
|
|
{
|
|
char temp;
|
|
ammoParseData * pData = (ammoParseData *)userData;
|
|
|
|
if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading
|
|
{
|
|
if(strcmp(name, "AMMOLIST") == 0)
|
|
{
|
|
pData->curElement = ELEMENT_NONE;
|
|
}
|
|
else if(strcmp(name, "AMMO") == 0)
|
|
{
|
|
pData->curElement = ELEMENT_LIST;
|
|
|
|
}
|
|
else if(strcmp(name, "AmmoCaliber") == 0)
|
|
{
|
|
pData->curElement = ELEMENT;
|
|
if(pData->curIndex < pData->maxArraySize)
|
|
{
|
|
#if 0
|
|
for(int i=0;i<min((int)strlen(pData->szCharData),MAX_CHAR_DATA_LENGTH);i++)
|
|
{
|
|
temp = pData->szCharData[i];
|
|
AmmoCaliber[pData->curIndex][i] = temp;
|
|
}
|
|
#else
|
|
MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, AmmoCaliber[pData->curIndex], sizeof(AmmoCaliber[0])/sizeof(AmmoCaliber[0][0]) );
|
|
AmmoCaliber[pData->curIndex][sizeof(AmmoCaliber[0])/sizeof(AmmoCaliber[0][0]) - 1] = '\0';
|
|
#endif
|
|
}
|
|
|
|
}
|
|
else if(strcmp(name, "BRCaliber") == 0)
|
|
{
|
|
pData->curElement = ELEMENT;
|
|
if(pData->curIndex < pData->maxArraySize)
|
|
{
|
|
#if 0
|
|
for(int i=0;i<min((int)strlen(pData->szCharData),MAX_CHAR_DATA_LENGTH);i++)
|
|
{
|
|
temp = pData->szCharData[i];
|
|
BobbyRayAmmoCaliber[pData->curIndex][i] = temp;
|
|
}
|
|
#else
|
|
MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, BobbyRayAmmoCaliber[pData->curIndex], sizeof(BobbyRayAmmoCaliber[0])/sizeof(BobbyRayAmmoCaliber[0][0]) );
|
|
BobbyRayAmmoCaliber[pData->curIndex][sizeof(BobbyRayAmmoCaliber[0])/sizeof(BobbyRayAmmoCaliber[0][0]) - 1] = '\0';
|
|
#endif
|
|
}
|
|
|
|
}
|
|
|
|
|
|
pData->maxReadDepth--;
|
|
}
|
|
|
|
pData->currentDepth--;
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOLEAN ReadInAmmoStats(STR fileName)
|
|
{
|
|
HWFILE hFile;
|
|
UINT32 uiBytesRead;
|
|
UINT32 uiFSize;
|
|
CHAR8 * lpcBuffer;
|
|
XML_Parser parser = XML_ParserCreate(NULL);
|
|
|
|
ammoParseData pData;
|
|
|
|
DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading AmmoStrings.xml" );
|
|
|
|
// Open ammos 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, ammoStartElementHandle, ammoEndElementHandle);
|
|
XML_SetCharacterDataHandler(parser, ammoCharacterDataHandle);
|
|
|
|
|
|
memset(&pData,0,sizeof(pData));
|
|
pData.maxArraySize = MAXITEMS;
|
|
pData.curIndex = -1;
|
|
|
|
XML_SetUserData(parser, &pData);
|
|
|
|
|
|
if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE))
|
|
{
|
|
CHAR8 errorBuf[511];
|
|
|
|
sprintf(errorBuf, "XML Parser Error in AmmoStrings.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser));
|
|
LiveMessage(errorBuf);
|
|
|
|
MemFree(lpcBuffer);
|
|
return FALSE;
|
|
}
|
|
|
|
MemFree(lpcBuffer);
|
|
|
|
|
|
XML_ParserFree(parser);
|
|
|
|
return( TRUE );
|
|
}
|
|
BOOLEAN WriteAmmoStats()
|
|
{
|
|
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\\Ammos out.xml", FILE_ACCESS_WRITE | FILE_CREATE_ALWAYS, FALSE );
|
|
if ( !hFile )
|
|
return( FALSE );
|
|
|
|
{
|
|
UINT32 cnt;
|
|
|
|
FilePrintf(hFile,"<AMMOLIST>\r\n");
|
|
for(cnt = 0;cnt < MAXITEMS;cnt++)
|
|
{
|
|
FilePrintf(hFile,"\t<AMMO>\r\n");
|
|
|
|
STR16 szRemainder = AmmoCaliber[cnt]; //the remaining string to be output (for making valid XML)
|
|
|
|
FilePrintf(hFile,"\t\t<AmmoCaliber>");
|
|
while(szRemainder[0] != '\0')
|
|
{
|
|
UINT32 uiCharLoc = wcscspn(szRemainder,L"&<>\'\"\0");
|
|
CHAR16 invChar = szRemainder[uiCharLoc];
|
|
|
|
if(uiCharLoc)
|
|
{
|
|
szRemainder[uiCharLoc] = '\0';
|
|
FilePrintf(hFile,"%S",szRemainder);
|
|
szRemainder[uiCharLoc] = invChar;
|
|
}
|
|
|
|
szRemainder += uiCharLoc;
|
|
|
|
switch(invChar)
|
|
{
|
|
case '&':
|
|
FilePrintf(hFile,"&");
|
|
szRemainder++;
|
|
break;
|
|
|
|
case '<':
|
|
FilePrintf(hFile,"<");
|
|
szRemainder++;
|
|
break;
|
|
|
|
case '>':
|
|
FilePrintf(hFile,">");
|
|
szRemainder++;
|
|
break;
|
|
|
|
case '\'':
|
|
FilePrintf(hFile,"'");
|
|
szRemainder++;
|
|
break;
|
|
|
|
case '\"':
|
|
FilePrintf(hFile,""");
|
|
szRemainder++;
|
|
break;
|
|
}
|
|
}
|
|
FilePrintf(hFile,"</AmmoCaliber>\r\n");
|
|
|
|
|
|
szRemainder = BobbyRayAmmoCaliber[cnt]; //the remaining string to be output (for making valid XML)
|
|
|
|
FilePrintf(hFile,"\t\t<BRCaliber>");
|
|
while(szRemainder[0] != '\0')
|
|
{
|
|
UINT32 uiCharLoc = wcscspn(szRemainder,L"&<>\'\"\0");
|
|
CHAR16 invChar = szRemainder[uiCharLoc];
|
|
|
|
if(uiCharLoc)
|
|
{
|
|
szRemainder[uiCharLoc] = '\0';
|
|
FilePrintf(hFile,"%S",szRemainder);
|
|
szRemainder[uiCharLoc] = invChar;
|
|
}
|
|
|
|
szRemainder += uiCharLoc;
|
|
|
|
switch(invChar)
|
|
{
|
|
case '&':
|
|
FilePrintf(hFile,"&");
|
|
szRemainder++;
|
|
break;
|
|
|
|
case '<':
|
|
FilePrintf(hFile,"<");
|
|
szRemainder++;
|
|
break;
|
|
|
|
case '>':
|
|
FilePrintf(hFile,">");
|
|
szRemainder++;
|
|
break;
|
|
|
|
case '\'':
|
|
FilePrintf(hFile,"'");
|
|
szRemainder++;
|
|
break;
|
|
|
|
case '\"':
|
|
FilePrintf(hFile,""");
|
|
szRemainder++;
|
|
break;
|
|
}
|
|
}
|
|
FilePrintf(hFile,"</BRCaliber>\r\n");
|
|
|
|
|
|
FilePrintf(hFile,"\t</AMMO>\r\n");
|
|
}
|
|
FilePrintf(hFile,"</AMMOLIST>\r\n");
|
|
}
|
|
FileClose( hFile );
|
|
|
|
return( TRUE );
|
|
} |