1190 lines
28 KiB
C++
1190 lines
28 KiB
C++
/*
|
|
This file is part of Warzone 2100.
|
|
Copyright (C) 1999-2004 Eidos Interactive
|
|
Copyright (C) 2005-2011 Warzone 2100 Project
|
|
|
|
Warzone 2100 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.
|
|
|
|
Warzone 2100 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 Warzone 2100; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/**
|
|
* @file data.c
|
|
*
|
|
* Data loading functions used by the framework resource module.
|
|
*
|
|
*/
|
|
|
|
#include <physfs.h>
|
|
|
|
#include "lib/framework/frame.h"
|
|
#include "lib/framework/frameresource.h"
|
|
#include "lib/framework/strres.h"
|
|
#include "lib/framework/crc.h"
|
|
#include "lib/framework/resly.h"
|
|
#include "lib/gamelib/parser.h"
|
|
#include "lib/ivis_opengl/bitimage.h"
|
|
#include "lib/ivis_opengl/tex.h"
|
|
#include "lib/script/script.h"
|
|
#include "lib/sound/audio.h"
|
|
|
|
#include "qtscript.h"
|
|
#include "data.h"
|
|
#include "droid.h"
|
|
#include "feature.h"
|
|
#include "function.h"
|
|
#include "mechanics.h"
|
|
#include "message.h"
|
|
#include "multiplay.h"
|
|
#include "research.h"
|
|
#include "scriptvals.h"
|
|
#include "stats.h"
|
|
#include "template.h"
|
|
#include "text.h"
|
|
#include "texture.h"
|
|
|
|
#define DT_TEXPAGE "TEXPAGE"
|
|
#define DT_TCMASK "TCMASK"
|
|
|
|
// whether a save game is currently being loaded
|
|
static bool saveFlag = false;
|
|
|
|
uint32_t DataHash[DATA_MAXDATA]= {0};
|
|
|
|
/**
|
|
* hashBuffer()
|
|
* \param pData pointer to our buffer (always a text file)
|
|
* \param size the size of the buffer
|
|
* \return hash calculated from the buffer.
|
|
*
|
|
* Note, this is obviously not a very complex hash routine. This most likely has many collisions possible.
|
|
* This is almost the same routine that Pumpkin had, minus the ugly bug :)
|
|
* And minus the old algorithm and debugging trace, replaced with a simple CRC...
|
|
*/
|
|
static UDWORD hashBuffer(uint8_t *pData, uint32_t size)
|
|
{
|
|
char nl = '\n';
|
|
uint32_t crc = 0;
|
|
uint32_t i, j;
|
|
uint32_t lines = 0;
|
|
uint32_t bytes = 0;
|
|
for (i = 0; i < size; i = j + 1)
|
|
{
|
|
for (j = i; j < size && pData[j] != '\n' && pData[j] != '\r'; ++j)
|
|
{}
|
|
|
|
if (i != j) // CRC non-empty lines only.
|
|
{
|
|
crc = crcSum(crc, pData + i, j - i); // CRC the line.
|
|
crc = crcSum(crc, &nl, 1); // CRC the line ending.
|
|
|
|
++lines;
|
|
bytes += j - i + 1;
|
|
}
|
|
}
|
|
debug(LOG_NET, "The size of the old buffer (%u bytes - %d stripped), New buffer size of %u bytes, %u non-empty lines.", size, size - bytes, bytes, lines);
|
|
|
|
return ~crc;
|
|
}
|
|
|
|
// create the hash for that data block.
|
|
// Data should be converted to Network byte order
|
|
static void calcDataHash(uint8_t *pBuffer, uint32_t size, uint32_t index)
|
|
{
|
|
const uint32_t oldHash = DataHash[index];
|
|
|
|
if (!bMultiPlayer)
|
|
{
|
|
return;
|
|
}
|
|
|
|
DataHash[index] += hashBuffer(pBuffer, size);
|
|
|
|
if (!DataHash[index] && oldHash)
|
|
{
|
|
debug(LOG_NET, "The new hash is 0, the old hash was %u. We added the negated value!", oldHash);
|
|
}
|
|
|
|
debug(LOG_NET, "DataHash[%2u] = %08x", index, DataHash[index]);
|
|
|
|
return;
|
|
}
|
|
|
|
void resetDataHash(void)
|
|
{
|
|
UDWORD i;
|
|
for (i = 0; i < DATA_MAXDATA; i++)
|
|
{
|
|
DataHash[i] = 0;
|
|
}
|
|
debug(LOG_NET, "== Hash is reset ==");
|
|
}
|
|
|
|
/**********************************************************/
|
|
|
|
|
|
void dataSetSaveFlag(void)
|
|
{
|
|
saveFlag = true;
|
|
}
|
|
void dataClearSaveFlag(void)
|
|
{
|
|
saveFlag = false;
|
|
}
|
|
|
|
/* Load the body stats */
|
|
static bool bufferSBODYLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_SBODY);
|
|
|
|
if (!loadBodyStats(pBuffer, size)
|
|
|| !allocComponentList(COMP_BODY, numBodyStats))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// set a dummy value so the release function gets called
|
|
*ppData = (void *)1;
|
|
return true;
|
|
}
|
|
|
|
static void dataReleaseStats(WZ_DECL_UNUSED void *pData)
|
|
{
|
|
freeComponentLists();
|
|
statsShutDown();
|
|
}
|
|
|
|
|
|
/* Load the weapon stats */
|
|
static bool bufferSWEAPONLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_SWEAPON);
|
|
|
|
if (!loadWeaponStats(pBuffer, size)
|
|
|| !allocComponentList(COMP_WEAPON, numWeaponStats))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the constructor stats */
|
|
static bool bufferSCONSTRLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_SCONSTR);
|
|
|
|
if (!loadConstructStats(pBuffer, size)
|
|
|| !allocComponentList(COMP_CONSTRUCT, numConstructStats))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the ECM stats */
|
|
static bool bufferSECMLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_SECM);
|
|
|
|
if (!loadECMStats(pBuffer, size)
|
|
|| !allocComponentList(COMP_ECM, numECMStats))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the Propulsion stats */
|
|
static bool bufferSPROPLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_SPROP);
|
|
|
|
if (!loadPropulsionStats(pBuffer, size)
|
|
|| !allocComponentList(COMP_PROPULSION, numPropulsionStats))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the Sensor stats */
|
|
static bool bufferSSENSORLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_SSENSOR);
|
|
|
|
if (!loadSensorStats(pBuffer, size)
|
|
|| !allocComponentList(COMP_SENSOR, numSensorStats))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the Repair stats */
|
|
static bool bufferSREPAIRLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_SREPAIR);
|
|
|
|
if (!loadRepairStats(pBuffer, size)
|
|
|| !allocComponentList(COMP_REPAIRUNIT, numRepairStats))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the Brain stats */
|
|
static bool bufferSBRAINLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_SBRAIN);
|
|
|
|
if (!loadBrainStats(pBuffer, size)
|
|
|| !allocComponentList(COMP_BRAIN, numBrainStats))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the PropulsionType stats */
|
|
static bool bufferSPROPTYPESLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_SPROPTY);
|
|
|
|
if (!loadPropulsionTypes(pBuffer, size))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
//not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the propulsion type sound stats */
|
|
static bool bufferSPROPSNDLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
if (!loadPropulsionSounds(pBuffer, size))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the STERRTABLE stats */
|
|
static bool bufferSTERRTABLELoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_STERRT);
|
|
|
|
if (!loadTerrainTable(pBuffer, size))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the body/propulsion IMDs stats */
|
|
static bool bufferSBPIMDLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
if (!loadBodyPropulsionIMDs(pBuffer, size))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the weapon sound stats */
|
|
static bool bufferSWEAPSNDLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
if (!loadWeaponSounds(pBuffer, size))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the Weapon Effect modifier stats */
|
|
static bool bufferSWEAPMODLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_SWEAPMOD);
|
|
|
|
if (!loadWeaponModifiers(pBuffer, size))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
|
|
/* Load the Template stats */
|
|
static bool bufferSTEMPLLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_STEMP);
|
|
|
|
if (!loadDroidTemplates(pBuffer, size))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// set a dummy value so the release function gets called
|
|
*ppData = (void *)1;
|
|
return true;
|
|
}
|
|
|
|
// release the templates
|
|
static void dataSTEMPLRelease(WZ_DECL_UNUSED void *pData)
|
|
{
|
|
//free the storage allocated to the droid templates
|
|
droidTemplateShutDown();
|
|
}
|
|
|
|
/* Load the Template weapons stats */
|
|
static bool bufferSTEMPWEAPLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_STEMPWEAP);
|
|
|
|
if (!loadDroidWeapons(pBuffer, size))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the Structure stats */
|
|
static bool bufferSSTRUCTLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_SSTRUCT);
|
|
|
|
if (!loadStructureStats(pBuffer, size)
|
|
|| !allocStructLists())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// set a dummy value so the release function gets called
|
|
*ppData = (void *)1;
|
|
return true;
|
|
}
|
|
|
|
// release the structure stats
|
|
static void dataSSTRUCTRelease(WZ_DECL_UNUSED void *pData)
|
|
{
|
|
freeStructureLists();
|
|
structureStatsShutDown();
|
|
}
|
|
|
|
/* Load the Structure Weapons stats */
|
|
static bool bufferSSTRWEAPLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_SSTRWEAP);
|
|
|
|
if (!loadStructureWeapons(pBuffer, size))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the Structure Functions stats */
|
|
static bool bufferSSTRFUNCLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_STRFUNC);
|
|
|
|
if (!loadStructureFunctions(pBuffer, size))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the Structure strength modifier stats */
|
|
static bool bufferSSTRMODLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_SSTRMOD);
|
|
|
|
if (!loadStructureStrengthModifiers(pBuffer, size))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the Feature stats */
|
|
static bool bufferSFEATLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_SFEAT);
|
|
|
|
if (!loadFeatureStats(pBuffer, size))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// set a dummy value so the release function gets called
|
|
*ppData = (void *)1;
|
|
return true;
|
|
}
|
|
|
|
// free the feature stats
|
|
static void dataSFEATRelease(WZ_DECL_UNUSED void *pData)
|
|
{
|
|
featureStatsShutDown();
|
|
}
|
|
|
|
/* Load the Functions stats */
|
|
static bool bufferSFUNCLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_SFUNC);
|
|
|
|
if (!loadFunctionStats(pBuffer, size))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//adjust max values of stats used in the design screen due to any possible upgrades
|
|
adjustMaxDesignStats();
|
|
|
|
// set a dummy value so the release function gets called
|
|
*ppData = (void *)1;
|
|
return true;
|
|
}
|
|
|
|
// release the function stats
|
|
static void dataSFUNCRelease(WZ_DECL_UNUSED void *pData)
|
|
{
|
|
FunctionShutDown();
|
|
}
|
|
|
|
// release the research stats
|
|
static void dataRESCHRelease(WZ_DECL_UNUSED void *pData)
|
|
{
|
|
//free the storage allocated to the stats
|
|
ResearchShutDown();
|
|
}
|
|
|
|
/* Load the Research stats */
|
|
static bool bufferRESCHLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_RESCH);
|
|
|
|
//check to see if already loaded
|
|
if (asResearch.size() > 0)
|
|
{
|
|
//release previous data before loading in the new
|
|
dataRESCHRelease(NULL);
|
|
}
|
|
|
|
if (!loadResearch(pBuffer, size))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
/* set a dummy value so the release function gets called - the Release
|
|
* function is now called when load up the next set
|
|
// *ppData = (void *)1;
|
|
* pass back NULL so that can load the same name file for the next campaign*/
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the research pre-requisites */
|
|
static bool bufferRPREREQLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_RPREREQ);
|
|
|
|
if (!loadResearchPR(pBuffer, size))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the research components made redundant */
|
|
static bool bufferRCOMPREDLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_RCOMPRED);
|
|
|
|
if (!loadResearchArtefacts(pBuffer, size, RED_LIST))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the research component results */
|
|
static bool bufferRCOMPRESLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_RCOMPRES);
|
|
|
|
if (!loadResearchArtefacts(pBuffer, size, RES_LIST))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the research structures required */
|
|
static bool bufferRSTRREQLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_RSTRREQ);
|
|
|
|
if (!loadResearchStructures(pBuffer, size, REQ_LIST))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the research structures made redundant */
|
|
static bool bufferRSTRREDLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_RSTRRED);
|
|
|
|
if (!loadResearchStructures(pBuffer, size, RED_LIST))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the research structure results */
|
|
static bool bufferRSTRRESLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_RSTRRES);
|
|
|
|
if (!loadResearchStructures(pBuffer, size, RES_LIST))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the research functions */
|
|
static bool bufferRFUNCLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
calcDataHash((uint8_t *)pBuffer, size, DATA_RFUNC);
|
|
|
|
if (!loadResearchFunctions(pBuffer, size))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//not interested in this value
|
|
*ppData = NULL;
|
|
return true;
|
|
}
|
|
|
|
/* Load the message viewdata */
|
|
static bool bufferSMSGLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
const char *ptr;
|
|
|
|
ptr = loadViewData(pBuffer, size);
|
|
if (!ptr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// set the pointer so the release function gets called with it
|
|
*ppData = (void *)ptr;
|
|
return true;
|
|
}
|
|
|
|
/* Load research message viewdata */
|
|
static bool dataResearchMsgLoad(const char* fileName, void** ppData)
|
|
{
|
|
const char *ptr = loadResearchViewData(fileName);
|
|
if (!ptr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// set the pointer so the release function gets called with it
|
|
*ppData = (void *)ptr;
|
|
return true;
|
|
}
|
|
|
|
// release the message viewdata
|
|
static void dataSMSGRelease(void *pData)
|
|
{
|
|
viewDataShutDown((const char *)pData);
|
|
}
|
|
|
|
/* Load an imd */
|
|
static bool dataIMDBufferLoad(const char *pBuffer, UDWORD size, void **ppData)
|
|
{
|
|
iIMDShape *psIMD;
|
|
const char *pBufferPosition = pBuffer;
|
|
|
|
psIMD = iV_ProcessIMD( &pBufferPosition, pBufferPosition + size );
|
|
if (psIMD == NULL) {
|
|
debug( LOG_ERROR, "IMD load failed - %s", GetLastResourceFilename() );
|
|
return false;
|
|
}
|
|
|
|
*ppData = psIMD;
|
|
return true;
|
|
}
|
|
|
|
|
|
/*!
|
|
* Load an image from file
|
|
*/
|
|
static bool dataImageLoad(const char *fileName, void **ppData)
|
|
{
|
|
iV_Image *psSprite = (iV_Image *)malloc(sizeof(iV_Image));
|
|
if (!psSprite)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!iV_loadImage_PNG(fileName, psSprite))
|
|
{
|
|
debug( LOG_ERROR, "IMGPAGE load failed" );
|
|
return false;
|
|
}
|
|
|
|
*ppData = psSprite;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// Tertiles (terrain tiles) loader.
|
|
static bool dataTERTILESLoad(const char *fileName, void **ppData)
|
|
{
|
|
bool status;
|
|
|
|
status = texLoad(fileName);
|
|
ASSERT_OR_RETURN(false, status, "Error loading tertiles!");
|
|
debug(LOG_TEXTURE, "HW Tiles loaded");
|
|
|
|
*ppData = NULL; // don't bother calling cleanup
|
|
|
|
return true;
|
|
}
|
|
|
|
static void dataTERTILESRelease(WZ_DECL_UNUSED void *pData)
|
|
{
|
|
}
|
|
|
|
|
|
static bool dataIMGLoad(const char *fileName, void **ppData)
|
|
{
|
|
*ppData = iV_LoadImageFile(fileName);
|
|
if(*ppData == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
static void dataIMGRelease(void *pData)
|
|
{
|
|
iV_FreeImageFile((IMAGEFILE*)pData);
|
|
}
|
|
|
|
|
|
/* Load a texturepage into memory */
|
|
static bool dataTexPageLoad(const char *fileName, void **ppData)
|
|
{
|
|
char texpage[PATH_MAX] = {'\0'};
|
|
|
|
// This hackery is needed, because fileName will include the directory name, whilst the LastResourceFilename will not, and we need a short name to identify the texpage
|
|
sstrcpy(texpage, GetLastResourceFilename());
|
|
|
|
pie_MakeTexPageName(texpage);
|
|
if (!dataImageLoad(fileName, ppData))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// see if this texture page has already been loaded
|
|
if (resPresent(DT_TEXPAGE, texpage))
|
|
{
|
|
// replace the old texture page with the new one
|
|
debug(LOG_TEXTURE, "replacing %s with new texture %s", texpage, fileName);
|
|
pie_ReplaceTexPage((iV_Image *)*ppData, texpage, getTextureSize(), true);
|
|
}
|
|
else
|
|
{
|
|
debug(LOG_TEXTURE, "adding page %s with texture %s", texpage, fileName);
|
|
SetLastResourceFilename(texpage);
|
|
pie_AddTexPage((iV_Image *)*ppData, texpage, 0, getTextureSize(), true);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* Load a team colour mask texturepage into memory */
|
|
static bool dataTexPageTCMaskLoad(const char *fileName, void **ppData)
|
|
{
|
|
char texpage[PATH_MAX] = {'\0'};
|
|
|
|
// This hackery is needed, because fileName will include the directory name, whilst the LastResourceFilename will not, and we need a short name to identify the texpage
|
|
sstrcpy(texpage, GetLastResourceFilename());
|
|
|
|
// Check if a corresponding texpage exists, exit if no
|
|
pie_MakeTexPageName(texpage);
|
|
ASSERT_OR_RETURN(false, resPresent(DT_TEXPAGE, texpage), "Corresponding texpage %s doesn't exists!", texpage);
|
|
|
|
pie_MakeTexPageTCMaskName(texpage);
|
|
|
|
if (!dataImageLoad(fileName, ppData))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// see if this texture page has already been loaded
|
|
if (resPresent(DT_TCMASK, texpage))
|
|
{
|
|
// replace the old texture page with the new one
|
|
debug(LOG_TEXTURE, "replacing %s with new tcmask %s", texpage, fileName);
|
|
pie_ReplaceTexPage((iV_Image *)*ppData, texpage, getTextureSize(), false);
|
|
}
|
|
else
|
|
{
|
|
debug(LOG_TEXTURE, "adding page %s with tcmask %s", texpage, fileName);
|
|
SetLastResourceFilename(texpage);
|
|
pie_AddTexPage((iV_Image *)*ppData, texpage, 0, getTextureSize(), false);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*!
|
|
* Release an Image
|
|
*/
|
|
static void dataImageRelease(void *pData)
|
|
{
|
|
iV_Image *psSprite = (iV_Image*) pData;
|
|
|
|
if( psSprite )
|
|
{
|
|
free(psSprite);
|
|
}
|
|
}
|
|
|
|
|
|
/* Load an audio file */
|
|
static bool dataAudioLoad(const char* fileName, void **ppData)
|
|
{
|
|
if ( audio_Disabled() == true )
|
|
{
|
|
*ppData = NULL;
|
|
// No error occurred (sound is just disabled), so we return true
|
|
return true;
|
|
}
|
|
|
|
// Load the track from a file
|
|
*ppData = sound_LoadTrackFromFile( fileName );
|
|
|
|
return *ppData != NULL;
|
|
}
|
|
|
|
/* Load an audio file */
|
|
static bool dataAudioCfgLoad(const char* fileName, void **ppData)
|
|
{
|
|
bool success;
|
|
PHYSFS_file* fileHandle;
|
|
|
|
*ppData = NULL;
|
|
|
|
if (audio_Disabled())
|
|
{
|
|
return true;
|
|
}
|
|
debug(LOG_WZ, "Reading...[directory: %s] %s", PHYSFS_getRealDir(fileName), fileName);
|
|
fileHandle = PHYSFS_openRead(fileName);
|
|
|
|
if (fileHandle == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
success = ParseResourceFile(fileHandle);
|
|
|
|
PHYSFS_close(fileHandle);
|
|
|
|
return success;
|
|
}
|
|
|
|
/* Load an anim file */
|
|
static bool dataAnimLoad(const char *fileName, void **ppData)
|
|
{
|
|
PHYSFS_file* fileHandle = PHYSFS_openRead(fileName);
|
|
debug(LOG_WZ, "Reading...[directory: %s] %s", PHYSFS_getRealDir(fileName), fileName);
|
|
if (fileHandle == NULL)
|
|
{
|
|
*ppData = NULL;
|
|
return false;
|
|
}
|
|
|
|
*ppData = anim_LoadFromFile(fileHandle);
|
|
|
|
PHYSFS_close(fileHandle);
|
|
|
|
return *ppData != NULL;
|
|
}
|
|
|
|
/* Load an audio config file */
|
|
static bool dataAnimCfgLoad(const char *fileName, void **ppData)
|
|
{
|
|
bool success;
|
|
PHYSFS_file* fileHandle = PHYSFS_openRead(fileName);
|
|
*ppData = NULL;
|
|
|
|
debug(LOG_WZ, "Reading...[directory: %s] %s", PHYSFS_getRealDir(fileName), fileName);
|
|
if (fileHandle == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
success = ParseResourceFile(fileHandle);
|
|
|
|
PHYSFS_close(fileHandle);
|
|
|
|
return success;
|
|
}
|
|
|
|
|
|
static void dataAnimRelease( void *pData )
|
|
{
|
|
anim_ReleaseAnim((BASEANIM*)pData);
|
|
}
|
|
|
|
/* Load a string resource file */
|
|
static bool dataStrResLoad(const char* fileName, void** ppData)
|
|
{
|
|
// recreate the string resource if it was freed by a WRF release
|
|
if (psStringRes == NULL)
|
|
{
|
|
if (!stringsInitialise())
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!strresLoad(psStringRes, fileName))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
*ppData = psStringRes;
|
|
return true;
|
|
}
|
|
|
|
static void dataStrResRelease(WZ_DECL_UNUSED void *pData)
|
|
{
|
|
if (psStringRes != NULL)
|
|
{
|
|
strresDestroy(psStringRes);
|
|
psStringRes = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/* Load a script file */
|
|
// All scripts, binary or otherwise are now passed through this routine
|
|
static bool dataScriptLoad(const char* fileName, void **ppData)
|
|
{
|
|
static const bool printHack = false;
|
|
SCRIPT_CODE** psProg = (SCRIPT_CODE**)ppData;
|
|
PHYSFS_file* fileHandle;
|
|
uint8_t *pBuffer;
|
|
PHYSFS_sint64 fileSize = 0;
|
|
|
|
debug(LOG_WZ, "COMPILING SCRIPT ...%s", GetLastResourceFilename());
|
|
|
|
fileHandle = PHYSFS_openRead(fileName);
|
|
debug(LOG_WZ, "Reading...[directory: %s] %s", PHYSFS_getRealDir(fileName), fileName);
|
|
if (fileHandle == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// due to the changes in r2531 we must do this routine a bit different.
|
|
fileSize = PHYSFS_fileLength(fileHandle);
|
|
|
|
pBuffer = (uint8_t *)malloc(fileSize * sizeof(uint8_t));
|
|
ASSERT_OR_RETURN(false, pBuffer, "Out of memory");
|
|
|
|
PHYSFS_read(fileHandle, pBuffer, 1, fileSize);
|
|
|
|
calcDataHash(pBuffer, fileSize, DATA_SCRIPT);
|
|
|
|
free(pBuffer);
|
|
|
|
PHYSFS_seek(fileHandle, 0); //reset position
|
|
|
|
*psProg = scriptCompile(fileHandle, SCRIPTTYPE);
|
|
|
|
PHYSFS_close(fileHandle);
|
|
|
|
if (!*psProg) // see script.h
|
|
{
|
|
debug(LOG_ERROR, "Script %s did not compile", GetLastResourceFilename());
|
|
return false;
|
|
}
|
|
|
|
if (printHack)
|
|
{
|
|
cpPrintProgram(*psProg);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
static void dataScriptRelease(void *pData)
|
|
{
|
|
SCRIPT_CODE *psCode = (SCRIPT_CODE *)pData;
|
|
scriptFreeCode(psCode);
|
|
}
|
|
|
|
static bool jsLoad(const char *fileName, void **ppData)
|
|
{
|
|
debug(LOG_WZ, "jsload: %s", fileName);
|
|
*ppData = NULL;
|
|
return loadGlobalScript(fileName);
|
|
}
|
|
|
|
// Load a script variable values file
|
|
static bool dataScriptLoadVals(const char* fileName, void **ppData)
|
|
{
|
|
bool success;
|
|
PHYSFS_file* fileHandle;
|
|
uint8_t *pBuffer;
|
|
PHYSFS_sint64 fileSize = 0;
|
|
|
|
*ppData = NULL;
|
|
|
|
// don't load anything if a saved game is being loaded
|
|
if (saveFlag)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
debug(LOG_WZ, "Loading script data %s", GetLastResourceFilename());
|
|
|
|
fileHandle = PHYSFS_openRead(fileName);
|
|
debug(LOG_WZ, "Reading...[directory: %s] %s", PHYSFS_getRealDir(fileName), fileName);
|
|
if (fileHandle == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
// due to the changes in r2532 we must do this routine a bit different.
|
|
fileSize = PHYSFS_fileLength(fileHandle);
|
|
|
|
pBuffer = (uint8_t *)malloc(fileSize * sizeof(uint8_t));
|
|
ASSERT_OR_RETURN(false, pBuffer, "Out of memory");
|
|
|
|
PHYSFS_read(fileHandle, pBuffer, 1, fileSize);
|
|
|
|
calcDataHash(pBuffer, fileSize, DATA_SCRIPTVAL);
|
|
|
|
free(pBuffer);
|
|
|
|
PHYSFS_seek(fileHandle, 0); //reset position
|
|
|
|
success = scrvLoad(fileHandle);
|
|
|
|
if (!success)
|
|
debug(LOG_FATAL, "Script %s did not compile", GetLastResourceFilename());
|
|
|
|
PHYSFS_close(fileHandle);
|
|
|
|
return success;
|
|
}
|
|
|
|
// New reduced resource type ... specially for PSX
|
|
// These are statically defined in data.c
|
|
// this is also defined in frameresource.c - needs moving to a .h file
|
|
// This basically matches the argument list of resAddBufferLoad in frameresource.c
|
|
struct RES_TYPE_MIN_BUF
|
|
{
|
|
const char *aType; ///< points to the string defining the type (e.g. SCRIPT) - NULL indicates end of list
|
|
RES_BUFFERLOAD buffLoad; ///< routine to process the data for this type
|
|
RES_FREE release; ///< routine to release the data (NULL indicates none)
|
|
};
|
|
|
|
static const RES_TYPE_MIN_BUF BufferResourceTypes[] =
|
|
{
|
|
{"SWEAPON", bufferSWEAPONLoad, NULL},
|
|
{"SBODY", bufferSBODYLoad, dataReleaseStats},
|
|
{"SBRAIN", bufferSBRAINLoad, NULL},
|
|
{"SPROP", bufferSPROPLoad, NULL},
|
|
{"SSENSOR", bufferSSENSORLoad, NULL},
|
|
{"SECM", bufferSECMLoad, NULL},
|
|
{"SREPAIR", bufferSREPAIRLoad, NULL},
|
|
{"SCONSTR", bufferSCONSTRLoad, NULL},
|
|
{"SPROPTYPES", bufferSPROPTYPESLoad, NULL},
|
|
{"SPROPSND", bufferSPROPSNDLoad, NULL},
|
|
{"STERRTABLE", bufferSTERRTABLELoad, NULL},
|
|
{"SBPIMD", bufferSBPIMDLoad, NULL},
|
|
{"SWEAPSND", bufferSWEAPSNDLoad, NULL},
|
|
{"SWEAPMOD", bufferSWEAPMODLoad, NULL},
|
|
{"STEMPL", bufferSTEMPLLoad, dataSTEMPLRelease}, //template and associated files
|
|
{"STEMPWEAP", bufferSTEMPWEAPLoad, NULL},
|
|
{"SSTRUCT", bufferSSTRUCTLoad, dataSSTRUCTRelease}, //structure stats and associated files
|
|
{"SSTRFUNC", bufferSSTRFUNCLoad, NULL},
|
|
{"SSTRWEAP", bufferSSTRWEAPLoad, NULL},
|
|
{"SSTRMOD", bufferSSTRMODLoad, NULL},
|
|
{"SFEAT", bufferSFEATLoad, dataSFEATRelease}, //feature stats file
|
|
{"SFUNC", bufferSFUNCLoad, dataSFUNCRelease}, //function stats file
|
|
{"RESCH", bufferRESCHLoad, dataRESCHRelease}, //research stats files
|
|
{"RPREREQ", bufferRPREREQLoad, NULL},
|
|
{"RCOMPRED", bufferRCOMPREDLoad, NULL},
|
|
{"RCOMPRES", bufferRCOMPRESLoad, NULL},
|
|
{"RSTRREQ", bufferRSTRREQLoad, NULL},
|
|
{"RSTRRED", bufferRSTRREDLoad, NULL},
|
|
{"RSTRRES", bufferRSTRRESLoad, NULL},
|
|
{"RFUNC", bufferRFUNCLoad, NULL},
|
|
{"SMSG", bufferSMSGLoad, dataSMSGRelease},
|
|
{"IMD", dataIMDBufferLoad, (RES_FREE)iV_IMDRelease},
|
|
};
|
|
|
|
struct RES_TYPE_MIN_FILE
|
|
{
|
|
const char *aType; ///< points to the string defining the type (e.g. SCRIPT) - NULL indicates end of list
|
|
RES_FILELOAD fileLoad; ///< routine to process the data for this type
|
|
RES_FREE release; ///< routine to release the data (NULL indicates none)
|
|
};
|
|
|
|
static const RES_TYPE_MIN_FILE FileResourceTypes[] =
|
|
{
|
|
{"WAV", dataAudioLoad, (RES_FREE)sound_ReleaseTrack},
|
|
{"AUDIOCFG", dataAudioCfgLoad, NULL},
|
|
{"ANI", dataAnimLoad, dataAnimRelease},
|
|
{"ANIMCFG", dataAnimCfgLoad, NULL},
|
|
{"IMGPAGE", dataImageLoad, dataImageRelease},
|
|
{"TERTILES", dataTERTILESLoad, dataTERTILESRelease},
|
|
{"IMG", dataIMGLoad, dataIMGRelease},
|
|
{DT_TEXPAGE, dataTexPageLoad, dataImageRelease},
|
|
{DT_TCMASK, dataTexPageTCMaskLoad, dataImageRelease},
|
|
{"SCRIPT", dataScriptLoad, dataScriptRelease},
|
|
{"SCRIPTVAL", dataScriptLoadVals, NULL},
|
|
{"STR_RES", dataStrResLoad, dataStrResRelease},
|
|
{"RESEARCHMSG", dataResearchMsgLoad, dataSMSGRelease },
|
|
{"JAVASCRIPT", jsLoad, NULL},
|
|
};
|
|
|
|
/* Pass all the data loading functions to the framework library */
|
|
bool dataInitLoadFuncs(void)
|
|
{
|
|
// init the data integrity hash;
|
|
resetDataHash();
|
|
// Using iterator style: begin iterator (ResourceTypes),
|
|
// end iterator (EndType), and current iterator (CurrentType)
|
|
|
|
// iterate through buffer load functions
|
|
{
|
|
const RES_TYPE_MIN_BUF *CurrentType;
|
|
// Points just past the last item in the list
|
|
const RES_TYPE_MIN_BUF * const EndType = &BufferResourceTypes[sizeof(BufferResourceTypes) / sizeof(RES_TYPE_MIN_BUF)];
|
|
|
|
for (CurrentType = BufferResourceTypes; CurrentType != EndType; ++CurrentType)
|
|
{
|
|
if(!resAddBufferLoad(CurrentType->aType, CurrentType->buffLoad, CurrentType->release))
|
|
{
|
|
return false; // error whilst adding a buffer load
|
|
}
|
|
}
|
|
}
|
|
|
|
// iterate through file load functions
|
|
{
|
|
const RES_TYPE_MIN_FILE *CurrentType;
|
|
// Points just past the last item in the list
|
|
const RES_TYPE_MIN_FILE * const EndType = &FileResourceTypes[sizeof(FileResourceTypes) / sizeof(RES_TYPE_MIN_BUF)];
|
|
|
|
for (CurrentType = FileResourceTypes; CurrentType != EndType; ++CurrentType)
|
|
{
|
|
if(!resAddFileLoad(CurrentType->aType, CurrentType->fileLoad, CurrentType->release))
|
|
{
|
|
return false; // error whilst adding a file load
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|