Files
source/TileEngine/worlddef.cpp
T
Overhaul 7a27e7105d New attack busy system
Added missing #includes

Added LUA scripting and console

Changed the way tracers are visualized, so they work more like real tracers instead of a light fountain

Fixed signedness of many grid variables used in GetMouseMapPos calls

Fixed enemy weapon choosing:  Sometimes a mortar is chosen but later rejected, but the grenade class was not reset.  Caused assertion failure

Added checks so enemies don't try to chuck RPG grenades with their hands

Now possible to shoot a someone in the head if he's in water

Fixed InitSightArrays to also clear soldier interrupt duel points.  This was causing an assertion failure elsewhere in the code because the interrupt list still had soldiers on it sometimes when this function was called.

Soldiers are much less willing to forfeit their turn over an attempt to use more APs than they have

Removed early setting of muzzle flash.  This would allow enemies to get an interrupt before you even fired.

Fixed item dropping by AI.  If AI tried to drop something while standing it would cause deadlock

Change to greatly speed up closing the sector inventory window in an unloaded sector

Added conditional compile flag to always give robot weapon ready advantage, even for 360 degree sighting


Check builddefines.h for the conditional flags.  Of greatest interest might be LUA_CONSOLE.  This will cause the game to bring up a command console when run.  However this console is severely lacking in many areas.  If anybody knows of an open-source terminal/console that could be used instead, it would be appreciated.  The existing console does bad things when you try to close it, and since it counts as a separate app, it pauses the game while it has focus.

LUA scripting is very limited, basically just proof of concept.  There is one global variable, the Soldiers array.  An array index gives you the soldier in that slot in the currently loaded sector.  The soldier has a few things that can be accessed:  name (short name); fullname (long name); grid (current grid #, can be changed); walkto(grid) (function to walk to another grid); runto(grid) (function to run to another grid)


git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@924 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2007-06-09 09:01:04 +00:00

4169 lines
117 KiB
C++

#include "builddefines.h"
#ifdef PRECOMPILEDHEADERS
#include "TileEngine All.h"
#include "PreBattle Interface.h"
#else
#include "worlddef.h"
#include "worlddat.h"
#include <stdio.h>
#include <string.h>
#include "wcheck.h"
#include "stdlib.h"
#include "time.h"
#include "video.h"
#include "debug.h"
#include "smooth.h"
#include "worldman.h"
#include "mousesystem.h"
#include "sys globals.h"
#include "screenids.h"
#include "Render Fun.h"
#include "font control.h"
#include "lighting.h"
#include "structure.h"
#include "vobject.h"
#include "Soldier Control.h"
#include "isometric utils.h"
#include "Interactive Tiles.h"
#include "utilities.h"
#include "overhead.h"
#include "points.h"
#include "Event Pump.h"
#include "Handle UI.h"
#include "opplist.h"
#include "shading.h"
#include "Animation Control.h"
#include "World Items.h"
#include "renderworld.h"
#include "Radar Screen.h"
#include "soldier create.h"
#include "Soldier Init List.h"
#include "Exit Grids.h"
#include "tile surface.h"
#include "rotting corpses.h"
#include "Keys.h"
#include "Map Information.h"
#include "Exit Grids.h"
#include "Summary Info.h"
#include "Animated ProgressBar.h"
#include "pathai.h"
#include "EditorBuildings.h"
#include "FileMan.h"
#include "music control.h"
#include "Map Edgepoints.h"
#include "environment.h"
#include "Shade Table Util.h"
#include "Structure Wrap.h"
#include "Scheduling.h"
#include "EditorMapInfo.h"
#include "pits.h"
#include "Game Clock.h"
#include "Buildings.h"
#include "strategicmap.h"
#include "overhead map.h"
#include "SmokeEffects.h"
#include "LightEffects.h"
#include "meanwhile.h"
#endif
#define SET_MOVEMENTCOST( a, b, c, d ) ( ( gubWorldMovementCosts[ a ][ b ][ c ] < d ) ? ( gubWorldMovementCosts[ a ][ b ][ c ] = d ) : 0 );
#define FORCE_SET_MOVEMENTCOST( a, b, c, d ) ( gubWorldMovementCosts[ a ][ b ][ c ] = d )
#define SET_CURRMOVEMENTCOST( a, b ) SET_MOVEMENTCOST( usGridNo, a, 0, b )
#define TEMP_FILE_FOR_TILESET_CHANGE "jatileS34.dat"
#define MAP_FULLSOLDIER_SAVED 0x00000001
#define MAP_WORLDONLY_SAVED 0x00000002
#define MAP_WORLDLIGHTS_SAVED 0x00000004
#define MAP_WORLDITEMS_SAVED 0x00000008
#define MAP_EXITGRIDS_SAVED 0x00000010
#define MAP_DOORTABLE_SAVED 0x00000020
#define MAP_EDGEPOINTS_SAVED 0x00000040
#define MAP_AMBIENTLIGHTLEVEL_SAVED 0x00000080
#define MAP_NPCSCHEDULES_SAVED 0x00000100
#ifdef JA2EDITOR
extern BOOLEAN gfErrorCatch;
extern CHAR16 gzErrorCatchString[256];
#endif
CHAR8 gubFilename[200];
// TEMP
BOOLEAN gfForceLoadPlayers = FALSE;
CHAR8 gzForceLoadFile[100 ];
BOOLEAN gfForceLoad = FALSE;
UINT8 gubCurrentLevel;
INT32 giCurrentTilesetID = 0;
CHAR8 gzLastLoadedFile[ 260 ];
UINT32 gCurrentBackground = FIRSTTEXTURE;
// From memman.c in SGP
extern UINT32 guiMemTotal;
CHAR8 TileSurfaceFilenames[NUMBEROFTILETYPES][32];
INT8 gbNewTileSurfaceLoaded[ NUMBEROFTILETYPES ];
void SetAllNewTileSurfacesLoaded( BOOLEAN fNew )
{
memset( gbNewTileSurfaceLoaded, fNew, sizeof( gbNewTileSurfaceLoaded ) );
}
BOOLEAN gfInitAnimateLoading = FALSE;
// Local Functions
BOOLEAN LoadTileSurfaces( char pTileSurfaceFilenames[][32], UINT8 ubTilesetID );
BOOLEAN AddTileSurface( SGPFILENAME cFilename, UINT32 ubType, UINT8 ubTilesetID, BOOLEAN fGetFromRoot );
void DestroyTileSurfaces( void );
void ProcessTilesetNamesForBPP(void);
BOOLEAN IsRoofVisibleForWireframe( INT16 sMapPos );
INT8 IsHiddenTileMarkerThere( INT16 sGridNo );
extern void SetInterfaceHeightLevel( );
extern void GetRootName( STR8 pDestStr, const STR8 pSrcStr );
void SaveMapLights( HWFILE hfile );
void LoadMapLights( INT8 **hBuffer );
// Global Variables
MAP_ELEMENT *gpWorldLevelData;
INT32 *gpDirtyData;
UINT32 gSurfaceMemUsage;
UINT8 gubWorldMovementCosts[ WORLD_MAX ][MAXDIR][2];
// set to nonzero (locs of base gridno of structure are good) to have it defined by structure code
INT16 gsRecompileAreaTop = 0;
INT16 gsRecompileAreaLeft = 0;
INT16 gsRecompileAreaRight = 0;
INT16 gsRecompileAreaBottom = 0;
//TIMER TESTING STUFF
#ifdef JA2TESTVERSION
extern UINT32 uiLoadWorldTime;
extern UINT32 uiTrashWorldTime;
extern UINT32 uiLoadMapTilesetTime;
extern UINT32 uiLoadMapLightsTime;
extern UINT32 uiBuildShadeTableTime;
extern UINT32 uiNumTablesLoaded;
extern UINT32 uiNumTablesSaved;
extern UINT32 uiNumImagesReloaded;
#endif
BOOLEAN DoorAtGridNo( UINT32 iMapIndex )
{
STRUCTURE *pStruct;
pStruct = gpWorldLevelData[ iMapIndex ].pStructureHead;
while( pStruct )
{
if( pStruct->fFlags & STRUCTURE_ANYDOOR )
return TRUE;
pStruct = pStruct->pNext;
}
return FALSE;
}
BOOLEAN OpenableAtGridNo( UINT32 iMapIndex )
{
STRUCTURE *pStruct;
pStruct = gpWorldLevelData[ iMapIndex ].pStructureHead;
while( pStruct )
{
if( pStruct->fFlags & STRUCTURE_OPENABLE )
return TRUE;
pStruct = pStruct->pNext;
}
return FALSE;
}
BOOLEAN FloorAtGridNo( UINT32 iMapIndex )
{
LEVELNODE *pLand;
UINT32 uiTileType;
pLand = gpWorldLevelData[ iMapIndex ].pLandHead;
// Look through all objects and Search for type
while( pLand )
{
if ( pLand->usIndex != NO_TILE )
{
GetTileType( pLand->usIndex, &uiTileType );
if ( uiTileType >= FIRSTFLOOR && uiTileType <= LASTFLOOR )
{
return TRUE;
}
pLand = pLand->pNext;
}
}
return FALSE;
}
BOOLEAN GridNoIndoors( UINT32 iMapIndex )
{
if( gfBasement || gfCaves )
return TRUE;
if( FloorAtGridNo( iMapIndex ) )
return TRUE;
return FALSE;
}
void DOIT( )
{
// LEVELNODE * pLand;
//LEVELNODE * pObject;
LEVELNODE * pStruct, *pNewStruct;
//LEVELNODE * pShadow;
UINT32 uiLoop;
// first level
for( uiLoop = 0; uiLoop < WORLD_MAX; uiLoop++ )
{
pStruct = gpWorldLevelData[ uiLoop ].pStructHead;
while ( pStruct != NULL )
{
pNewStruct = pStruct->pNext;
if ( pStruct->usIndex >= DEBRISWOOD1 && pStruct->usIndex <= DEBRISWEEDS10 )
{
AddObjectToHead( uiLoop, pStruct->usIndex );
RemoveStruct( uiLoop, pStruct->usIndex );
}
pStruct = pNewStruct;
}
}
}
BOOLEAN InitializeWorld( )
{
gTileDatabaseSize = 0;
gSurfaceMemUsage = 0;
giCurrentTilesetID = -1;
// DB Adds the _8 to the names if we're in 8 bit mode.
//ProcessTilesetNamesForBPP();
// Memset tileset list
memset( TileSurfaceFilenames, '\0', sizeof( TileSurfaceFilenames ) );
// ATE: MEMSET LOG HEIGHT VALUES
memset( gTileTypeLogicalHeight, 1, sizeof( gTileTypeLogicalHeight ) );
// Memset tile database
memset( gTileDatabase, 0, sizeof( gTileDatabase ) );
// Init surface list
memset( gTileSurfaceArray, 0, sizeof( gTileSurfaceArray ) );
// Init default surface list
memset( gbDefaultSurfaceUsed, 0, sizeof( gbDefaultSurfaceUsed ) );
// Init same surface list
memset( gbSameAsDefaultSurfaceUsed, 0, sizeof( gbSameAsDefaultSurfaceUsed ) );
// Initialize world data
gpWorldLevelData = (MAP_ELEMENT *)MemAlloc( WORLD_MAX * sizeof( MAP_ELEMENT ) );
CHECKF( gpWorldLevelData );
// Zero world
memset( gpWorldLevelData, 0, WORLD_MAX * sizeof( MAP_ELEMENT ) );
// Init room database
InitRoomDatabase( );
// INit tilesets
InitEngineTilesets( );
return( TRUE );
}
void DeinitializeWorld( )
{
TrashWorld();
if ( gpWorldLevelData != NULL )
{
MemFree( gpWorldLevelData );
}
if ( gpDirtyData != NULL )
{
MemFree( gpDirtyData );
}
DestroyTileSurfaces( );
FreeAllStructureFiles( );
// Shutdown tile database data
DeallocateTileDatabase( );
ShutdownRoomDatabase( );
}
BOOLEAN ReloadTilesetSlot( INT32 iSlot )
{
return(TRUE);
}
BOOLEAN LoadTileSurfaces( char ppTileSurfaceFilenames[][32], UINT8 ubTilesetID )
{
SGPFILENAME cTemp;
UINT32 uiLoop;
UINT32 uiPercentage;
//UINT32 uiLength;
//UINT16 uiFillColor;
STRING512 ExeDir;
STRING512 INIFile;
// Get Executable Directory
GetExecutableDirectory( ExeDir );
// Adjust Current Dir
// CHECK IF DEFAULT INI OVERRIDE FILE EXISTS
sprintf( INIFile, "%s\\engine.ini", ExeDir );
if ( !FileExists( INIFile ) )
{
// USE PER TILESET BASIS
sprintf( INIFile, "%s\\engine%d.ini", ExeDir, ubTilesetID );
}
// If no Tileset filenames are given, return error
if (ppTileSurfaceFilenames == NULL)
{
return( FALSE );
}
else
{
for (uiLoop = 0; uiLoop < NUMBEROFTILETYPES; uiLoop++)
strcpy( TileSurfaceFilenames[uiLoop], ppTileSurfaceFilenames[uiLoop] );//(ppTileSurfaceFilenames + (65 * uiLoop)) );
}
//uiFillColor = Get16BPPColor(FROMRGB(223, 223, 223));
//StartFrameBufferRender( );
//ColorFillVideoSurfaceArea( FRAME_BUFFER, 20, 399, 622, 420, uiFillColor );
//ColorFillVideoSurfaceArea( FRAME_BUFFER, 21, 400, 621, 419, 0 );
//EndFrameBufferRender( );
//uiFillColor = Get16BPPColor(FROMRGB( 100, 0, 0 ));
// load the tile surfaces
SetRelativeStartAndEndPercentage( 0, 1, 35, L"Tile Surfaces" );
for (uiLoop = 0; uiLoop < NUMBEROFTILETYPES; uiLoop++)
{
uiPercentage = (uiLoop * 100) / (NUMBEROFTILETYPES-1);
RenderProgressBar( 0, uiPercentage );
//uiFillColor = Get16BPPColor(FROMRGB( 100 + uiPercentage , 0, 0 ));
//ColorFillVideoSurfaceArea( FRAME_BUFFER, 22, 401, 22 + uiLength, 418, uiFillColor );
//InvalidateRegion( 0, 399, 640, 420 );
//EndFrameBufferRender( );
// The cost of having to do this check each time through the loop,
// thus about 20 times, seems better than having to maintain two
// almost completely identical functions
if (ppTileSurfaceFilenames == NULL)
{
GetPrivateProfileString( "TileSurface Filenames", gTileSurfaceName[uiLoop], "", cTemp, SGPFILENAME_LEN, INIFile );
if (*cTemp != '\0')
{
strcpy( TileSurfaceFilenames[uiLoop], cTemp );
if (AddTileSurface( cTemp, uiLoop, ubTilesetID, TRUE ) == FALSE)
{
DestroyTileSurfaces( );
return( FALSE );
}
}
else
{
// Use default
if (AddTileSurface( TileSurfaceFilenames[uiLoop], uiLoop, ubTilesetID, FALSE ) == FALSE)
{
DestroyTileSurfaces( );
return( FALSE );
}
}
}
else
{
GetPrivateProfileString( "TileSurface Filenames", gTileSurfaceName[uiLoop], "", cTemp, SGPFILENAME_LEN, INIFile );
if (*cTemp != '\0')
{
strcpy( TileSurfaceFilenames[uiLoop], cTemp );
if (AddTileSurface( cTemp, uiLoop, ubTilesetID, TRUE ) == FALSE)
{
DestroyTileSurfaces( );
return( FALSE );
}
}
else
{
if (*(ppTileSurfaceFilenames[uiLoop]) != '\0')
{
if (AddTileSurface( ppTileSurfaceFilenames[uiLoop], uiLoop, ubTilesetID, FALSE ) == FALSE)
{
DestroyTileSurfaces( );
return( FALSE );
}
}
else
{
// USE FIRST TILESET VALUE!
// ATE: If here, don't load default surface if already loaded...
if ( !gbDefaultSurfaceUsed[ uiLoop ] )
{
strcpy( TileSurfaceFilenames[uiLoop], gTilesets[ TLS_GENERIC_1 ].TileSurfaceFilenames[uiLoop] );//(ppTileSurfaceFilenames + (65 * uiLoop)) );
if (AddTileSurface( gTilesets[ TLS_GENERIC_1 ].TileSurfaceFilenames[uiLoop], uiLoop, TLS_GENERIC_1, FALSE ) == FALSE)
{
DestroyTileSurfaces( );
return( FALSE );
}
}
else
{
gbSameAsDefaultSurfaceUsed[ uiLoop ] = TRUE;
}
}
}
}
}
return( TRUE );
}
BOOLEAN AddTileSurface( STR8 cFilename, UINT32 ubType, UINT8 ubTilesetID, BOOLEAN fGetFromRoot )
{
// Add tile surface
PTILE_IMAGERY TileSurf;
CHAR8 cFileBPP[128];
CHAR8 cAdjustedFile[ 128 ];
// Delete the surface first!
if ( gTileSurfaceArray[ ubType ] != NULL )
{
DeleteTileSurface( gTileSurfaceArray[ ubType ] );
gTileSurfaceArray[ ubType ] = NULL;
}
// Adjust flag for same as default used...
gbSameAsDefaultSurfaceUsed[ ubType ] = FALSE;
// Adjust for BPP
FilenameForBPP(cFilename, cFileBPP);
if ( !fGetFromRoot )
{
// Adjust for tileset position
sprintf( cAdjustedFile, "TILESETS\\%d\\%s", ubTilesetID, cFileBPP );
}
else
{
sprintf( cAdjustedFile, "%s", cFileBPP );
}
TileSurf = LoadTileSurface( cAdjustedFile );
if ( TileSurf == NULL )
return( FALSE );
TileSurf->fType = ubType;
SetRaisedObjectFlag( cAdjustedFile, TileSurf );
gTileSurfaceArray[ ubType ] = TileSurf;
// OK, if we were not the default tileset, set value indicating that!
if ( ubTilesetID != TLS_GENERIC_1 )
{
gbDefaultSurfaceUsed[ ubType ] = FALSE;
}
else
{
gbDefaultSurfaceUsed[ ubType ] = TRUE;
}
gbNewTileSurfaceLoaded[ ubType ] = TRUE;
return( TRUE );
}
extern BOOLEAN gfLoadShadeTablesFromTextFile;
void BuildTileShadeTables( )
{
HWFILE hfile;
STRING512 DataDir;
STRING512 ShadeTableDir;
UINT32 uiLoop;
CHAR8 cRootFile[ 128 ];
BOOLEAN fForceRebuildForSlot = FALSE;
#ifdef JA2TESTVERSION
UINT32 uiStartTime;
#endif
static UINT8 ubLastRed = 255, ubLastGreen = 255, ubLastBlue = 255;
#ifdef JA2TESTVERSION
uiNumTablesLoaded = 0;
uiNumTablesSaved = 0;
uiNumImagesReloaded = 0;
uiStartTime = GetJA2Clock();
#endif
//Set the directory to the shadetable directory
GetFileManCurrentDirectory( DataDir );
sprintf( ShadeTableDir, "%s\\ShadeTables", DataDir );
if( !SetFileManCurrentDirectory( ShadeTableDir ) )
{
AssertMsg( 0, "Can't set the directory to Data\\ShadeTable. Kris' big problem!" );
}
hfile = FileOpen( "IgnoreShadeTables.txt", FILE_ACCESS_READ, FALSE );
if( hfile )
{
FileClose( hfile );
gfForceBuildShadeTables = TRUE;
}
else
{
gfForceBuildShadeTables = FALSE;
}
//now, determine if we are using specialized colors.
if( gpLightColors[0].peRed || gpLightColors[0].peGreen || gpLightColors[0].peBlue )
{ //we are, which basically means we force build the shadetables. However, the one
//exception is if we are loading another map and the colors are the same.
if( gpLightColors[0].peRed != ubLastRed ||
gpLightColors[0].peGreen != ubLastGreen ||
gpLightColors[0].peBlue != ubLastBlue )
{ //Same tileset, but colors are different, so set things up to regenerate the shadetables.
gfForceBuildShadeTables = TRUE;
}
else
{ //same colors, same tileset, so don't rebuild shadetables -- much faster!
gfForceBuildShadeTables = FALSE;
}
}
if( gfLoadShadeTablesFromTextFile )
{ //Because we're tweaking the RGB values in the text file, always force rebuild the shadetables
//so that the user can tweak them in the same exe session.
memset( gbNewTileSurfaceLoaded, 1, sizeof( gbNewTileSurfaceLoaded ) );
}
for (uiLoop = 0; uiLoop < NUMBEROFTILETYPES; uiLoop++)
{
if ( gTileSurfaceArray[ uiLoop ] != NULL )
{
// Don't Create shade tables if default were already used once!
#ifdef JA2EDITOR
if( gbNewTileSurfaceLoaded[ uiLoop ] || gfEditorForceShadeTableRebuild )
#else
if( gbNewTileSurfaceLoaded[ uiLoop ] )
#endif
{
fForceRebuildForSlot = FALSE;
GetRootName( cRootFile, TileSurfaceFilenames[ uiLoop ] );
if ( strcmp( cRootFile, "grass2" ) == 0 )
{
fForceRebuildForSlot = TRUE;
}
#ifdef JA2TESTVERSION
uiNumImagesReloaded++;
#endif
RenderProgressBar( 0, uiLoop * 100 / NUMBEROFTILETYPES );
CreateTilePaletteTables( gTileSurfaceArray[ uiLoop ]->vo, uiLoop, fForceRebuildForSlot );
}
}
}
//Restore the data directory once we are finished.
SetFileManCurrentDirectory( DataDir );
ubLastRed = gpLightColors[0].peRed;
ubLastGreen = gpLightColors[0].peGreen;
ubLastBlue = gpLightColors[0].peBlue;
#ifdef JA2TESTVERSION
uiBuildShadeTableTime = GetJA2Clock() - uiStartTime;
#endif
}
void DestroyTileShadeTables( )
{
UINT32 uiLoop;
for (uiLoop = 0; uiLoop < NUMBEROFTILETYPES; uiLoop++)
{
if ( gTileSurfaceArray[ uiLoop ] != NULL )
{
// Don't Delete shade tables if default are still being used...
#ifdef JA2EDITOR
if( gbNewTileSurfaceLoaded[ uiLoop ] || gfEditorForceShadeTableRebuild )
{
DestroyObjectPaletteTables( gTileSurfaceArray[ uiLoop ]->vo );
}
#else
if( gbNewTileSurfaceLoaded[ uiLoop ] )
{
DestroyObjectPaletteTables( gTileSurfaceArray[ uiLoop ]->vo );
}
#endif
}
}
}
void DestroyTileSurfaces( )
{
UINT32 uiLoop;
for (uiLoop = 0; uiLoop < NUMBEROFTILETYPES; uiLoop++)
{
if ( gTileSurfaceArray[ uiLoop ] != NULL )
{
DeleteTileSurface( gTileSurfaceArray[ uiLoop ] );
gTileSurfaceArray[ uiLoop ] = NULL;
}
}
}
void CompileWorldTerrainIDs( void )
{
INT16 sGridNo;
INT16 sTempGridNo;
LEVELNODE * pNode;
TILE_ELEMENT * pTileElement;
UINT8 ubLoop;
for( sGridNo = 0; sGridNo < WORLD_MAX; sGridNo++ )
{
if (GridNoOnVisibleWorldTile( sGridNo ))
{
// Check if we have anything in object layer which has a terrain modifier
pNode = gpWorldLevelData[ sGridNo ].pObjectHead;
// ATE: CRAPOLA! Special case stuff here for the friggen pool since art was fu*ked up
if ( giCurrentTilesetID == TLS_BALIME_MUSEUM )
{
// Get ID
if ( pNode != NULL )
{
if ( pNode->usIndex == ANOTHERDEBRIS4 || pNode->usIndex == ANOTHERDEBRIS6 ||pNode->usIndex == ANOTHERDEBRIS7 )
{
gpWorldLevelData[sGridNo].ubTerrainID = LOW_WATER;
continue;
}
}
}
if (pNode == NULL || pNode->usIndex >= NUMBEROFTILES || gTileDatabase[ pNode->usIndex ].ubTerrainID == NO_TERRAIN)
{ // Try terrain instead!
pNode = gpWorldLevelData[ sGridNo ].pLandHead;
}
pTileElement = &(gTileDatabase[ pNode->usIndex ]);
if (pTileElement->ubNumberOfTiles > 1)
{
for (ubLoop = 0; ubLoop < pTileElement->ubNumberOfTiles; ubLoop++)
{
sTempGridNo = sGridNo + pTileElement->pTileLocData[ubLoop].bTileOffsetX + pTileElement->pTileLocData[ubLoop].bTileOffsetY * WORLD_COLS;
gpWorldLevelData[sTempGridNo].ubTerrainID = pTileElement->ubTerrainID;
}
}
else
{
gpWorldLevelData[sGridNo].ubTerrainID = pTileElement->ubTerrainID;
}
}
}
}
void CompileTileMovementCosts( UINT16 usGridNo )
{
UINT8 ubTerrainID;
TILE_ELEMENT TileElem;
LEVELNODE * pLand;
STRUCTURE * pStructure;
BOOLEAN fStructuresOnRoof;
UINT8 ubDirLoop;
/*
*/
if ( GridNoOnVisibleWorldTile( usGridNo ) )
{
// check for land of a different height in adjacent locations
for ( ubDirLoop = 0; ubDirLoop < 8; ubDirLoop++ )
{
if ( gpWorldLevelData[ usGridNo ].sHeight !=
gpWorldLevelData[ usGridNo + DirectionInc( ubDirLoop ) ].sHeight )
{
SET_CURRMOVEMENTCOST( ubDirLoop, TRAVELCOST_OBSTACLE );
}
}
// check for exit grids
if ( ExitGridAtGridNo( usGridNo ) )
{
for (ubDirLoop=0; ubDirLoop < 8; ubDirLoop++)
{
SET_CURRMOVEMENTCOST( ubDirLoop, TRAVELCOST_EXITGRID );
}
// leave the roof alone, and continue, so that we can get values for the roof if traversable
}
}
else
{
for (ubDirLoop=0; ubDirLoop < 8; ubDirLoop++)
{
SET_MOVEMENTCOST( usGridNo, ubDirLoop, 0, TRAVELCOST_OFF_MAP );
SET_MOVEMENTCOST( usGridNo, ubDirLoop, 1, TRAVELCOST_OFF_MAP );
}
if (gpWorldLevelData[usGridNo].pStructureHead == NULL)
{
return;
}
}
if (gpWorldLevelData[usGridNo].pStructureHead != NULL)
{ // structures in tile
// consider the land
pLand = gpWorldLevelData[ usGridNo ].pLandHead;
if ( pLand != NULL )
{
// Set TEMPORARY cost here
// Get from tile database
TileElem = gTileDatabase[ pLand->usIndex ];
// Get terrain type
ubTerrainID = gpWorldLevelData[usGridNo].ubTerrainID; // = GetTerrainType( (INT16)usGridNo );
for (ubDirLoop=0; ubDirLoop < NUM_WORLD_DIRECTIONS; ubDirLoop++)
{
SET_CURRMOVEMENTCOST( ubDirLoop, gTileTypeMovementCost[ ubTerrainID ] );
}
}
// now consider all structures
pStructure = gpWorldLevelData[usGridNo].pStructureHead;
fStructuresOnRoof = FALSE;
do
{
if (pStructure->sCubeOffset == STRUCTURE_ON_GROUND)
{
if (pStructure->fFlags & STRUCTURE_PASSABLE)
{
if (pStructure->fFlags & STRUCTURE_WIREFENCE && pStructure->fFlags & STRUCTURE_OPEN)
{
// prevent movement along the fence but allow in all other directions
switch( pStructure->ubWallOrientation )
{
case OUTSIDE_TOP_LEFT:
case INSIDE_TOP_LEFT:
SET_CURRMOVEMENTCOST( NORTH, TRAVELCOST_NOT_STANDING );
SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_NOT_STANDING );
SET_CURRMOVEMENTCOST( EAST, TRAVELCOST_OBSTACLE );
SET_CURRMOVEMENTCOST( SOUTHEAST, TRAVELCOST_NOT_STANDING );
SET_CURRMOVEMENTCOST( SOUTH, TRAVELCOST_NOT_STANDING );
SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_NOT_STANDING );
SET_CURRMOVEMENTCOST( WEST, TRAVELCOST_OBSTACLE );
SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_NOT_STANDING );
break;
case OUTSIDE_TOP_RIGHT:
case INSIDE_TOP_RIGHT:
SET_CURRMOVEMENTCOST( NORTH, TRAVELCOST_OBSTACLE );
SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_NOT_STANDING );
SET_CURRMOVEMENTCOST( EAST, TRAVELCOST_NOT_STANDING );
SET_CURRMOVEMENTCOST( SOUTHEAST, TRAVELCOST_NOT_STANDING );
SET_CURRMOVEMENTCOST( SOUTH, TRAVELCOST_OBSTACLE );
SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_NOT_STANDING );
SET_CURRMOVEMENTCOST( WEST, TRAVELCOST_NOT_STANDING );
SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_NOT_STANDING );
break;
}
}
// all other passable structures do not block movement in any way
}
else if (pStructure->fFlags & STRUCTURE_BLOCKSMOVES)
{
if ( (pStructure->fFlags & STRUCTURE_FENCE) && !(pStructure->fFlags & STRUCTURE_SPECIAL) )
{
// jumpable!
switch( pStructure->ubWallOrientation )
{
case OUTSIDE_TOP_LEFT:
case INSIDE_TOP_LEFT:
// can be jumped north and south
SET_CURRMOVEMENTCOST( NORTH, TRAVELCOST_FENCE );
SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_OBSTACLE );
SET_CURRMOVEMENTCOST( EAST, TRAVELCOST_OBSTACLE );
SET_CURRMOVEMENTCOST( SOUTHEAST, TRAVELCOST_OBSTACLE );
SET_CURRMOVEMENTCOST( SOUTH, TRAVELCOST_FENCE );
SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_OBSTACLE );
SET_CURRMOVEMENTCOST( WEST, TRAVELCOST_OBSTACLE );
SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_OBSTACLE );
// set values for the tiles EXITED from this location
FORCE_SET_MOVEMENTCOST( usGridNo - WORLD_COLS, NORTH, 0, TRAVELCOST_NONE );
SET_MOVEMENTCOST( usGridNo - WORLD_COLS + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + 1, EAST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE );
FORCE_SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_NONE );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS - 1, SOUTHWEST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo - 1, WEST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo - WORLD_COLS - 1, NORTHWEST, 0, TRAVELCOST_OBSTACLE );
break;
case OUTSIDE_TOP_RIGHT:
case INSIDE_TOP_RIGHT:
// can be jumped east and west
SET_CURRMOVEMENTCOST( NORTH, TRAVELCOST_OBSTACLE );
SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_OBSTACLE );
SET_CURRMOVEMENTCOST( EAST, TRAVELCOST_FENCE );
SET_CURRMOVEMENTCOST( SOUTHEAST, TRAVELCOST_OBSTACLE );
SET_CURRMOVEMENTCOST( SOUTH, TRAVELCOST_OBSTACLE );
SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_OBSTACLE );
SET_CURRMOVEMENTCOST( WEST, TRAVELCOST_FENCE );
SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_OBSTACLE );
// set values for the tiles EXITED from this location
SET_MOVEMENTCOST( usGridNo - WORLD_COLS, NORTH, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo - WORLD_COLS + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE );
// make sure no obstacle costs exists before changing path cost to 0
if ( gubWorldMovementCosts[ usGridNo + 1 ][ EAST ][ 0 ] < TRAVELCOST_BLOCKED )
{
FORCE_SET_MOVEMENTCOST( usGridNo + 1, EAST, 0, TRAVELCOST_NONE );
}
SET_MOVEMENTCOST( usGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS - 1, SOUTHWEST, 0, TRAVELCOST_OBSTACLE );
if ( gubWorldMovementCosts[ usGridNo - 1 ][ WEST ][ 0 ] < TRAVELCOST_BLOCKED )
{
FORCE_SET_MOVEMENTCOST( usGridNo - 1, WEST, 0, TRAVELCOST_NONE );
}
SET_MOVEMENTCOST( usGridNo - WORLD_COLS - 1, NORTHWEST, 0, TRAVELCOST_OBSTACLE );
break;
default:
// corners aren't jumpable
for (ubDirLoop=0; ubDirLoop < NUM_WORLD_DIRECTIONS; ubDirLoop++)
{
SET_CURRMOVEMENTCOST( ubDirLoop, TRAVELCOST_OBSTACLE );
}
break;
}
}
else if ( pStructure->pDBStructureRef->pDBStructure->ubArmour == MATERIAL_SANDBAG && StructureHeight( pStructure ) < 2 )
{
for (ubDirLoop=0; ubDirLoop < NUM_WORLD_DIRECTIONS; ubDirLoop++)
{
SET_CURRMOVEMENTCOST( ubDirLoop, TRAVELCOST_OBSTACLE );
}
if ( FindStructure( (UINT16) (usGridNo - WORLD_COLS), STRUCTURE_OBSTACLE ) == FALSE && FindStructure( (UINT16)(usGridNo + WORLD_COLS), STRUCTURE_OBSTACLE ) == FALSE )
{
FORCE_SET_MOVEMENTCOST( usGridNo, NORTH, 0, TRAVELCOST_FENCE );
FORCE_SET_MOVEMENTCOST( usGridNo, SOUTH, 0, TRAVELCOST_FENCE );
}
if ( FindStructure( (UINT16)(usGridNo - 1), STRUCTURE_OBSTACLE ) == FALSE && FindStructure( (UINT16)(usGridNo + 1), STRUCTURE_OBSTACLE ) == FALSE )
{
FORCE_SET_MOVEMENTCOST( usGridNo, EAST, 0, TRAVELCOST_FENCE );
FORCE_SET_MOVEMENTCOST( usGridNo, WEST, 0, TRAVELCOST_FENCE );
}
}
else if ( (pStructure->fFlags & STRUCTURE_CAVEWALL ) )
{
for (ubDirLoop=0; ubDirLoop < NUM_WORLD_DIRECTIONS; ubDirLoop++)
{
SET_CURRMOVEMENTCOST( ubDirLoop, TRAVELCOST_CAVEWALL );
}
}
else
{
for (ubDirLoop=0; ubDirLoop < NUM_WORLD_DIRECTIONS; ubDirLoop++)
{
SET_CURRMOVEMENTCOST( ubDirLoop, TRAVELCOST_OBSTACLE );
}
}
}
else if (pStructure->fFlags & STRUCTURE_ANYDOOR) /*&& (pStructure->fFlags & STRUCTURE_OPEN))*/
{ // NB closed doors are treated just like walls, in the section after this
if (pStructure->fFlags & STRUCTURE_DDOOR_LEFT && (pStructure->ubWallOrientation == INSIDE_TOP_RIGHT || pStructure->ubWallOrientation == OUTSIDE_TOP_RIGHT) )
{
// double door, left side (as you look on the screen)
switch( pStructure->ubWallOrientation )
{
case OUTSIDE_TOP_RIGHT:
if (pStructure->fFlags & STRUCTURE_BASE_TILE)
{ // doorpost
SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_WALL );
SET_CURRMOVEMENTCOST( WEST, TRAVELCOST_DOOR_CLOSED_HERE );
SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + 1, NORTHEAST, 0, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + 1, EAST, 0, TRAVELCOST_DOOR_CLOSED_W );
SET_MOVEMENTCOST( usGridNo + 1, SOUTHEAST, 0, TRAVELCOST_WALL );
// corner
SET_MOVEMENTCOST( usGridNo + 1 + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_WALL );
}
else
{ // door
SET_CURRMOVEMENTCOST( NORTH, TRAVELCOST_DOOR_OPEN_W );
SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_DOOR_OPEN_W );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_DOOR_OPEN_NW );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_DOOR_OPEN_NW );
SET_MOVEMENTCOST( usGridNo + 1, NORTHEAST, 0, TRAVELCOST_DOOR_OPEN_W_W );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_DOOR_OPEN_NW_W );
}
break;
case INSIDE_TOP_RIGHT:
// doorpost
SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + 1,NORTHEAST, 0, TRAVELCOST_WALL );
// door
SET_CURRMOVEMENTCOST( NORTH, TRAVELCOST_DOOR_OPEN_HERE );
SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_DOOR_OPEN_HERE );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_DOOR_OPEN_N );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_DOOR_OPEN_N );
SET_MOVEMENTCOST( usGridNo - 1, NORTHWEST, 0, TRAVELCOST_DOOR_OPEN_E );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS - 1, SOUTHWEST, 0, TRAVELCOST_DOOR_OPEN_NE );
break;
default:
// door with no orientation specified!?
break;
}
}
else if (pStructure->fFlags & STRUCTURE_DDOOR_RIGHT && (pStructure->ubWallOrientation == INSIDE_TOP_LEFT || pStructure->ubWallOrientation == OUTSIDE_TOP_LEFT) )
{
// double door, right side (as you look on the screen)
switch( pStructure->ubWallOrientation )
{
case OUTSIDE_TOP_LEFT:
if (pStructure->fFlags & STRUCTURE_BASE_TILE)
{ // doorpost
SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_WALL );
SET_CURRMOVEMENTCOST( NORTH, TRAVELCOST_DOOR_CLOSED_HERE );
SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_DOOR_CLOSED_N )
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_WALL ); ;
// corner
SET_MOVEMENTCOST( usGridNo + 1 ,NORTHEAST, 0, TRAVELCOST_WALL );
}
else
{ // door
SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_DOOR_OPEN_N );
SET_CURRMOVEMENTCOST( WEST, TRAVELCOST_DOOR_OPEN_N );
SET_MOVEMENTCOST( usGridNo + 1, EAST, 0, TRAVELCOST_DOOR_OPEN_NW );
SET_MOVEMENTCOST( usGridNo + 1, NORTHEAST, 0, TRAVELCOST_DOOR_OPEN_NW );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_DOOR_OPEN_N_N );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_DOOR_OPEN_NW_N );
}
break;
case INSIDE_TOP_LEFT:
// doorpost
SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_WALL );
// corner
SET_MOVEMENTCOST( usGridNo + 1 ,NORTHEAST, 0, TRAVELCOST_WALL );
// door
SET_CURRMOVEMENTCOST( WEST, TRAVELCOST_DOOR_OPEN_HERE );
SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_DOOR_OPEN_HERE );
SET_MOVEMENTCOST( usGridNo + 1, EAST, 0, TRAVELCOST_DOOR_OPEN_W );
SET_MOVEMENTCOST( usGridNo + 1, SOUTHEAST, 0, TRAVELCOST_DOOR_OPEN_W );
SET_MOVEMENTCOST( usGridNo - WORLD_COLS, NORTHWEST, 0, TRAVELCOST_DOOR_OPEN_S );
SET_MOVEMENTCOST( usGridNo - WORLD_COLS + 1, NORTHEAST, 0, TRAVELCOST_DOOR_OPEN_SW );
break;
default:
// door with no orientation specified!?
break;
}
}
else if (pStructure->fFlags & STRUCTURE_SLIDINGDOOR && pStructure->pDBStructureRef->pDBStructure->ubNumberOfTiles > 1)
{
switch( pStructure->ubWallOrientation )
{
case OUTSIDE_TOP_LEFT:
case INSIDE_TOP_LEFT:
// doorframe post in one corner of each of the tiles
if (pStructure->fFlags & STRUCTURE_BASE_TILE)
{
SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_WALL );
SET_CURRMOVEMENTCOST( NORTH, TRAVELCOST_DOOR_CLOSED_HERE );
SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_DOOR_CLOSED_HERE );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_DOOR_CLOSED_N );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_DOOR_CLOSED_N );
}
else
{
SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_DOOR_CLOSED_HERE );
SET_CURRMOVEMENTCOST( NORTH, TRAVELCOST_DOOR_CLOSED_HERE );
SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_DOOR_CLOSED_N);
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_DOOR_CLOSED_N);
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_WALL );
}
break;
case OUTSIDE_TOP_RIGHT:
case INSIDE_TOP_RIGHT:
// doorframe post in one corner of each of the tiles
if (pStructure->fFlags & STRUCTURE_BASE_TILE)
{
SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_WALL );
SET_CURRMOVEMENTCOST( WEST, TRAVELCOST_DOOR_CLOSED_HERE );
SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_DOOR_CLOSED_HERE );
SET_MOVEMENTCOST( usGridNo + 1, NORTHEAST, 0, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + 1, EAST, 0, TRAVELCOST_DOOR_CLOSED_W );
SET_MOVEMENTCOST( usGridNo + 1, SOUTHEAST, 0, TRAVELCOST_DOOR_CLOSED_W );
}
else
{
SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_DOOR_CLOSED_HERE );
SET_CURRMOVEMENTCOST( WEST, TRAVELCOST_DOOR_CLOSED_HERE );
SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + 1, NORTHEAST, 0, TRAVELCOST_DOOR_CLOSED_W );
SET_MOVEMENTCOST( usGridNo + 1, EAST, 0, TRAVELCOST_DOOR_CLOSED_W );
SET_MOVEMENTCOST( usGridNo + 1, SOUTHEAST, 0, TRAVELCOST_WALL );
}
break;
}
}
else
{
// standard door
switch( pStructure->ubWallOrientation )
{
case OUTSIDE_TOP_LEFT:
if (pStructure->fFlags & STRUCTURE_BASE_TILE)
{ // doorframe
SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_WALL );
SET_CURRMOVEMENTCOST( NORTH, TRAVELCOST_DOOR_CLOSED_HERE );
SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_DOOR_CLOSED_N );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_WALL );
// DO CORNERS
SET_MOVEMENTCOST( usGridNo - 1, NORTHWEST, 0, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + 1, NORTHEAST, 0, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS - 1, SOUTHWEST, 0, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_WALL );
//SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_OBSTACLE );
//SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_OBSTACLE );
//SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_OBSTACLE );
//SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_OBSTACLE );
// corner
//SET_MOVEMENTCOST( usGridNo + 1 ,NORTHEAST, 0, TRAVELCOST_OBSTACLE );
}
else if (!(pStructure->fFlags & STRUCTURE_SLIDINGDOOR))
{ // door
SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_WALL );
SET_CURRMOVEMENTCOST( EAST, TRAVELCOST_DOOR_OPEN_N );
SET_MOVEMENTCOST( usGridNo - 1, WEST, 0, TRAVELCOST_DOOR_OPEN_NE );
SET_MOVEMENTCOST( usGridNo - 1, NORTHWEST, 0, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_DOOR_OPEN_N_N );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS - 1, SOUTHWEST, 0, TRAVELCOST_DOOR_OPEN_NE_N );
}
break;
case INSIDE_TOP_LEFT:
SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_WALL );
SET_CURRMOVEMENTCOST( NORTH, TRAVELCOST_DOOR_CLOSED_HERE );
SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_DOOR_CLOSED_N );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_OBSTACLE );
// DO CORNERS
SET_MOVEMENTCOST( usGridNo - 1, NORTHWEST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS - 1, SOUTHWEST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE );
// doorframe
//SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_OBSTACLE );
//SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_OBSTACLE );
//SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_OBSTACLE );
//SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_OBSTACLE );
// corner
//SET_MOVEMENTCOST( usGridNo + 1 ,NORTHEAST, 0, TRAVELCOST_OBSTACLE );
// door
if (!(pStructure->fFlags & STRUCTURE_SLIDINGDOOR))
{
SET_CURRMOVEMENTCOST( EAST, TRAVELCOST_DOOR_OPEN_HERE );
SET_CURRMOVEMENTCOST( SOUTHEAST, TRAVELCOST_DOOR_OPEN_HERE );
SET_MOVEMENTCOST( usGridNo - 1, WEST, 0, TRAVELCOST_DOOR_OPEN_E );
SET_MOVEMENTCOST( usGridNo - 1, SOUTHWEST, 0, TRAVELCOST_DOOR_OPEN_E );
SET_MOVEMENTCOST( usGridNo - WORLD_COLS, NORTHEAST, 0, TRAVELCOST_DOOR_OPEN_S );
SET_MOVEMENTCOST( usGridNo - WORLD_COLS - 1, NORTHWEST, 0, TRAVELCOST_DOOR_OPEN_SE );
}
break;
case OUTSIDE_TOP_RIGHT:
if (pStructure->fFlags & STRUCTURE_BASE_TILE)
{ // doorframe
SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_OBSTACLE );
SET_CURRMOVEMENTCOST( WEST, TRAVELCOST_DOOR_CLOSED_HERE );
SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + 1, EAST, 0, TRAVELCOST_DOOR_CLOSED_W );
SET_MOVEMENTCOST( usGridNo + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE );
// DO CORNERS
SET_MOVEMENTCOST( usGridNo - WORLD_COLS + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo - WORLD_COLS, NORTHWEST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_OBSTACLE );
//SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_OBSTACLE );
//SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_OBSTACLE );
//SET_MOVEMENTCOST( usGridNo + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE );
//SET_MOVEMENTCOST( usGridNo + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE );
// corner
//SET_MOVEMENTCOST( usGridNo + 1 + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_OBSTACLE );
}
else if (!(pStructure->fFlags & STRUCTURE_SLIDINGDOOR))
{ // door
SET_CURRMOVEMENTCOST( SOUTH, TRAVELCOST_DOOR_OPEN_W );
SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_DOOR_OPEN_W );
SET_MOVEMENTCOST( usGridNo - WORLD_COLS, NORTH, 0, TRAVELCOST_DOOR_OPEN_SW );
SET_MOVEMENTCOST( usGridNo - WORLD_COLS, NORTHWEST, 0, TRAVELCOST_DOOR_OPEN_SW );
SET_MOVEMENTCOST( usGridNo + 1, SOUTHEAST, 0, TRAVELCOST_DOOR_OPEN_W_W );
SET_MOVEMENTCOST( usGridNo - WORLD_COLS + 1, NORTHEAST, 0, TRAVELCOST_DOOR_OPEN_SW_W );
}
break;
case INSIDE_TOP_RIGHT:
SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_OBSTACLE );
SET_CURRMOVEMENTCOST( WEST, TRAVELCOST_DOOR_CLOSED_HERE );
SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + 1, EAST, 0, TRAVELCOST_DOOR_CLOSED_W );
SET_MOVEMENTCOST( usGridNo + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE );
// DO CORNERS
SET_MOVEMENTCOST( usGridNo - WORLD_COLS + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo - WORLD_COLS, NORTHWEST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_OBSTACLE );
// doorframe
/*
SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_OBSTACLE );
SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + 1,SOUTHEAST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + 1,NORTHEAST, 0, TRAVELCOST_OBSTACLE );
// corner
SET_MOVEMENTCOST( usGridNo - WORLD_COLS, NORTHWEST, 0, TRAVELCOST_OBSTACLE );
*/
if (!(pStructure->fFlags & STRUCTURE_SLIDINGDOOR))
{
// door
SET_CURRMOVEMENTCOST( SOUTH, TRAVELCOST_DOOR_OPEN_HERE );
SET_CURRMOVEMENTCOST( SOUTHEAST, TRAVELCOST_DOOR_OPEN_HERE );
SET_MOVEMENTCOST( usGridNo - WORLD_COLS, NORTH, 0, TRAVELCOST_DOOR_OPEN_S );
SET_MOVEMENTCOST( usGridNo - WORLD_COLS, NORTHEAST, 0, TRAVELCOST_DOOR_OPEN_S );
SET_MOVEMENTCOST( usGridNo - 1, SOUTHWEST, 0, TRAVELCOST_DOOR_OPEN_E );
SET_MOVEMENTCOST( usGridNo - WORLD_COLS - 1, NORTHWEST, 0, TRAVELCOST_DOOR_OPEN_SE );
}
break;
default:
// door with no orientation specified!?
break;
}
}
/*
switch( pStructure->ubWallOrientation )
{
case OUTSIDE_TOP_LEFT:
case INSIDE_TOP_LEFT:
SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_OBSTACLE );
SET_CURRMOVEMENTCOST( NORTH, TRAVELCOST_DOOR_CLOSED_HERE );
SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_DOOR_CLOSED_N );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_OBSTACLE );
// DO CORNERS
SET_MOVEMENTCOST( usGridNo - 1, NORTHWEST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS - 1, SOUTHWEST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE );
break;
case OUTSIDE_TOP_RIGHT:
case INSIDE_TOP_RIGHT:
SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_OBSTACLE );
SET_CURRMOVEMENTCOST( WEST, TRAVELCOST_DOOR_CLOSED_HERE );
SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + 1, EAST, 0, TRAVELCOST_DOOR_CLOSED_W );
SET_MOVEMENTCOST( usGridNo + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE );
// DO CORNERS
SET_MOVEMENTCOST( usGridNo - WORLD_COLS + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo - WORLD_COLS, NORTHWEST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_OBSTACLE );
break;
default:
// wall with no orientation specified!?
break;
}
*/
}
else if (pStructure->fFlags & STRUCTURE_WALLSTUFF )
{
//ATE: IF a closed door, set to door value
switch( pStructure->ubWallOrientation )
{
case OUTSIDE_TOP_LEFT:
case INSIDE_TOP_LEFT:
SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_WALL );
SET_CURRMOVEMENTCOST( NORTH, TRAVELCOST_WALL );
SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_WALL );
// DO CORNERS
SET_MOVEMENTCOST( usGridNo - 1, NORTHWEST, 0, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + 1, NORTHEAST, 0, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS - 1, SOUTHWEST, 0, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_WALL );
break;
case OUTSIDE_TOP_RIGHT:
case INSIDE_TOP_RIGHT:
SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_WALL );
SET_CURRMOVEMENTCOST( WEST, TRAVELCOST_WALL );
SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + 1, SOUTHEAST, 0, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + 1, EAST, 0, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + 1, NORTHEAST, 0, TRAVELCOST_WALL );
// DO CORNERS
SET_MOVEMENTCOST( usGridNo - WORLD_COLS + 1, NORTHEAST, 0, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo - WORLD_COLS, NORTHWEST, 0, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_WALL );
SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_WALL );
break;
default:
// wall with no orientation specified!?
break;
}
}
}
else
{
if (!(pStructure->fFlags & STRUCTURE_PASSABLE || pStructure->fFlags & STRUCTURE_NORMAL_ROOF))
{
// DNS: Try a fix to prevent people from "permanently" blocking the roof
if (!(pStructure->fFlags & STRUCTURE_PERSON))
{
fStructuresOnRoof = TRUE;
}
}
}
pStructure = pStructure->pNext;
} while (pStructure != NULL);
// HIGHEST LAYER
if ((gpWorldLevelData[ usGridNo ].pRoofHead != NULL))
{
if (!fStructuresOnRoof)
{
for (ubDirLoop=0; ubDirLoop < 8; ubDirLoop++)
{
SET_MOVEMENTCOST( usGridNo, ubDirLoop, 1, TRAVELCOST_FLAT );
}
}
else
{
for (ubDirLoop=0; ubDirLoop < 8; ubDirLoop++)
{
SET_MOVEMENTCOST( usGridNo, ubDirLoop, 1, TRAVELCOST_OBSTACLE );
}
}
}
else
{
for (ubDirLoop=0; ubDirLoop < 8; ubDirLoop++)
{
SET_MOVEMENTCOST( usGridNo, ubDirLoop, 1, TRAVELCOST_OBSTACLE );
}
}
}
else
{ // NO STRUCTURES IN TILE
// consider just the land
// Get terrain type
ubTerrainID = gpWorldLevelData[usGridNo].ubTerrainID; // = GetTerrainType( (INT16)usGridNo );
for (ubDirLoop=0; ubDirLoop < 8; ubDirLoop++)
{
SET_MOVEMENTCOST( usGridNo ,ubDirLoop, 0, gTileTypeMovementCost[ ubTerrainID ] );
}
/*
pLand = gpWorldLevelData[ usGridNo ].pLandHead;
if ( pLand != NULL )
{
// Set cost here
// Get from tile database
TileElem = gTileDatabase[ pLand->usIndex ];
// Get terrain type
ubTerrainID = GetTerrainType( (INT16)usGridNo );
for (ubDirLoop=0; ubDirLoop < 8; ubDirLoop++)
{
SET_MOVEMENTCOST( usGridNo ,ubDirLoop, 0, gTileTypeMovementCost[ ubTerrainID ] );
}
}
*/
// HIGHEST LEVEL
if (gpWorldLevelData[ usGridNo ].pRoofHead != NULL)
{
for (ubDirLoop=0; ubDirLoop < 8; ubDirLoop++)
{
SET_MOVEMENTCOST( usGridNo, ubDirLoop, 1, TRAVELCOST_FLAT );
}
}
else
{
for (ubDirLoop=0; ubDirLoop < 8; ubDirLoop++)
{
SET_MOVEMENTCOST( usGridNo, ubDirLoop, 1, TRAVELCOST_OBSTACLE );
}
}
}
}
#define LOCAL_RADIUS 4
void RecompileLocalMovementCosts( INT16 sCentreGridNo )
{
INT16 usGridNo;
INT16 sGridX, sGridY;
INT16 sCentreGridX, sCentreGridY;
INT8 bDirLoop;
ConvertGridNoToXY( sCentreGridNo, &sCentreGridX, &sCentreGridY );
for( sGridY = sCentreGridY - LOCAL_RADIUS; sGridY < sCentreGridY + LOCAL_RADIUS; sGridY++ )
{
for( sGridX = sCentreGridX - LOCAL_RADIUS; sGridX < sCentreGridX + LOCAL_RADIUS; sGridX++ )
{
usGridNo = MAPROWCOLTOPOS( sGridY, sGridX );
// times 2 for 2 levels, times 2 for UINT16s
// memset( &(gubWorldMovementCosts[usGridNo]), 0, MAXDIR * 2 * 2 );
if (usGridNo < WORLD_MAX)
{
for( bDirLoop = 0; bDirLoop < MAXDIR; bDirLoop++)
{
gubWorldMovementCosts[usGridNo][bDirLoop][0] = 0;
gubWorldMovementCosts[usGridNo][bDirLoop][1] = 0;
}
}
}
}
// note the radius used in this loop is larger, to guarantee that the
// edges of the recompiled areas are correct (i.e. there could be spillover)
for( sGridY = sCentreGridY - LOCAL_RADIUS - 1; sGridY < sCentreGridY + LOCAL_RADIUS + 1; sGridY++ )
{
for( sGridX = sCentreGridX - LOCAL_RADIUS - 1; sGridX < sCentreGridX + LOCAL_RADIUS + 1; sGridX++ )
{
usGridNo = MAPROWCOLTOPOS( sGridY, sGridX );
if (usGridNo < WORLD_MAX)
{
CompileTileMovementCosts( usGridNo );
}
}
}
}
void RecompileLocalMovementCostsFromRadius( INT16 sCentreGridNo, INT8 bRadius )
{
INT16 usGridNo;
INT16 sGridX, sGridY;
INT16 sCentreGridX, sCentreGridY;
INT8 bDirLoop;
ConvertGridNoToXY( sCentreGridNo, &sCentreGridX, &sCentreGridY );
if (bRadius == 0)
{
// one tile check only
for( bDirLoop = 0; bDirLoop < MAXDIR; bDirLoop++)
{
gubWorldMovementCosts[sCentreGridNo][bDirLoop][0] = 0;
gubWorldMovementCosts[sCentreGridNo][bDirLoop][1] = 0;
}
CompileTileMovementCosts( sCentreGridNo );
}
else
{
for( sGridY = sCentreGridY - bRadius; sGridY < sCentreGridY + bRadius; sGridY++ )
{
for( sGridX = sCentreGridX - bRadius; sGridX < sCentreGridX + bRadius; sGridX++ )
{
usGridNo = MAPROWCOLTOPOS( sGridY, sGridX );
// times 2 for 2 levels, times 2 for UINT16s
// memset( &(gubWorldMovementCosts[usGridNo]), 0, MAXDIR * 2 * 2 );
if (usGridNo < WORLD_MAX)
{
for( bDirLoop = 0; bDirLoop < MAXDIR; bDirLoop++)
{
gubWorldMovementCosts[usGridNo][bDirLoop][0] = 0;
gubWorldMovementCosts[usGridNo][bDirLoop][1] = 0;
}
}
}
}
// note the radius used in this loop is larger, to guarantee that the
// edges of the recompiled areas are correct (i.e. there could be spillover)
for( sGridY = sCentreGridY - bRadius - 1; sGridY < sCentreGridY + bRadius + 1; sGridY++ )
{
for( sGridX = sCentreGridX - bRadius - 1; sGridX < sCentreGridX + bRadius + 1; sGridX++ )
{
usGridNo = MAPROWCOLTOPOS( sGridY, sGridX );
if (usGridNo < WORLD_MAX)
{
CompileTileMovementCosts( usGridNo );
}
}
}
}
}
void AddTileToRecompileArea( INT16 sGridNo )
{
INT16 sCheckGridNo;
INT16 sCheckX;
INT16 sCheckY;
// Set flag to wipe and recompile MPs in this tile
if (sGridNo < 0 || sGridNo >= WORLD_MAX)
{
return;
}
gpWorldLevelData[ sGridNo ].ubExtFlags[0] |= MAPELEMENT_EXT_RECALCULATE_MOVEMENT;
// check Top/Left of recompile region
sCheckGridNo = NewGridNo( sGridNo, DirectionInc( NORTHWEST ) );
sCheckX = sCheckGridNo % WORLD_COLS;
sCheckY = sCheckGridNo / WORLD_COLS;
if ( sCheckX < gsRecompileAreaLeft )
{
gsRecompileAreaLeft = sCheckX;
}
if ( sCheckY < gsRecompileAreaTop )
{
gsRecompileAreaTop = sCheckY;
}
// check Bottom/Right
sCheckGridNo = NewGridNo( sGridNo, DirectionInc( SOUTHEAST ) );
sCheckX = sCheckGridNo % WORLD_COLS;
sCheckY = sCheckGridNo / WORLD_COLS;
if ( sCheckX > gsRecompileAreaRight )
{
gsRecompileAreaRight = sCheckX;
}
if ( sCheckY > gsRecompileAreaBottom )
{
gsRecompileAreaBottom = sCheckY;
}
}
void RecompileLocalMovementCostsInAreaWithFlags( void )
{
INT16 usGridNo;
INT16 sGridX, sGridY;
INT8 bDirLoop;
for( sGridY = gsRecompileAreaTop; sGridY <= gsRecompileAreaBottom; sGridY++ )
{
for( sGridX = gsRecompileAreaLeft; sGridX < gsRecompileAreaRight; sGridX++ )
{
usGridNo = MAPROWCOLTOPOS( sGridY, sGridX );
if ( usGridNo < WORLD_MAX && gpWorldLevelData[ usGridNo ].ubExtFlags[0] & MAPELEMENT_EXT_RECALCULATE_MOVEMENT )
{
// wipe MPs in this tile!
for( bDirLoop = 0; bDirLoop < MAXDIR; bDirLoop++)
{
gubWorldMovementCosts[usGridNo][bDirLoop][0] = 0;
gubWorldMovementCosts[usGridNo][bDirLoop][1] = 0;
}
// reset flag
gpWorldLevelData[ usGridNo ].ubExtFlags[0] &= (~MAPELEMENT_EXT_RECALCULATE_MOVEMENT);
}
}
}
for( sGridY = gsRecompileAreaTop; sGridY <= gsRecompileAreaBottom; sGridY++ )
{
for( sGridX = gsRecompileAreaLeft; sGridX <= gsRecompileAreaRight; sGridX++ )
{
usGridNo = MAPROWCOLTOPOS( sGridY, sGridX );
if (usGridNo < WORLD_MAX)
{
CompileTileMovementCosts( usGridNo );
}
}
}
}
void RecompileLocalMovementCostsForWall( INT16 sGridNo, UINT8 ubOrientation )
{
INT8 bDirLoop;
INT16 sUp, sDown, sLeft, sRight;
INT16 sX, sY, sTempGridNo;
switch( ubOrientation )
{
case OUTSIDE_TOP_RIGHT:
case INSIDE_TOP_RIGHT:
sUp = -1;
sDown = 1;
sLeft = 0;
sRight = 1;
break;
case OUTSIDE_TOP_LEFT:
case INSIDE_TOP_LEFT:
sUp = 0;
sDown = 1;
sLeft = -1;
sRight = 1;
break;
default:
return;
}
for ( sY = sUp; sY <= sDown; sY++ )
{
for ( sX = sLeft; sX <= sRight; sX++ )
{
sTempGridNo = sGridNo + sX + sY * WORLD_COLS;
for( bDirLoop = 0; bDirLoop < MAXDIR; bDirLoop++)
{
gubWorldMovementCosts[sTempGridNo][bDirLoop][0] = 0;
gubWorldMovementCosts[sTempGridNo][bDirLoop][1] = 0;
}
CompileTileMovementCosts( sTempGridNo );
}
}
}
// GLOBAL WORLD MANIPULATION FUNCTIONS
void CompileWorldMovementCosts( )
{
UINT16 usGridNo;
memset( gubWorldMovementCosts, 0, sizeof( gubWorldMovementCosts ) );
CompileWorldTerrainIDs();
for( usGridNo = 0; usGridNo < WORLD_MAX; usGridNo++ )
{
CompileTileMovementCosts( usGridNo );
}
}
// SAVING CODE
BOOLEAN SaveWorld( const STR8 puiFilename )
{
#ifdef JA2EDITOR
INT32 cnt;
UINT32 uiSoldierSize;
UINT32 uiType;
UINT32 uiFlags;
UINT32 uiBytesWritten;
UINT32 uiNumWarningsCaught = 0;
HWFILE hfile;
LEVELNODE *pLand;
LEVELNODE *pObject;
LEVELNODE *pStruct;
LEVELNODE *pShadow;
LEVELNODE *pRoof;
LEVELNODE *pOnRoof;
LEVELNODE *pTailLand=NULL;
UINT16 usNumExitGrids = 0;
UINT16 usTypeSubIndex;
UINT8 LayerCount;
UINT8 ObjectCount;
UINT8 StructCount;
UINT8 ShadowCount;
UINT8 RoofCount;
UINT8 OnRoofCount;
UINT8 ubType;
UINT8 ubTypeSubIndex;
UINT8 ubTest = 1;
CHAR8 aFilename[ 255 ];
UINT8 ubCombine;
UINT8 bCounts[ WORLD_MAX ][8];
sprintf( aFilename, "MAPS\\%s", puiFilename );
// Open file
hfile = FileOpen( aFilename, FILE_ACCESS_WRITE | FILE_CREATE_ALWAYS, FALSE );
if ( !hfile )
{
return( FALSE );
}
// Write JA2 Version ID
FileWrite( hfile, &gdMajorMapVersion, sizeof( FLOAT ), &uiBytesWritten );
if( gdMajorMapVersion >= 4.00 )
{
FileWrite( hfile, &gubMinorMapVersion, sizeof( UINT8 ), &uiBytesWritten );
}
// Write FLAGS FOR WORLD
//uiFlags = MAP_WORLDONLY_SAVED;
uiFlags = 0;
uiFlags |= MAP_FULLSOLDIER_SAVED;
uiFlags |= MAP_EXITGRIDS_SAVED;
uiFlags |= MAP_WORLDLIGHTS_SAVED;
uiFlags |= MAP_DOORTABLE_SAVED;
uiFlags |= MAP_WORLDITEMS_SAVED;
uiFlags |= MAP_EDGEPOINTS_SAVED;
if( gfBasement || gfCaves )
uiFlags |= MAP_AMBIENTLIGHTLEVEL_SAVED;
uiFlags |= MAP_NPCSCHEDULES_SAVED;
FileWrite( hfile, &uiFlags, sizeof( INT32 ), &uiBytesWritten );
// Write tileset ID
FileWrite( hfile, &giCurrentTilesetID, sizeof( INT32 ), &uiBytesWritten );
// Write SOLDIER CONTROL SIZE
uiSoldierSize = sizeof( SOLDIERTYPE );
FileWrite( hfile, &uiSoldierSize, sizeof( INT32 ), &uiBytesWritten );
// REMOVE WORLD VISIBILITY TILES
RemoveWorldWireFrameTiles( );
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
// Write out height values
FileWrite( hfile, &gpWorldLevelData[ cnt ].sHeight, sizeof( INT16 ), &uiBytesWritten );
}
// Write out # values - we'll have no more than 15 per level!
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
// Determine number of land
pLand = gpWorldLevelData[ cnt ].pLandHead;
LayerCount = 0;
while( pLand != NULL )
{
LayerCount++;
pLand = pLand->pNext;
}
if( LayerCount > 15 )
{
swprintf( gzErrorCatchString, L"SAVE ABORTED! Land count too high (%d) for gridno %d."
L" Need to fix before map can be saved! There are %d additional warnings.",
LayerCount, cnt, uiNumWarningsCaught );
gfErrorCatch = TRUE;
FileClose( hfile );
return FALSE;
}
if( LayerCount > 10 )
{
uiNumWarningsCaught++;
gfErrorCatch = TRUE;
swprintf( gzErrorCatchString, L"Warnings %d -- Last warning: Land count warning of %d for gridno %d.",
uiNumWarningsCaught, LayerCount, cnt );
}
bCounts[ cnt ][ 0 ] = LayerCount;
// Combine # of land layers with worlddef flags ( first 4 bits )
ubCombine = (UINT8)( ( LayerCount&0xf ) | ( (gpWorldLevelData[ cnt ].uiFlags&0xf)<<4 ) );
// Write combination
FileWrite( hfile, &ubCombine, sizeof( ubCombine ), &uiBytesWritten );
// Determine # of objects
pObject = gpWorldLevelData[ cnt ].pObjectHead;
ObjectCount = 0;
while( pObject != NULL )
{
// DON'T WRITE ANY ITEMS
if ( !(pObject->uiFlags & ( LEVELNODE_ITEM ) ) )
{
UINT32 uiTileType;
//Make sure this isn't a UI Element
GetTileType( pObject->usIndex, &uiTileType );
if( uiTileType < FIRSTPOINTERS )
ObjectCount++;
}
pObject = pObject->pNext;
}
if( ObjectCount > 15 )
{
swprintf( gzErrorCatchString, L"SAVE ABORTED! Object count too high (%d) for gridno %d."
L" Need to fix before map can be saved! There are %d additional warnings.",
ObjectCount, cnt, uiNumWarningsCaught );
gfErrorCatch = TRUE;
FileClose( hfile );
return FALSE;
}
if( ObjectCount > 10 )
{
uiNumWarningsCaught++;
gfErrorCatch = TRUE;
swprintf( gzErrorCatchString, L"Warnings %d -- Last warning: Object count warning of %d for gridno %d.",
uiNumWarningsCaught, ObjectCount, cnt );
}
bCounts[ cnt ][ 1 ] = ObjectCount;
// Determine # of structs
pStruct = gpWorldLevelData[ cnt ].pStructHead;
StructCount = 0;
while( pStruct != NULL )
{
// DON'T WRITE ANY ITEMS
if ( !(pStruct->uiFlags & ( LEVELNODE_ITEM ) ) )
{
StructCount++;
}
pStruct = pStruct->pNext;
}
if( StructCount > 15 )
{
swprintf( gzErrorCatchString, L"SAVE ABORTED! Struct count too high (%d) for gridno %d."
L" Need to fix before map can be saved! There are %d additional warnings.",
StructCount, cnt, uiNumWarningsCaught );
gfErrorCatch = TRUE;
FileClose( hfile );
return FALSE;
}
if( StructCount > 10 )
{
uiNumWarningsCaught++;
gfErrorCatch = TRUE;
swprintf( gzErrorCatchString, L"Warnings %d -- Last warning: Struct count warning of %d for gridno %d.",
uiNumWarningsCaught, StructCount, cnt );
}
bCounts[ cnt ][ 2 ] = StructCount;
ubCombine = (UINT8)( ( ObjectCount&0xf ) | ( (StructCount&0xf)<<4 ) );
// Write combination
FileWrite( hfile, &ubCombine, sizeof( ubCombine ), &uiBytesWritten );
// Determine # of shadows
pShadow = gpWorldLevelData[ cnt ].pShadowHead;
ShadowCount = 0;
while( pShadow != NULL )
{
// Don't write any shadowbuddys or exit grids
if ( !(pShadow->uiFlags & ( LEVELNODE_BUDDYSHADOW | LEVELNODE_EXITGRID ) ) )
{
ShadowCount++;
}
pShadow = pShadow->pNext;
}
if( ShadowCount > 15 )
{
swprintf( gzErrorCatchString, L"SAVE ABORTED! Shadow count too high (%d) for gridno %d."
L" Need to fix before map can be saved! There are %d additional warnings.",
ShadowCount, cnt, uiNumWarningsCaught );
gfErrorCatch = TRUE;
FileClose( hfile );
return FALSE;
}
if( ShadowCount > 10 )
{
uiNumWarningsCaught++;
gfErrorCatch = TRUE;
swprintf( gzErrorCatchString, L"Warnings %d -- Last warning: Shadow count warning of %d for gridno %d.",
uiNumWarningsCaught, ShadowCount, cnt );
}
bCounts[ cnt ][ 3 ] = ShadowCount;
// Determine # of Roofs
pRoof = gpWorldLevelData[ cnt ].pRoofHead;
RoofCount = 0;
while( pRoof != NULL )
{
// ATE: Don't save revealed roof info...
if ( pRoof->usIndex != SLANTROOFCEILING1 )
{
RoofCount++;
}
pRoof = pRoof->pNext;
}
if( RoofCount > 15 )
{
swprintf( gzErrorCatchString, L"SAVE ABORTED! Roof count too high (%d) for gridno %d."
L" Need to fix before map can be saved! There are %d additional warnings.",
RoofCount, cnt, uiNumWarningsCaught );
gfErrorCatch = TRUE;
FileClose( hfile );
return FALSE;
}
if( RoofCount > 10 )
{
uiNumWarningsCaught++;
gfErrorCatch = TRUE;
swprintf( gzErrorCatchString, L"Warnings %d -- Last warning: Roof count warning of %d for gridno %d.",
uiNumWarningsCaught, RoofCount, cnt );
}
bCounts[ cnt ][ 4 ] = RoofCount;
ubCombine = (UINT8)( ( ShadowCount&0xf ) | ( (RoofCount&0xf)<<4 ) );
// Write combination
FileWrite( hfile, &ubCombine, sizeof( ubCombine ), &uiBytesWritten );
// Write OnRoof layer
// Determine # of OnRoofs
pOnRoof = gpWorldLevelData[ cnt ].pOnRoofHead;
OnRoofCount = 0;
while( pOnRoof != NULL )
{
OnRoofCount++;
pOnRoof = pOnRoof->pNext;
}
if( OnRoofCount > 15 )
{
swprintf( gzErrorCatchString, L"SAVE ABORTED! OnRoof count too high (%d) for gridno %d."
L" Need to fix before map can be saved! There are %d additional warnings.",
OnRoofCount, cnt, uiNumWarningsCaught );
gfErrorCatch = TRUE;
FileClose( hfile );
return FALSE;
}
if( OnRoofCount > 10 )
{
uiNumWarningsCaught++;
gfErrorCatch = TRUE;
swprintf( gzErrorCatchString, L"Warnings %d -- Last warning: OnRoof count warning of %d for gridno %d.",
uiNumWarningsCaught, OnRoofCount, cnt );
}
bCounts[ cnt ][ 5 ] = RoofCount;
// Write combination of onroof and nothing...
ubCombine = (UINT8)( ( OnRoofCount&0xf ) );
// Write combination
FileWrite( hfile, &ubCombine, sizeof( ubCombine ), &uiBytesWritten );
}
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
if ( bCounts[ cnt ][ 0 ] == 0 )
{
FileWrite( hfile, &ubTest, sizeof( UINT8 ), &uiBytesWritten );
FileWrite( hfile, &ubTest, sizeof( UINT8 ), &uiBytesWritten );
}
else
{
// Write land layers
// Write out land peices backwards so that they are loaded properly
pLand = gpWorldLevelData[ cnt ].pLandHead;
// GET TAIL
while( pLand != NULL )
{
pTailLand = pLand;
pLand = pLand->pNext;
}
while( pTailLand != NULL )
{
// Write out object type and sub-index
GetTileType( pTailLand->usIndex, &uiType );
ubType = (UINT8)uiType;
GetTypeSubIndexFromTileIndexChar( uiType, pTailLand->usIndex, &ubTypeSubIndex );
FileWrite( hfile, &ubType, sizeof( UINT8 ), &uiBytesWritten );
FileWrite( hfile, &ubTypeSubIndex, sizeof( UINT8 ), &uiBytesWritten );
pTailLand = pTailLand->pPrevNode;
}
}
}
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
// Write object layer
pObject = gpWorldLevelData[ cnt ].pObjectHead;
while( pObject != NULL )
{
// DON'T WRITE ANY ITEMS
if ( !(pObject->uiFlags & ( LEVELNODE_ITEM ) ) )
{
// Write out object type and sub-index
GetTileType( pObject->usIndex, &uiType );
//Make sure this isn't a UI Element
if( uiType < FIRSTPOINTERS )
{
//We are writing 2 bytes for the type subindex in the object layer because the
//ROADPIECES slot contains more than 256 subindices.
ubType = (UINT8)uiType;
GetTypeSubIndexFromTileIndex( uiType, pObject->usIndex, &usTypeSubIndex );
FileWrite( hfile, &ubType, sizeof( UINT8 ), &uiBytesWritten );
FileWrite( hfile, &usTypeSubIndex, sizeof( UINT16 ), &uiBytesWritten );
}
}
pObject = pObject->pNext;
}
}
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
// Write struct layer
pStruct = gpWorldLevelData[ cnt ].pStructHead;
while( pStruct != NULL )
{
// DON'T WRITE ANY ITEMS
if ( !(pStruct->uiFlags & ( LEVELNODE_ITEM ) ) )
{
// Write out object type and sub-index
GetTileType( pStruct->usIndex, &uiType );
ubType = (UINT8)uiType;
GetTypeSubIndexFromTileIndexChar( uiType, pStruct->usIndex, &ubTypeSubIndex );
FileWrite( hfile, &ubType, sizeof( UINT8 ), &uiBytesWritten );
FileWrite( hfile, &ubTypeSubIndex, sizeof( UINT8 ), &uiBytesWritten );
}
pStruct = pStruct->pNext;
}
}
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
// Write shadows
pShadow = gpWorldLevelData[ cnt ].pShadowHead;
while( pShadow != NULL )
{
// Dont't write any buddys or exit grids
if ( !(pShadow->uiFlags & ( LEVELNODE_BUDDYSHADOW | LEVELNODE_EXITGRID ) ) )
{
// Write out object type and sub-index
// Write out object type and sub-index
GetTileType( pShadow->usIndex, &uiType );
ubType = (UINT8)uiType;
GetTypeSubIndexFromTileIndexChar( uiType, pShadow->usIndex, &ubTypeSubIndex );
FileWrite( hfile, &ubType, sizeof( UINT8 ), &uiBytesWritten );
FileWrite( hfile, &ubTypeSubIndex, sizeof( UINT8 ), &uiBytesWritten );
}
else if( pShadow->uiFlags & LEVELNODE_EXITGRID )
{ //count the number of exitgrids
usNumExitGrids++;
}
pShadow = pShadow->pNext;
}
}
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
pRoof = gpWorldLevelData[ cnt ].pRoofHead;
while( pRoof != NULL )
{
// ATE: Don't save revealed roof info...
if ( pRoof->usIndex != SLANTROOFCEILING1 )
{
// Write out object type and sub-index
GetTileType( pRoof->usIndex, &uiType );
ubType = (UINT8)uiType;
GetTypeSubIndexFromTileIndexChar( uiType, pRoof->usIndex, &ubTypeSubIndex );
FileWrite( hfile, &ubType, sizeof( UINT8 ), &uiBytesWritten );
FileWrite( hfile, &ubTypeSubIndex, sizeof( UINT8 ), &uiBytesWritten );
}
pRoof = pRoof->pNext;
}
}
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
// Write OnRoofs
pOnRoof = gpWorldLevelData[ cnt ].pOnRoofHead;
while( pOnRoof != NULL )
{
// Write out object type and sub-index
GetTileType( pOnRoof->usIndex, &uiType );
ubType = (UINT8)uiType;
GetTypeSubIndexFromTileIndexChar( uiType, pOnRoof->usIndex, &ubTypeSubIndex );
FileWrite( hfile, &ubType, sizeof( UINT8 ), &uiBytesWritten );
FileWrite( hfile, &ubTypeSubIndex, sizeof( UINT8 ), &uiBytesWritten );
pOnRoof = pOnRoof->pNext;
}
}
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
// Write out room information
FileWrite( hfile, &gubWorldRoomInfo[ cnt ], sizeof( INT8 ), &uiBytesWritten );
}
if ( uiFlags & MAP_WORLDITEMS_SAVED )
{
// Write out item information
SaveWorldItemsToMap( hfile );
}
if( uiFlags & MAP_AMBIENTLIGHTLEVEL_SAVED )
{
FileWrite( hfile, &gfBasement, 1, &uiBytesWritten );
FileWrite( hfile, &gfCaves, 1, &uiBytesWritten );
FileWrite( hfile, &ubAmbientLightLevel, 1, &uiBytesWritten );
}
if( uiFlags & MAP_WORLDLIGHTS_SAVED )
{
SaveMapLights( hfile );
}
SaveMapInformation( hfile );
if( uiFlags & MAP_FULLSOLDIER_SAVED )
{
SaveSoldiersToMap( hfile );
}
if( uiFlags & MAP_EXITGRIDS_SAVED )
{
SaveExitGrids( hfile, usNumExitGrids );
}
if( uiFlags & MAP_DOORTABLE_SAVED )
{
SaveDoorTableToMap( hfile );
}
if( uiFlags & MAP_EDGEPOINTS_SAVED )
{
CompileWorldMovementCosts();
GenerateMapEdgepoints();
SaveMapEdgepoints( hfile );
}
if( uiFlags & MAP_NPCSCHEDULES_SAVED )
{
SaveSchedules( hfile );
}
FileClose( hfile );
sprintf( gubFilename, puiFilename );
#endif //JA2EDITOR
return( TRUE );
}
#define NUM_DIR_SEARCHES 5
INT8 bDirectionsForShadowSearch[ NUM_DIR_SEARCHES ] =
{
WEST,
SOUTHWEST,
SOUTH,
SOUTHEAST,
EAST
};
void OptimizeMapForShadows( )
{
INT32 cnt, dir;
INT16 sNewGridNo;
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
// CHECK IF WE ARE A TREE HERE
if ( IsTreePresentAtGridno( (INT16)cnt ) )
{
// CHECK FOR A STRUCTURE A FOOTPRINT AWAY
for ( dir = 0; dir < NUM_DIR_SEARCHES; dir++ )
{
sNewGridNo = NewGridNo( (INT16)cnt, (UINT16)DirectionInc( bDirectionsForShadowSearch[ dir ] ) );
if ( gpWorldLevelData[ sNewGridNo ].pStructureHead == NULL )
{
break;
}
}
// If we made it here, remove shadow!
// We're full of structures
if ( dir == NUM_DIR_SEARCHES )
{
RemoveAllShadows( cnt );
// Display message to effect
}
}
}
}
void SetBlueFlagFlags( void )
{
INT32 cnt;
LEVELNODE * pNode;
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
pNode = gpWorldLevelData[ cnt ].pStructHead;
while ( pNode )
{
if ( pNode->usIndex == BLUEFLAG_GRAPHIC)
{
gpWorldLevelData[ cnt ].uiFlags |= MAPELEMENT_PLAYER_MINE_PRESENT;
break;
}
pNode = pNode->pNext;
}
}
}
void InitLoadedWorld( )
{
//if the current sector is not valid, dont init the world
if( gWorldSectorX == 0 || gWorldSectorY == 0 )
{
return;
}
// COMPILE MOVEMENT COSTS
CompileWorldMovementCosts( );
// COMPILE INTERACTIVE TILES
CompileInteractiveTiles( );
// COMPILE WORLD VISIBLIY TILES
CalculateWorldWireFrameTiles( TRUE );
LightSpriteRenderAll();
OptimizeMapForShadows( );
SetInterfaceHeightLevel( );
// ATE: if we have a slide location, remove it!
gTacticalStatus.sSlideTarget = NOWHERE;
SetBlueFlagFlags();
}
#ifdef JA2EDITOR
//This is a specialty function that is very similar to LoadWorld, except that it
//doesn't actually load the world, it instead evaluates the map and generates summary
//information for use within the summary editor. The header is defined in Summary Info.h,
//not worlddef.h -- though it's not likely this is going to be used anywhere where it would
//matter.
extern double MasterStart, MasterEnd;
extern BOOLEAN gfUpdatingNow;
BOOLEAN EvaluateWorld( STR8 pSector, UINT8 ubLevel )
{
FLOAT dMajorMapVersion;
SUMMARYFILE *pSummary;
HWFILE hfile;
MAPCREATE_STRUCT mapInfo;
INT8 *pBuffer, *pBufferHead;
UINT32 uiFileSize;
UINT32 uiFlags;
UINT32 uiBytesRead;
INT32 cnt;
INT32 i;
INT32 iTilesetID;
CHAR16 str[40];
UINT8 bCounts[ WORLD_MAX ][8];
UINT8 ubCombine;
CHAR8 szDirFilename[ 50 ];
CHAR8 szFilename[ 40 ];
UINT8 ubMinorMapVersion;
//Make sure the file exists... if not, then return false
sprintf( szFilename, pSector );
if( ubLevel % 4 )
{
CHAR8 str[4];
sprintf( str, "_b%d", ubLevel % 4 );
strcat( szFilename, str );
}
if( ubLevel >= 4 )
{
strcat( szFilename, "_a" );
}
strcat( szFilename, ".dat" );
sprintf( szDirFilename, "MAPS\\%s", szFilename );
if( gfMajorUpdate )
{
if( !LoadWorld( szFilename ) ) //error
return FALSE;
FileClearAttributes( szDirFilename );
SaveWorld( szFilename );
}
hfile = FileOpen( szDirFilename, FILE_ACCESS_READ, FALSE );
if( !hfile )
return FALSE;
uiFileSize = FileGetSize( hfile );
pBuffer = (INT8*)MemAlloc( uiFileSize );
pBufferHead = pBuffer;
FileRead( hfile, pBuffer, uiFileSize, &uiBytesRead );
FileClose( hfile );
swprintf( str, L"Analyzing map %S", szFilename );
if( !gfUpdatingNow )
SetRelativeStartAndEndPercentage( 0, 0, 100, str );
else
SetRelativeStartAndEndPercentage( 0, (UINT16)MasterStart, (UINT16)MasterEnd, str );
RenderProgressBar( 0, 0 );
//RenderProgressBar( 1, 0 );
//clear the summary file info
pSummary = (SUMMARYFILE*)MemAlloc( sizeof( SUMMARYFILE ) );
Assert( pSummary );
memset( pSummary, 0, sizeof( SUMMARYFILE ) );
pSummary->ubSummaryVersion = GLOBAL_SUMMARY_VERSION;
pSummary->dMajorMapVersion = gdMajorMapVersion;
//skip JA2 Version ID
LOADDATA( &dMajorMapVersion, pBuffer, sizeof( FLOAT ) );
if( dMajorMapVersion >= 4.00 )
{
LOADDATA( &ubMinorMapVersion, pBuffer, sizeof( UINT8 ) );
}
//Read FLAGS FOR WORLD
LOADDATA( &uiFlags, pBuffer, sizeof( INT32 ) );
//Read tilesetID
LOADDATA( &iTilesetID, pBuffer, sizeof( INT32 ) );
pSummary->ubTilesetID = (UINT8)iTilesetID;
//skip soldier size
pBuffer += sizeof( INT32 );
//skip height values
pBuffer += sizeof( INT16 ) * WORLD_MAX;
//read layer counts
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
if( !( cnt % 2560 ) )
{
RenderProgressBar( 0, (cnt / 2560)+1 ); //1 - 10
//RenderProgressBar( 1, (cnt / 2560)+1 ); //1 - 10
}
// Read combination of land/world flags
LOADDATA( &ubCombine, pBuffer, sizeof( UINT8 ) );
// split
bCounts[ cnt ][0] = (UINT8)(ubCombine&0xf);
gpWorldLevelData[ cnt ].uiFlags |= (UINT8)((ubCombine&0xf0)>>4);
// Read #objects, structs
LOADDATA( &ubCombine, pBuffer, sizeof( UINT8 ) );
// split
bCounts[ cnt ][1] = (UINT8)(ubCombine&0xf);
bCounts[ cnt ][2] = (UINT8)((ubCombine&0xf0)>>4);
// Read shadows, roof
LOADDATA( &ubCombine, pBuffer, sizeof( UINT8 ) );
// split
bCounts[ cnt ][3] = (UINT8)(ubCombine&0xf);
bCounts[ cnt ][4] = (UINT8)((ubCombine&0xf0)>>4);
// Read OnRoof, nothing
LOADDATA( &ubCombine, pBuffer, sizeof( UINT8 ) );
// split
bCounts[ cnt ][5] = (UINT8)(ubCombine&0xf);
//bCounts[ cnt ][4] = (UINT8)((ubCombine&0xf0)>>4);
bCounts[ cnt ][6] = bCounts[cnt][0] + bCounts[cnt][1] +
bCounts[cnt][2] + bCounts[cnt][3] +
bCounts[cnt][4] + bCounts[cnt][5];
}
//skip all layers
for( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
if( !( cnt % 320 ) )
{
RenderProgressBar( 0, (cnt / 320)+11 ); //11 - 90
//RenderProgressBar( 1, (cnt / 320)+11 ); //11 - 90
}
pBuffer += sizeof( UINT16 ) * bCounts[cnt][6];
pBuffer += bCounts[cnt][1];
}
//extract highest room number
{
UINT8 ubRoomNum;
for( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
LOADDATA( &ubRoomNum, pBuffer, 1 );
if( ubRoomNum > pSummary->ubNumRooms )
{
pSummary->ubNumRooms = ubRoomNum;
}
}
}
if( uiFlags & MAP_WORLDITEMS_SAVED )
{
UINT32 temp;
RenderProgressBar( 0, 91 );
//RenderProgressBar( 1, 91 );
//get number of items (for now)
LOADDATA( &temp, pBuffer, 4 );
pSummary->usNumItems = (UINT16)temp;
//Important: Saves the file position (byte offset) of the position where the numitems
// resides. Checking this value and comparing to usNumItems will ensure validity.
if( pSummary->usNumItems )
{
pSummary->uiNumItemsPosition = pBuffer - pBufferHead - 4;
}
//Skip the contents of the world items.
pBuffer += sizeof( WORLDITEM ) * pSummary->usNumItems;
}
if( uiFlags & MAP_AMBIENTLIGHTLEVEL_SAVED )
{
pBuffer += 3;
}
if( uiFlags & MAP_WORLDLIGHTS_SAVED )
{
UINT8 ubTemp;
RenderProgressBar( 0, 92 );
//RenderProgressBar( 1, 92 );
//skip number of light palette entries
LOADDATA( &ubTemp, pBuffer, 1 );
pBuffer += sizeof( SGPPaletteEntry ) * ubTemp;
//get number of lights
LOADDATA( &pSummary->usNumLights, pBuffer, 2 );
//skip the light loading
for( cnt = 0; cnt < pSummary->usNumLights; cnt++ )
{
UINT8 ubStrLen;
pBuffer += sizeof( LIGHT_SPRITE );
LOADDATA( &ubStrLen, pBuffer, 1 );
if( ubStrLen )
{
pBuffer += ubStrLen;
}
}
}
//read the mapinformation
LOADDATA( &mapInfo, pBuffer, sizeof( MAPCREATE_STRUCT ) );
memcpy( &pSummary->MapInfo, &mapInfo, sizeof( MAPCREATE_STRUCT ) );
if( uiFlags & MAP_FULLSOLDIER_SAVED )
{
TEAMSUMMARY *pTeam=NULL;
BASIC_SOLDIERCREATE_STRUCT basic;
SOLDIERCREATE_STRUCT priority;
RenderProgressBar( 0, 94 );
//RenderProgressBar( 1, 94 );
pSummary->uiEnemyPlacementPosition = pBuffer - pBufferHead;
for( i=0; i < pSummary->MapInfo.ubNumIndividuals ; i++ )
{
LOADDATA( &basic, pBuffer, sizeof( BASIC_SOLDIERCREATE_STRUCT ) );
switch( basic.bTeam )
{
case ENEMY_TEAM: pTeam = &pSummary->EnemyTeam; break;
case CREATURE_TEAM: pTeam = &pSummary->CreatureTeam; break;
case MILITIA_TEAM: pTeam = &pSummary->RebelTeam; break;
case CIV_TEAM: pTeam = &pSummary->CivTeam; break;
}
if( basic.bOrders == RNDPTPATROL || basic.bOrders == POINTPATROL )
{ //make sure the placement has at least one waypoint.
if( !basic.bPatrolCnt )
{
pSummary->ubEnemiesReqWaypoints++;
}
}
else if( basic.bPatrolCnt )
{
pSummary->ubEnemiesHaveWaypoints++;
}
if( basic.fPriorityExistance )
pTeam->ubExistance++;
switch( basic.bRelativeAttributeLevel )
{
case 0: pTeam->ubBadA++; break;
case 1: pTeam->ubPoorA++; break;
case 2: pTeam->ubAvgA++; break;
case 3: pTeam->ubGoodA++; break;
case 4: pTeam->ubGreatA++; break;
}
switch( basic.bRelativeEquipmentLevel )
{
case 0: pTeam->ubBadE++; break;
case 1: pTeam->ubPoorE++; break;
case 2: pTeam->ubAvgE++; break;
case 3: pTeam->ubGoodE++; break;
case 4: pTeam->ubGreatE++; break;
}
if( basic.fDetailedPlacement )
{ //skip static priority placement
LOADDATA( &priority, pBuffer, sizeof( SOLDIERCREATE_STRUCT ) );
if( priority.ubProfile != NO_PROFILE )
pTeam->ubProfile++;
else
pTeam->ubDetailed++;
if( basic.bTeam == CIV_TEAM )
{
if( priority.ubScheduleID )
pSummary->ubCivSchedules++;
if( priority.bBodyType == COW )
pSummary->ubCivCows++;
else if( priority.bBodyType == BLOODCAT )
pSummary->ubCivBloodcats++;
}
}
if( basic.bTeam == ENEMY_TEAM )
{
switch( basic.ubSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
pSummary->ubNumAdmins++;
if( basic.fPriorityExistance )
pSummary->ubAdminExistance++;
if( basic.fDetailedPlacement )
{
if( priority.ubProfile != NO_PROFILE )
pSummary->ubAdminProfile++;
else
pSummary->ubAdminDetailed++;
}
break;
case SOLDIER_CLASS_ELITE:
pSummary->ubNumElites++;
if( basic.fPriorityExistance )
pSummary->ubEliteExistance++;
if( basic.fDetailedPlacement )
{
if( priority.ubProfile != NO_PROFILE )
pSummary->ubEliteProfile++;
else
pSummary->ubEliteDetailed++;
}
break;
case SOLDIER_CLASS_ARMY:
pSummary->ubNumTroops++;
if( basic.fPriorityExistance )
pSummary->ubTroopExistance++;
if( basic.fDetailedPlacement )
{
if( priority.ubProfile != NO_PROFILE )
pSummary->ubTroopProfile++;
else
pSummary->ubTroopDetailed++;
}
break;
}
}
else if( basic.bTeam == CREATURE_TEAM )
{
if( basic.bBodyType == BLOODCAT )
pTeam->ubNumAnimals++;
}
pTeam->ubTotal++;
}
RenderProgressBar( 0, 96 );
//RenderProgressBar( 1, 96 );
}
if( uiFlags & MAP_EXITGRIDS_SAVED )
{
EXITGRID exitGrid;
INT32 loop;
UINT16 usMapIndex;
BOOLEAN fExitGridFound;
RenderProgressBar( 0, 98 );
//RenderProgressBar( 1, 98 );
LOADDATA( &cnt, pBuffer, 2 );
for( i = 0; i < cnt; i++ )
{
LOADDATA( &usMapIndex, pBuffer, 2 );
LOADDATA( &exitGrid, pBuffer, 5 );
fExitGridFound = FALSE;
for( loop = 0; loop < pSummary->ubNumExitGridDests; loop++ )
{
if( pSummary->ExitGrid[ loop ].usGridNo == exitGrid.usGridNo &&
pSummary->ExitGrid[ loop ].ubGotoSectorX == exitGrid.ubGotoSectorX &&
pSummary->ExitGrid[ loop ].ubGotoSectorY == exitGrid.ubGotoSectorY &&
pSummary->ExitGrid[ loop ].ubGotoSectorZ == exitGrid.ubGotoSectorZ )
{ //same destination.
pSummary->usExitGridSize[ loop ]++;
fExitGridFound = TRUE;
break;
}
}
if( !fExitGridFound )
{
if( loop >= 4 )
{
pSummary->fTooManyExitGridDests = TRUE;
}
else
{
pSummary->ubNumExitGridDests++;
pSummary->usExitGridSize[ loop ]++;
pSummary->ExitGrid[ loop ].usGridNo = exitGrid.usGridNo;
pSummary->ExitGrid[ loop ].ubGotoSectorX = exitGrid.ubGotoSectorX;
pSummary->ExitGrid[ loop ].ubGotoSectorY = exitGrid.ubGotoSectorY;
pSummary->ExitGrid[ loop ].ubGotoSectorZ = exitGrid.ubGotoSectorZ;
if( pSummary->ExitGrid[ loop ].ubGotoSectorX != exitGrid.ubGotoSectorX ||
pSummary->ExitGrid[ loop ].ubGotoSectorY != exitGrid.ubGotoSectorY )
{
pSummary->fInvalidDest[ loop ] = TRUE;
}
}
}
}
}
if( uiFlags & MAP_DOORTABLE_SAVED )
{
DOOR Door;
LOADDATA( &pSummary->ubNumDoors, pBuffer, 1 );
for( cnt = 0; cnt < pSummary->ubNumDoors; cnt++ )
{
LOADDATA( &Door, pBuffer, sizeof( DOOR ) );
if( Door.ubTrapID && Door.ubLockID )
pSummary->ubNumDoorsLockedAndTrapped++;
else if( Door.ubLockID )
pSummary->ubNumDoorsLocked++;
else if( Door.ubTrapID )
pSummary->ubNumDoorsTrapped++;
}
}
RenderProgressBar( 0, 100 );
//RenderProgressBar( 1, 100 );
MemFree( pBufferHead );
WriteSectorSummaryUpdate( szFilename, ubLevel, pSummary );
return TRUE;
}
#endif
extern UINT8 GetCurrentSummaryVersion();
extern void LoadShadeTablesFromTextFile();
BOOLEAN LoadWorld( const STR8 puiFilename )
{
HWFILE hfile;
FLOAT dMajorMapVersion;
UINT32 uiFlags;
UINT32 uiBytesRead;
UINT32 uiSoldierSize;
UINT32 uiFileSize;
UINT32 fp, offset;
#ifdef JA2TESTVERSION
UINT32 uiStartTime;
UINT32 uiLoadWorldStartTime;
#endif
INT32 cnt, cnt2;
INT32 iTilesetID;
UINT16 usTileIndex;
UINT16 usTypeSubIndex;
UINT8 ubType;
UINT8 ubSubIndex;
CHAR8 aFilename[ 50 ];
UINT8 ubCombine;
UINT8 bCounts[ WORLD_MAX ][8];
INT8 *pBuffer;
INT8 *pBufferHead;
BOOLEAN fGenerateEdgePoints = FALSE;
UINT8 ubMinorMapVersion;
#ifdef JA2TESTVERSION
uiLoadWorldStartTime = GetJA2Clock();
#endif
LoadShadeTablesFromTextFile();
// Append exension to filename!
if ( gfForceLoad )
{
sprintf( aFilename, "MAPS\\%s", gzForceLoadFile );
}
else
{
sprintf( aFilename, "MAPS\\%s", puiFilename );
}
// RESET FLAGS FOR OUTDOORS/INDOORS
gfBasement = FALSE;
gfCaves = FALSE;
// Open file
hfile = FileOpen( aFilename, FILE_ACCESS_READ, FALSE );
if ( !hfile )
{
SET_ERROR( "Could not load map file %S", aFilename );
return( FALSE );
}
SetRelativeStartAndEndPercentage( 0, 0, 1, L"Trashing world..." );
#ifdef JA2TESTVERSION
uiStartTime = GetJA2Clock();
#endif
TrashWorld();
#ifdef JA2TESTVERSION
uiTrashWorldTime = GetJA2Clock() - uiStartTime;
#endif
LightReset();
//Get the file size and alloc one huge buffer for it.
//We will use this buffer to transfer all of the data from.
uiFileSize = FileGetSize( hfile );
pBuffer = (INT8*)MemAlloc( uiFileSize );
pBufferHead = pBuffer;
FileRead( hfile, pBuffer, uiFileSize, &uiBytesRead );
FileClose( hfile );
// Read JA2 Version ID
LOADDATA( &dMajorMapVersion, pBuffer, sizeof( FLOAT ) );
// Lesh: disable this because now we accept any version map
//#ifdef RUSSIAN
// if( dMajorMapVersion != 6.00 )
// {
// return FALSE;
// }
//#endif
LOADDATA( &ubMinorMapVersion, pBuffer, sizeof( UINT8 ) );
// CHECK FOR NON-COMPATIBLE VERSIONS!
// CHECK FOR MAJOR MAP VERSION INCOMPATIBLITIES
//if ( dMajorMapVersion < gdMajorMapVersion )
//{
//AssertMsg( 0, "Major version conflict. Should have force updated this map already!!!" );
//SET_ERROR( "Incompatible JA2 map version: %f, map version is now at %f", gdLoadedMapVersion, gdMapVersion );
//return( FALSE );
//}
// Read FLAGS FOR WORLD
LOADDATA( &uiFlags, pBuffer, sizeof( INT32 ) );
LOADDATA( &iTilesetID, pBuffer, sizeof( INT32 ) );
#ifdef JA2TESTVERSION
uiStartTime = GetJA2Clock();
#endif
CHECKF( LoadMapTileset( iTilesetID ) != FALSE );
#ifdef JA2TESTVERSION
uiLoadMapTilesetTime = GetJA2Clock() - uiStartTime;
#endif
// Load soldier size
LOADDATA( &uiSoldierSize, pBuffer, sizeof( INT32 ) );
//FP 0x000010
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
// Read height values
LOADDATA( &gpWorldLevelData[ cnt ].sHeight, pBuffer, sizeof( INT16 ) );
}
//FP 0x00c810
SetRelativeStartAndEndPercentage( 0, 35, 40, L"Counting layers..." );
RenderProgressBar( 0, 100 );
// Read layer counts
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
// Read combination of land/world flags
LOADDATA( &ubCombine, pBuffer, sizeof( UINT8 ) );
// split
bCounts[ cnt ][0] = (UINT8)(ubCombine&0xf);
gpWorldLevelData[ cnt ].uiFlags |= (UINT8)((ubCombine&0xf0)>>4);
// Read #objects, structs
LOADDATA( &ubCombine, pBuffer, sizeof( UINT8 ) );
// split
bCounts[ cnt ][1] = (UINT8)(ubCombine&0xf);
bCounts[ cnt ][2] = (UINT8)((ubCombine&0xf0)>>4);
// Read shadows, roof
LOADDATA( &ubCombine, pBuffer, sizeof( UINT8 ) );
// split
bCounts[ cnt ][3] = (UINT8)(ubCombine&0xf);
bCounts[ cnt ][4] = (UINT8)((ubCombine&0xf0)>>4);
// Read OnRoof, nothing
LOADDATA( &ubCombine, pBuffer, sizeof( UINT8 ) );
// split
bCounts[ cnt ][5] = (UINT8)(ubCombine&0xf);
}
//FP 0x025810
fp = 0x025810;
offset = 0;
SetRelativeStartAndEndPercentage( 0, 40, 43, L"Loading land layers...");
RenderProgressBar( 0, 100 );
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
// Read new values
if( bCounts[ cnt ][ 0 ] > 10 )
{
cnt = cnt;
}
for( cnt2 = 0; cnt2 < bCounts[ cnt ][ 0 ]; cnt2++ )
{
LOADDATA( &ubType, pBuffer, sizeof( UINT8 ) );
LOADDATA( &ubSubIndex, pBuffer, sizeof( UINT8 ) );
// Get tile index
GetTileIndexFromTypeSubIndex( ubType, ubSubIndex, &usTileIndex );
// Add layer
AddLandToHead( cnt, usTileIndex );
offset += 2;
}
}
fp += offset;
offset = 0;
SetRelativeStartAndEndPercentage( 0, 43, 46, L"Loading object layer...");
RenderProgressBar( 0, 100 );
if( 0 )
{ //Old loads
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
// Set objects
for( cnt2 = 0; cnt2 < bCounts[ cnt ][ 1 ]; cnt2++ )
{
LOADDATA( &ubType, pBuffer, sizeof( UINT8 ) );
LOADDATA( &ubSubIndex, pBuffer, sizeof( UINT8 ) );
if ( ubType >= FIRSTPOINTERS )
{
continue;
}
// Get tile index
GetTileIndexFromTypeSubIndex( ubType, ubSubIndex, &usTileIndex );
// Add layer
AddObjectToTail( cnt, usTileIndex );
}
}
}
else
{ //New load require UINT16 for the type subindex due to the fact that ROADPIECES
//contain over 300 type subindices.
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
// Set objects
if( bCounts[ cnt ][ 1 ] > 10 )
{
cnt = cnt;
}
for( cnt2 = 0; cnt2 < bCounts[ cnt ][ 1 ]; cnt2++ )
{
LOADDATA( &ubType, pBuffer, sizeof( UINT8 ) );
LOADDATA( &usTypeSubIndex, pBuffer, sizeof( UINT16 ) );
if ( ubType >= FIRSTPOINTERS )
{
continue;
}
// Get tile index
GetTileIndexFromTypeSubIndex( ubType, usTypeSubIndex, &usTileIndex );
// Add layer
AddObjectToTail( cnt, usTileIndex );
offset += 3;
}
}
}
fp += offset;
offset = 0;
SetRelativeStartAndEndPercentage( 0, 46, 49, L"Loading struct layer..." );
RenderProgressBar( 0, 100 );
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
// Set structs
if( bCounts[ cnt ][ 2 ] > 10 )
{
cnt = cnt;
}
for( cnt2 = 0; cnt2 < bCounts[ cnt ][ 2 ]; cnt2++ )
{
LOADDATA( &ubType, pBuffer, sizeof( UINT8 ) );
LOADDATA( &ubSubIndex, pBuffer, sizeof( UINT8 ) );
// Get tile index
GetTileIndexFromTypeSubIndex( ubType, ubSubIndex, &usTileIndex );
if ( ubMinorMapVersion <= 25 )
{
// Check patching for phantom menace struct data...
if ( gTileDatabase[ usTileIndex ].uiFlags & UNDERFLOW_FILLER )
{
GetTileIndexFromTypeSubIndex( ubType, 1, &usTileIndex );
}
}
// Add layer
AddStructToTail( cnt, usTileIndex );
offset += 2;
}
}
fp += offset;
offset = 0;
SetRelativeStartAndEndPercentage( 0, 49, 52, L"Loading shadow layer..." );
RenderProgressBar( 0, 100 );
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
if( bCounts[ cnt ][ 3 ] > 10 )
{
cnt = cnt;
}
for( cnt2 = 0; cnt2 < bCounts[ cnt ][ 3 ]; cnt2++ )
{
LOADDATA( &ubType, pBuffer, sizeof( UINT8 ) );
LOADDATA( &ubSubIndex, pBuffer, sizeof( UINT8 ) );
// Get tile index
GetTileIndexFromTypeSubIndex( ubType, ubSubIndex, &usTileIndex );
// Add layer
AddShadowToTail( cnt, usTileIndex );
offset += 2;
}
}
fp += offset;
offset = 0;
SetRelativeStartAndEndPercentage( 0, 52, 55, L"Loading roof layer..." );
RenderProgressBar( 0, 100 );
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
if( bCounts[ cnt ][ 4 ] > 10 )
{
cnt = cnt;
}
for( cnt2 = 0; cnt2 < bCounts[ cnt ][ 4 ]; cnt2++ )
{
LOADDATA( &ubType, pBuffer, sizeof( UINT8 ) );
LOADDATA( &ubSubIndex, pBuffer, sizeof( UINT8 ) );
// Get tile index
GetTileIndexFromTypeSubIndex( ubType, ubSubIndex, &usTileIndex );
// Add layer
AddRoofToTail( cnt, usTileIndex );
offset += 2;
}
}
fp += offset;
offset = 0;
SetRelativeStartAndEndPercentage( 0, 55, 58, L"Loading on roof layer..." );
RenderProgressBar( 0, 100 );
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
if( bCounts[ cnt ][ 5 ] > 10 )
{
cnt = cnt;
}
for( cnt2 = 0; cnt2 < bCounts[ cnt ][ 5 ]; cnt2++ )
{
LOADDATA( &ubType, pBuffer, sizeof( UINT8 ) );
LOADDATA( &ubSubIndex, pBuffer, sizeof( UINT8 ) );
// Get tile index
GetTileIndexFromTypeSubIndex( ubType, ubSubIndex, &usTileIndex );
// Add layer
AddOnRoofToTail( cnt, usTileIndex );
offset += 2;
}
}
fp += offset;
offset = 0;
// Lesh: read additional bytes for map major version 6.00
if( dMajorMapVersion == 6.00 )
{
UINT32 uiNums[37];
LOADDATA( uiNums, pBuffer, 37 * sizeof( INT32 ) );
dMajorMapVersion = 5.00;
}
SetRelativeStartAndEndPercentage( 0, 58, 59, L"Loading room information..." );
RenderProgressBar( 0, 100 );
#ifdef JA2EDITOR
gubMaxRoomNumber = 0;
for( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
// Read room information
LOADDATA( &gubWorldRoomInfo[ cnt ], pBuffer, sizeof( INT8 ) );
//Got to set the max room number
if( gubWorldRoomInfo[ cnt ] > gubMaxRoomNumber )
gubMaxRoomNumber = gubWorldRoomInfo[ cnt ];
}
if( gubMaxRoomNumber < 255 )
gubMaxRoomNumber++;
#else
LOADDATA( gubWorldRoomInfo, pBuffer, sizeof( INT8 ) * WORLD_MAX );
#endif
// ATE; Memset this array!
if( 0 )
{ //for debugging purposes
memset( gubWorldRoomInfo, 0, sizeof( gubWorldRoomInfo ) );
}
memset( gubWorldRoomHidden, TRUE, sizeof( gubWorldRoomHidden ) );
SetRelativeStartAndEndPercentage( 0, 59, 61, L"Loading items..." );
RenderProgressBar( 0, 100 );
if( uiFlags & MAP_WORLDITEMS_SAVED )
{
// Load out item information
gfLoadPitsWithoutArming = TRUE;
LoadWorldItemsFromMap( &pBuffer );
gfLoadPitsWithoutArming = FALSE;
}
SetRelativeStartAndEndPercentage( 0, 62, 85, L"Loading lights..." );
RenderProgressBar( 0, 0 );
if( uiFlags & MAP_AMBIENTLIGHTLEVEL_SAVED )
{ //Ambient light levels are only saved in underground levels
LOADDATA( &gfBasement, pBuffer, 1 );
LOADDATA( &gfCaves, pBuffer, 1 );
LOADDATA( &ubAmbientLightLevel, pBuffer, 1 );
}
else
{ //We are above ground.
gfBasement = FALSE;
gfCaves = FALSE;
if( !gfEditMode && guiCurrentScreen != MAPUTILITY_SCREEN )
{
ubAmbientLightLevel = GetTimeOfDayAmbientLightLevel();
}
else
{
ubAmbientLightLevel = 4;
}
}
#ifdef JA2TESTVERSION
uiStartTime = GetJA2Clock();
#endif
if( uiFlags & MAP_WORLDLIGHTS_SAVED )
{
LoadMapLights( &pBuffer );
}
else
{
// Set some default value for lighting
SetDefaultWorldLightingColors( );
}
LightSetBaseLevel( ubAmbientLightLevel );
#ifdef JA2TESTVERSION
uiLoadMapLightsTime = GetJA2Clock() - uiStartTime;
#endif
SetRelativeStartAndEndPercentage( 0, 85, 86, L"Loading map information..." );
RenderProgressBar( 0, 0 );
LoadMapInformation( &pBuffer );
if( uiFlags & MAP_FULLSOLDIER_SAVED )
{
SetRelativeStartAndEndPercentage( 0, 86, 87, L"Loading placements..." );
RenderProgressBar( 0, 0 );
LoadSoldiersFromMap( &pBuffer );
}
if( uiFlags & MAP_EXITGRIDS_SAVED )
{
SetRelativeStartAndEndPercentage( 0, 87, 88, L"Loading exit grids..." );
RenderProgressBar( 0, 0 );
LoadExitGrids( &pBuffer );
}
if( uiFlags & MAP_DOORTABLE_SAVED )
{
SetRelativeStartAndEndPercentage( 0, 89, 90, L"Loading door tables..." );
RenderProgressBar( 0, 0 );
LoadDoorTableFromMap( &pBuffer );
}
if( uiFlags & MAP_EDGEPOINTS_SAVED )
{
SetRelativeStartAndEndPercentage( 0, 90, 91, L"Loading edgepoints..." );
RenderProgressBar( 0, 0 );
if( !LoadMapEdgepoints( &pBuffer ) )
fGenerateEdgePoints = TRUE; //only if the map had the older edgepoint system
}
else
{
fGenerateEdgePoints = TRUE;
}
if( uiFlags & MAP_NPCSCHEDULES_SAVED )
{
SetRelativeStartAndEndPercentage( 0, 91, 92, L"Loading NPC schedules..." );
RenderProgressBar( 0, 0 );
LoadSchedules( &pBuffer );
}
ValidateAndUpdateMapVersionIfNecessary();
//if we arent loading a saved game
// if( !(gTacticalStatus.uiFlags & LOADING_SAVED_GAME ) )
{
SetRelativeStartAndEndPercentage( 0, 93, 94, L"Init Loaded World..." );
RenderProgressBar( 0, 0 );
InitLoadedWorld( );
}
if( fGenerateEdgePoints )
{
SetRelativeStartAndEndPercentage( 0, 94, 95, L"Generating map edgepoints..." );
RenderProgressBar( 0, 0 );
CompileWorldMovementCosts();
GenerateMapEdgepoints();
}
RenderProgressBar( 0, 20 );
SetRelativeStartAndEndPercentage( 0, 95, 100, L"General initialization..." );
// RESET AI!
InitOpponentKnowledgeSystem();
RenderProgressBar( 0, 30 );
//AllTeamsLookForAll(NO_INTERRUPTS);
RenderProgressBar( 0, 40 );
//Reset some override flags
gfForceLoadPlayers = FALSE;
gfForceLoad = FALSE;
// CHECK IF OUR SELECTED GUY IS GONE!
if ( gusSelectedSoldier != NO_SOLDIER )
{
if ( MercPtrs[ gusSelectedSoldier ]->bActive == FALSE )
{
gusSelectedSoldier = NO_SOLDIER;
}
}
AdjustSoldierCreationStartValues( );
RenderProgressBar( 0, 60 );
InvalidateWorldRedundency( );
// SAVE FILENAME
strcpy( gzLastLoadedFile, puiFilename );
LoadRadarScreenBitmap( puiFilename );
RenderProgressBar( 0, 80 );
gfWorldLoaded = TRUE;
sprintf( gubFilename, puiFilename );
//Remove this rather large chunk of memory from the system now!
MemFree( pBufferHead );
#ifdef JA2TESTVERSION
uiLoadWorldTime = GetJA2Clock() - uiLoadWorldStartTime;
#endif
//#ifdef JA2TESTVERSION
// ATE: Not while updating maps!
if ( guiCurrentScreen != MAPUTILITY_SCREEN )
{
GenerateBuildings();
}
//#endif
RenderProgressBar( 0, 100 );
DequeueAllKeyBoardEvents();
return( TRUE );
}
//****************************************************************************************
//
// Deletes everything then re-creates the world with simple ground tiles
//
//****************************************************************************************
BOOLEAN NewWorld( void )
{
UINT16 NewIndex;
INT32 cnt;
gusSelectedSoldier = gusOldSelectedSoldier = NO_SOLDIER;
AdjustSoldierCreationStartValues( );
TrashWorld();
// Create world randomly from tiles
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
// Set land index
NewIndex = (UINT16)(rand( ) % 10);
AddLandToHead( cnt, NewIndex );
}
InitRoomDatabase( );
gfWorldLoaded = TRUE;
return( TRUE );
}
void TrashWorld( void )
{
MAP_ELEMENT *pMapTile;
LEVELNODE *pLandNode;
LEVELNODE *pObjectNode;
LEVELNODE *pStructNode;
LEVELNODE *pShadowNode;
LEVELNODE *pMercNode;
LEVELNODE *pRoofNode;
LEVELNODE *pOnRoofNode;
LEVELNODE *pTopmostNode;
// STRUCTURE *pStructureNode;
INT32 cnt;
SOLDIERTYPE *pSoldier;
if( !gfWorldLoaded )
return;
// REMOVE ALL ITEMS FROM WORLD
TrashWorldItems( );
// Trash the overhead map
TrashOverheadMap( );
//Reset the smoke effects.
ResetSmokeEffects();
//Reset the light effects
ResetLightEffects();
// Set soldiers to not active!
//ATE: FOR NOW, ONLY TRASH FROM NPC UP!!!!
//cnt = gTacticalStatus.Team[ gbPlayerNum ].bLastID + 1;
cnt = 0;
for ( pSoldier = MercPtrs[ cnt ]; cnt < MAX_NUM_SOLDIERS; pSoldier++, cnt++ )
{
if ( pSoldier->bActive )
{
if ( pSoldier->bTeam == gbPlayerNum )
{
// Just delete levelnode
pSoldier->pLevelNode = NULL;
}
else
{
// Delete from world
TacticalRemoveSoldier( (UINT16)cnt );
}
}
}
RemoveCorpses( );
// Remove all ani tiles...
DeleteAniTiles( );
//Kill both soldier init lists.
UseEditorAlternateList();
KillSoldierInitList();
UseEditorOriginalList();
KillSoldierInitList();
//Remove the schedules
DestroyAllSchedules();
// on trash world sheck if we have to set up the first meanwhile
HandleFirstMeanWhileSetUpWithTrashWorld( );
// Create world randomly from tiles
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
pMapTile = &gpWorldLevelData[ cnt ];
// Free the memory associated with the map tile link lists
pLandNode = pMapTile->pLandHead;
while ( pLandNode != NULL )
{
pMapTile->pLandHead = pLandNode->pNext;
MemFree( pLandNode );
pLandNode = pMapTile->pLandHead;
}
pObjectNode = pMapTile->pObjectHead;
while ( pObjectNode != NULL )
{
pMapTile->pObjectHead = pObjectNode->pNext;
MemFree( pObjectNode );
pObjectNode = pMapTile->pObjectHead;
}
pStructNode = pMapTile->pStructHead;
while ( pStructNode != NULL )
{
pMapTile->pStructHead = pStructNode->pNext;
MemFree( pStructNode );
pStructNode = pMapTile->pStructHead;
}
pShadowNode = pMapTile->pShadowHead;
while ( pShadowNode != NULL )
{
pMapTile->pShadowHead = pShadowNode->pNext;
MemFree( pShadowNode );
pShadowNode = pMapTile->pShadowHead;
}
pMercNode = pMapTile->pMercHead;
while ( pMercNode != NULL )
{
pMapTile->pMercHead = pMercNode->pNext;
MemFree( pMercNode );
pMercNode = pMapTile->pMercHead;
}
pRoofNode = pMapTile->pRoofHead;
while ( pRoofNode != NULL )
{
pMapTile->pRoofHead = pRoofNode->pNext;
MemFree( pRoofNode );
pRoofNode = pMapTile->pRoofHead;
}
pOnRoofNode = pMapTile->pOnRoofHead;
while ( pOnRoofNode != NULL )
{
pMapTile->pOnRoofHead = pOnRoofNode->pNext;
MemFree( pOnRoofNode );
pOnRoofNode = pMapTile->pOnRoofHead;
}
pTopmostNode = pMapTile->pTopmostHead;
while ( pTopmostNode != NULL )
{
pMapTile->pTopmostHead = pTopmostNode->pNext;
MemFree( pTopmostNode );
pTopmostNode = pMapTile->pTopmostHead;
}
while (pMapTile->pStructureHead != NULL)
{
if (DeleteStructureFromWorld( pMapTile->pStructureHead ) == FALSE)
{
// ERROR!!!!!!
break;
}
}
}
// Zero world
memset( gpWorldLevelData, 0, WORLD_MAX * sizeof( MAP_ELEMENT ) );
// Set some default flags
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
gpWorldLevelData[ cnt ].uiFlags |= MAPELEMENT_RECALCULATE_WIREFRAMES;
}
TrashDoorTable();
TrashMapEdgepoints();
TrashDoorStatusArray();
//gfBlitBattleSectorLocator = FALSE;
gfWorldLoaded = FALSE;
sprintf( gubFilename, "none" );
}
void TrashMapTile(INT16 MapTile)
{
MAP_ELEMENT *pMapTile;
LEVELNODE *pLandNode;
LEVELNODE *pObjectNode;
LEVELNODE *pStructNode;
LEVELNODE *pShadowNode;
LEVELNODE *pMercNode;
LEVELNODE *pRoofNode;
LEVELNODE *pOnRoofNode;
LEVELNODE *pTopmostNode;
pMapTile = &gpWorldLevelData[ MapTile ];
// Free the memory associated with the map tile link lists
pLandNode = pMapTile->pLandHead;
while ( pLandNode != NULL )
{
pMapTile->pLandHead = pLandNode->pNext;
MemFree( pLandNode );
pLandNode = pMapTile->pLandHead;
}
pMapTile->pLandHead = pMapTile->pLandStart = NULL;
pObjectNode = pMapTile->pObjectHead;
while ( pObjectNode != NULL )
{
pMapTile->pObjectHead = pObjectNode->pNext;
MemFree( pObjectNode );
pObjectNode = pMapTile->pObjectHead;
}
pMapTile->pObjectHead = NULL;
pStructNode = pMapTile->pStructHead;
while ( pStructNode != NULL )
{
pMapTile->pStructHead = pStructNode->pNext;
MemFree( pStructNode );
pStructNode = pMapTile->pStructHead;
}
pMapTile->pStructHead = NULL;
pShadowNode = pMapTile->pShadowHead;
while ( pShadowNode != NULL )
{
pMapTile->pShadowHead = pShadowNode->pNext;
MemFree( pShadowNode );
pShadowNode = pMapTile->pShadowHead;
}
pMapTile->pShadowHead = NULL;
pMercNode = pMapTile->pMercHead;
while ( pMercNode != NULL )
{
pMapTile->pMercHead = pMercNode->pNext;
MemFree( pMercNode );
pMercNode = pMapTile->pMercHead;
}
pMapTile->pMercHead = NULL;
pRoofNode = pMapTile->pRoofHead;
while ( pRoofNode != NULL )
{
pMapTile->pRoofHead = pRoofNode->pNext;
MemFree( pRoofNode );
pRoofNode = pMapTile->pRoofHead;
}
pMapTile->pRoofHead = NULL;
pOnRoofNode = pMapTile->pOnRoofHead;
while ( pOnRoofNode != NULL )
{
pMapTile->pOnRoofHead = pOnRoofNode->pNext;
MemFree( pOnRoofNode );
pOnRoofNode = pMapTile->pOnRoofHead;
}
pMapTile->pOnRoofHead = NULL;
pTopmostNode = pMapTile->pTopmostHead;
while ( pTopmostNode != NULL )
{
pMapTile->pTopmostHead = pTopmostNode->pNext;
MemFree( pTopmostNode );
pTopmostNode = pMapTile->pTopmostHead;
}
pMapTile->pTopmostHead = NULL;
while (pMapTile->pStructureHead != NULL)
{
DeleteStructureFromWorld( pMapTile->pStructureHead );
}
pMapTile->pStructureHead = pMapTile->pStructureTail = NULL;
}
BOOLEAN LoadMapTileset( INT32 iTilesetID )
{
if ( iTilesetID >= gubNumSets )
{
return( FALSE );
}
// Init tile surface used values
memset( gbNewTileSurfaceLoaded, 0, sizeof( gbNewTileSurfaceLoaded ) );
if( iTilesetID == giCurrentTilesetID )
{
return( TRUE );
}
// Get free memory value nere
gSurfaceMemUsage = guiMemTotal;
// LOAD SURFACES
CHECKF( LoadTileSurfaces( &(gTilesets[ iTilesetID ].TileSurfaceFilenames[0] ), (UINT8)iTilesetID ) != FALSE );
// SET TERRAIN COSTS
if ( gTilesets[ iTilesetID ].MovementCostFnc != NULL )
{
gTilesets[ iTilesetID ].MovementCostFnc( );
}
else
{
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Tileset %d has no callback function for movement costs. Using default.", iTilesetID) );
SetTilesetOneTerrainValues( );
}
// RESET TILE DATABASE
DeallocateTileDatabase( );
CreateTileDatabase( );
// SET GLOBAL ID FOR TILESET ( FOR SAVING! )
giCurrentTilesetID = iTilesetID;
return( TRUE );
}
BOOLEAN SaveMapTileset( INT32 iTilesetID )
{
// FILE *hTSet;
HWFILE hTSet;
char zTilesetName[65];
int cnt;
UINT32 uiBytesWritten;
// Are we trying to save the default tileset?
if ( iTilesetID == 0 )
return( TRUE );
sprintf( zTilesetName, "TSET%04d.SET", iTilesetID );
// Open file
hTSet = FileOpen( zTilesetName, FILE_ACCESS_WRITE | FILE_CREATE_ALWAYS, FALSE );
if ( !hTSet )
{
return( FALSE );
}
// Save current tile set in map file.
for ( cnt = 0; cnt < NUMBEROFTILETYPES; cnt++ )
FileWrite( hTSet, TileSurfaceFilenames[cnt], 65, &uiBytesWritten );
FileClose( hTSet );
return( TRUE );
}
void SetLoadOverrideParams( BOOLEAN fForceLoad, BOOLEAN fForceFile, CHAR8 *zLoadName )
{
gfForceLoadPlayers = fForceLoad;
gfForceLoad = fForceFile;
if ( zLoadName != NULL )
{
strcpy( gzForceLoadFile, zLoadName );
}
}
void AddWireFrame( INT16 sGridNo, UINT16 usIndex, BOOLEAN fForced )
{
LEVELNODE *pTopmost, *pTopmostTail;
pTopmost = gpWorldLevelData[ sGridNo ].pTopmostHead;
while ( pTopmost != NULL )
{
// Check if one of the samer type exists!
if ( pTopmost->usIndex == usIndex )
{
return;
}
pTopmost = pTopmost->pNext;
}
pTopmostTail = AddTopmostToTail( sGridNo, usIndex );
if ( fForced )
{
pTopmostTail->uiFlags |= LEVELNODE_WIREFRAME;
}
}
UINT16 GetWireframeGraphicNumToUseForWall( INT16 sGridNo, STRUCTURE *pStructure )
{
LEVELNODE *pNode = NULL;
UINT8 ubWallOrientation;
UINT16 usValue = 0;
UINT16 usSubIndex;
STRUCTURE *pBaseStructure;
ubWallOrientation = pStructure->ubWallOrientation;
pBaseStructure = FindBaseStructure( pStructure );
if ( pBaseStructure )
{
// Find levelnode...
pNode = gpWorldLevelData[sGridNo].pStructHead;
while( pNode != NULL )
{
if (pNode->pStructureData == pBaseStructure)
{
break;
}
pNode = pNode->pNext;
}
if ( pNode != NULL )
{
// Get Subindex for this wall...
GetSubIndexFromTileIndex( pNode->usIndex, &usSubIndex );
// Check for broken peices...
if ( usSubIndex == 48 || usSubIndex == 52 )
{
return( WIREFRAMES12 );
}
else if ( usSubIndex == 49 || usSubIndex == 53 )
{
return( WIREFRAMES13 );
}
else if ( usSubIndex == 50 || usSubIndex == 54 )
{
return( WIREFRAMES10 );
}
else if ( usSubIndex == 51 || usSubIndex == 55 )
{
return( WIREFRAMES11 );
}
}
}
switch( ubWallOrientation )
{
case OUTSIDE_TOP_LEFT:
case INSIDE_TOP_LEFT:
usValue = WIREFRAMES6;
break;
case OUTSIDE_TOP_RIGHT:
case INSIDE_TOP_RIGHT:
usValue = WIREFRAMES5;
break;
}
return( usValue );
}
void CalculateWorldWireFrameTiles( BOOLEAN fForce )
{
INT32 cnt;
STRUCTURE *pStructure;
INT16 sGridNo;
UINT8 ubWallOrientation;
INT8 bHiddenVal;
INT8 bNumWallsSameGridNo;
UINT16 usWireFrameIndex;
// Create world randomly from tiles
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
if ( gpWorldLevelData[ cnt ].uiFlags & MAPELEMENT_RECALCULATE_WIREFRAMES || fForce )
{
if ( cnt == 8377 )
{
int i = 0;
}
// Turn off flag
gpWorldLevelData[ cnt ].uiFlags &= (~MAPELEMENT_RECALCULATE_WIREFRAMES );
// Remove old ones
RemoveWireFrameTiles( (INT16)cnt );
bNumWallsSameGridNo = 0;
// Check our gridno, if we have a roof over us that has not beenr evealed, no need for a wiereframe
if ( IsRoofVisibleForWireframe( (UINT16)cnt ) && !( gpWorldLevelData[ cnt ].uiFlags & MAPELEMENT_REVEALED ) )
{
continue;
}
pStructure = gpWorldLevelData[ cnt ].pStructureHead;
while ( pStructure != NULL )
{
// Check for doors
if ( pStructure->fFlags & STRUCTURE_ANYDOOR )
{
// ATE: need this additional check here for hidden doors!
if ( pStructure->fFlags & STRUCTURE_OPENABLE )
{
// Does the gridno we are over have a non-visible tile?
// Based on orientation
ubWallOrientation = pStructure->ubWallOrientation;
switch( ubWallOrientation )
{
case OUTSIDE_TOP_LEFT:
case INSIDE_TOP_LEFT:
// Get gridno
sGridNo = NewGridNo( (INT16)cnt, DirectionInc( SOUTH ) );
if ( IsRoofVisibleForWireframe( sGridNo ) && !( gpWorldLevelData[ sGridNo ].uiFlags & MAPELEMENT_REVEALED ) )
{
AddWireFrame( (INT16)cnt, WIREFRAMES4, (BOOLEAN)( ( gpWorldLevelData[ sGridNo ].uiFlags & MAPELEMENT_REVEALED ) != 0 ) );
}
break;
case OUTSIDE_TOP_RIGHT:
case INSIDE_TOP_RIGHT:
// Get gridno
sGridNo = NewGridNo( (INT16)cnt, DirectionInc( EAST ) );
if ( IsRoofVisibleForWireframe( sGridNo ) && !( gpWorldLevelData[ sGridNo ].uiFlags & MAPELEMENT_REVEALED ) )
{
AddWireFrame( (INT16)cnt, WIREFRAMES3 , (BOOLEAN)( ( gpWorldLevelData[ sGridNo ].uiFlags & MAPELEMENT_REVEALED ) != 0 ) );
}
break;
}
}
}
// Check for windows
else
{
if ( pStructure->fFlags & STRUCTURE_WALLNWINDOW )
{
// Does the gridno we are over have a non-visible tile?
// Based on orientation
ubWallOrientation = pStructure->ubWallOrientation;
switch( ubWallOrientation )
{
case OUTSIDE_TOP_LEFT:
case INSIDE_TOP_LEFT:
// Get gridno
sGridNo = NewGridNo( (INT16)cnt, DirectionInc( SOUTH ) );
if ( IsRoofVisibleForWireframe( sGridNo ) && !( gpWorldLevelData[ sGridNo ].uiFlags & MAPELEMENT_REVEALED ) )
{
AddWireFrame( (INT16)cnt, WIREFRAMES2, (BOOLEAN)( ( gpWorldLevelData[ sGridNo ].uiFlags & MAPELEMENT_REVEALED ) != 0 ) );
}
break;
case OUTSIDE_TOP_RIGHT:
case INSIDE_TOP_RIGHT:
// Get gridno
sGridNo = NewGridNo( (INT16)cnt, DirectionInc( EAST ) );
if ( IsRoofVisibleForWireframe( sGridNo ) && !( gpWorldLevelData[ sGridNo ].uiFlags & MAPELEMENT_REVEALED ) )
{
AddWireFrame( (INT16)cnt, WIREFRAMES1, (BOOLEAN)( ( gpWorldLevelData[ sGridNo ].uiFlags & MAPELEMENT_REVEALED ) != 0 ) );
}
break;
}
}
// Check for walls
if ( pStructure->fFlags & STRUCTURE_WALLSTUFF )
{
// Does the gridno we are over have a non-visible tile?
// Based on orientation
ubWallOrientation = pStructure->ubWallOrientation;
usWireFrameIndex = GetWireframeGraphicNumToUseForWall( (UINT16)cnt, pStructure );
switch( ubWallOrientation )
{
case OUTSIDE_TOP_LEFT:
case INSIDE_TOP_LEFT:
// Get gridno
sGridNo = NewGridNo( (INT16)cnt, DirectionInc( SOUTH ) );
if ( IsRoofVisibleForWireframe( sGridNo ) )
{
bNumWallsSameGridNo++;
AddWireFrame( (INT16)cnt, usWireFrameIndex, (BOOLEAN)( ( gpWorldLevelData[ sGridNo ].uiFlags & MAPELEMENT_REVEALED ) != 0 ) );
// Check along our direction to see if we are a corner
sGridNo = NewGridNo( (INT16)cnt, DirectionInc( WEST ) );
sGridNo = NewGridNo( sGridNo, DirectionInc( SOUTH ) );
bHiddenVal = IsHiddenTileMarkerThere( sGridNo );
// If we do not exist ( -1 ) or are revealed ( 1 )
if ( bHiddenVal == -1 || bHiddenVal == 1 )
{
// Place corner!
AddWireFrame( (INT16)cnt, WIREFRAMES9, (BOOLEAN)( ( gpWorldLevelData[ sGridNo ].uiFlags & MAPELEMENT_REVEALED ) != 0 ) );
}
}
break;
case OUTSIDE_TOP_RIGHT:
case INSIDE_TOP_RIGHT:
// Get gridno
sGridNo = NewGridNo( (INT16)cnt, DirectionInc( EAST ) );
if ( IsRoofVisibleForWireframe( sGridNo ) )
{
bNumWallsSameGridNo++;
AddWireFrame( (INT16)cnt, usWireFrameIndex, (BOOLEAN)( ( gpWorldLevelData[ sGridNo ].uiFlags & MAPELEMENT_REVEALED ) != 0 ) );
// Check along our direction to see if we are a corner
sGridNo = NewGridNo( (INT16)cnt, DirectionInc( NORTH ) );
sGridNo = NewGridNo( sGridNo, DirectionInc( EAST ) );
bHiddenVal = IsHiddenTileMarkerThere( sGridNo );
// If we do not exist ( -1 ) or are revealed ( 1 )
if ( bHiddenVal == -1 || bHiddenVal == 1 )
{
// Place corner!
AddWireFrame( (INT16)cnt, WIREFRAMES8, (BOOLEAN)( ( gpWorldLevelData[ sGridNo ].uiFlags & MAPELEMENT_REVEALED ) != 0 ) );
}
}
break;
}
// Check for both walls
if ( bNumWallsSameGridNo == 2 )
{
sGridNo = NewGridNo( (INT16)cnt, DirectionInc( EAST ) );
sGridNo = NewGridNo( sGridNo, DirectionInc( SOUTH ) );
AddWireFrame( (INT16)cnt, WIREFRAMES7, (BOOLEAN)( ( gpWorldLevelData[ sGridNo ].uiFlags & MAPELEMENT_REVEALED ) != 0 ) );
}
}
}
pStructure = pStructure->pNext;
}
}
}
}
void RemoveWorldWireFrameTiles( )
{
INT32 cnt;
// Create world randomly from tiles
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
RemoveWireFrameTiles( (INT16)cnt );
}
}
void RemoveWireFrameTiles( INT16 sGridNo )
{
LEVELNODE *pTopmost, *pNewTopmost;
TILE_ELEMENT * pTileElement;
pTopmost = gpWorldLevelData[ sGridNo ].pTopmostHead;
while ( pTopmost != NULL )
{
pNewTopmost = pTopmost->pNext;
if ( pTopmost->usIndex < NUMBEROFTILES )
{
pTileElement = &(gTileDatabase[ pTopmost->usIndex ]);
if ( pTileElement->fType == WIREFRAMES )
{
RemoveTopmost( sGridNo, pTopmost->usIndex );
}
}
pTopmost = pNewTopmost;
}
}
INT8 IsHiddenTileMarkerThere( INT16 sGridNo )
{
STRUCTURE * pStructure;
if ( !gfBasement )
{
pStructure = FindStructure( sGridNo, STRUCTURE_ROOF );
if ( pStructure != NULL )
{
//if ( !( gpWorldLevelData[ sGridNo ].uiFlags & MAPELEMENT_REVEALED ) )
{
return( 2 );
}
// if we are here, a roof exists but has been revealed
return( 1 );
}
}
else
{
//if ( InARoom( sGridNo, &ubRoom ) )
{
//if ( !( gpWorldLevelData[ sGridNo ].uiFlags & MAPELEMENT_REVEALED ) )
{
return( 2 );
}
return( 1 );
}
}
return( -1 );
}
void ReloadTileset( UINT8 ubID )
{
CHAR8 aFilename[ 255 ];
INT32 iCurrTilesetID = giCurrentTilesetID;
// Set gloabal
giCurrentTilesetID = ubID;
// Save Map
SaveWorld( TEMP_FILE_FOR_TILESET_CHANGE );
//IMPORTANT: If this is not set, the LoadTileset() will assume that
//it is loading the same tileset and ignore it...
giCurrentTilesetID = iCurrTilesetID;
// Load Map with new tileset
LoadWorld( TEMP_FILE_FOR_TILESET_CHANGE );
// Delete file
sprintf( aFilename, "MAPS\\%s", TEMP_FILE_FOR_TILESET_CHANGE );
FileDelete( aFilename );
}
void SaveMapLights( HWFILE hfile )
{
SOLDIERTYPE *pSoldier;
SGPPaletteEntry LColors[3];
UINT8 ubNumColors;
BOOLEAN fSoldierLight;
UINT16 usNumLights = 0;
UINT16 cnt, cnt2;
UINT8 ubStrLen;
UINT32 uiBytesWritten;
ubNumColors = LightGetColors( LColors );
// Save the current light colors!
FileWrite( hfile, &ubNumColors, 1, &uiBytesWritten );
FileWrite( hfile, LColors, sizeof(SGPPaletteEntry)*ubNumColors, &uiBytesWritten );
//count number of non-merc lights.
for( cnt = 0; cnt < MAX_LIGHT_SPRITES; cnt++ )
{
if( LightSprites[ cnt ].uiFlags & LIGHT_SPR_ACTIVE )
{ //found an active light. Check to make sure it doesn't belong to a merc.
fSoldierLight = FALSE;
for ( cnt2 = 0; cnt2 < MAX_NUM_SOLDIERS && !fSoldierLight; cnt2++ )
{
if( GetSoldier( &pSoldier, cnt2 ) )
{
if ( pSoldier->iLight == (INT32)cnt )
fSoldierLight = TRUE;
}
}
if( !fSoldierLight )
usNumLights++;
}
}
//save the number of lights.
FileWrite( hfile, &usNumLights, 2, &uiBytesWritten );
for( cnt = 0; cnt < MAX_LIGHT_SPRITES; cnt++ )
{
if( LightSprites[ cnt ].uiFlags & LIGHT_SPR_ACTIVE )
{ //found an active light. Check to make sure it doesn't belong to a merc.
fSoldierLight = FALSE;
for ( cnt2 = 0; cnt2 < MAX_NUM_SOLDIERS && !fSoldierLight; cnt2++ )
{
if ( GetSoldier( &pSoldier, cnt2 ) )
{
if ( pSoldier->iLight == (INT32)cnt )
fSoldierLight = TRUE;
}
}
if( !fSoldierLight )
{ //save the light
FileWrite( hfile, &LightSprites[ cnt ], sizeof( LIGHT_SPRITE ), &uiBytesWritten );
ubStrLen = strlen( pLightNames[LightSprites[cnt].iTemplate] ) + 1 ;
FileWrite( hfile, &ubStrLen, 1, &uiBytesWritten );
FileWrite( hfile, pLightNames[LightSprites[cnt].iTemplate], ubStrLen, &uiBytesWritten );
}
}
}
}
void LoadMapLights( INT8 **hBuffer )
{
SGPPaletteEntry LColors[3];
UINT8 ubNumColors;
UINT16 usNumLights;
INT32 cnt;
CHAR8 str[30];
UINT8 ubStrLen;
LIGHT_SPRITE TmpLight;
INT32 iLSprite;
UINT32 uiHour;
BOOLEAN fPrimeTime = FALSE, fNightTime = FALSE;
//reset the lighting system, so that any current lights are toasted.
LightReset();
// read in the light colors!
LOADDATA( &ubNumColors, *hBuffer, 1 );
LOADDATA( LColors, *hBuffer, sizeof(SGPPaletteEntry)*ubNumColors );
LOADDATA( &usNumLights, *hBuffer, 2 );
ubNumColors = 1;
// ATE: OK, only regenrate if colors are different.....
//if ( LColors[0].peRed != gpLightColors[0].peRed ||
// LColors[0].peGreen != gpLightColors[0].peGreen ||
// LColors[0].peBlue != gpLightColors[0].peBlue )
{
LightSetColors( LColors, ubNumColors );
}
//Determine which lights are valid for the current time.
if( !gfEditMode )
{
uiHour = GetWorldHour();
if( uiHour >= NIGHT_TIME_LIGHT_START_HOUR || uiHour < NIGHT_TIME_LIGHT_END_HOUR )
{
fNightTime = TRUE;
}
if( uiHour >= PRIME_TIME_LIGHT_START_HOUR )
{
fPrimeTime = TRUE;
}
}
for( cnt = 0; cnt < usNumLights; cnt++ )
{
LOADDATA( &TmpLight, *hBuffer, sizeof( LIGHT_SPRITE ) );
LOADDATA( &ubStrLen, *hBuffer, 1 );
if( ubStrLen )
{
LOADDATA( str, *hBuffer, ubStrLen );
}
str[ ubStrLen ] = 0;
iLSprite = LightSpriteCreate( str, TmpLight.uiLightType );
//if this fails, then we will ignore the light.
// ATE: Don't add ANY lights of mapscreen util is on
if( iLSprite != -1 && guiCurrentScreen != MAPUTILITY_SCREEN )
{
if( !gfCaves || gfEditMode )
{
if( gfEditMode ||
TmpLight.uiFlags & LIGHT_PRIMETIME && fPrimeTime ||
TmpLight.uiFlags & LIGHT_NIGHTTIME && fNightTime ||
!(TmpLight.uiFlags & (LIGHT_PRIMETIME | LIGHT_NIGHTTIME)) )
{ //power only valid lights.
LightSpritePower( iLSprite, TRUE );
}
}
LightSpritePosition( iLSprite, TmpLight.iX, TmpLight.iY );
if( TmpLight.uiFlags & LIGHT_PRIMETIME )
LightSprites[ iLSprite ].uiFlags |= LIGHT_PRIMETIME;
else if( TmpLight.uiFlags & LIGHT_NIGHTTIME )
LightSprites[ iLSprite ].uiFlags |= LIGHT_NIGHTTIME;
}
}
}
BOOLEAN IsRoofVisibleForWireframe( INT16 sMapPos )
{
STRUCTURE * pStructure;
if ( !gfBasement )
{
pStructure = FindStructure( sMapPos, STRUCTURE_ROOF );
if ( pStructure != NULL )
{
return( TRUE );
}
}
else
{
//if ( InARoom( sMapPos, &ubRoom ) )
{
//if ( !( gpWorldLevelData[ sMapPos ].uiFlags & MAPELEMENT_REVEALED ) )
{
return( TRUE );
}
}
}
return( FALSE );
}