#include "builddefines.h" #ifdef PRECOMPILEDHEADERS #include "TileEngine All.h" #include "PreBattle Interface.h" #else #include "worlddef.h" #include "worlddat.h" #include #include #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 "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 //forward declarations of common classes to eliminate includes class OBJECTTYPE; class SOLDIERTYPE; #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( sGridNo, 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( INT16 sGridNo ) { UINT8 ubTerrainID; TILE_ELEMENT TileElem; LEVELNODE * pLand; STRUCTURE * pStructure; BOOLEAN fStructuresOnRoof; UINT8 ubDirLoop; /* */ if ( GridNoOnVisibleWorldTile( sGridNo ) ) { // check for land of a different height in adjacent locations for ( ubDirLoop = 0; ubDirLoop < 8; ubDirLoop++ ) { if ( gpWorldLevelData[ sGridNo ].sHeight != gpWorldLevelData[ sGridNo + DirectionInc( ubDirLoop ) ].sHeight ) { SET_CURRMOVEMENTCOST( ubDirLoop, TRAVELCOST_OBSTACLE ); } } // check for exit grids if ( ExitGridAtGridNo( sGridNo ) ) { 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( sGridNo, ubDirLoop, 0, TRAVELCOST_OFF_MAP ); SET_MOVEMENTCOST( sGridNo, ubDirLoop, 1, TRAVELCOST_OFF_MAP ); } if (gpWorldLevelData[sGridNo].pStructureHead == NULL) { return; } } if (gpWorldLevelData[sGridNo].pStructureHead != NULL) { // structures in tile // consider the land pLand = gpWorldLevelData[ sGridNo ].pLandHead; if ( pLand != NULL ) { // Set TEMPORARY cost here // Get from tile database TileElem = gTileDatabase[ pLand->usIndex ]; // Get terrain type ubTerrainID = gpWorldLevelData[sGridNo].ubTerrainID; // = GetTerrainType( (INT16)sGridNo ); for (ubDirLoop=0; ubDirLoop < NUM_WORLD_DIRECTIONS; ubDirLoop++) { SET_CURRMOVEMENTCOST( ubDirLoop, gTileTypeMovementCost[ ubTerrainID ] ); } } // now consider all structures pStructure = gpWorldLevelData[sGridNo].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( sGridNo - WORLD_COLS, NORTH, 0, TRAVELCOST_NONE ); SET_MOVEMENTCOST( sGridNo - WORLD_COLS + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo + 1, EAST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); FORCE_SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_NONE ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS - 1, SOUTHWEST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo - 1, WEST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo - 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( sGridNo - WORLD_COLS, NORTH, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo - WORLD_COLS + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE ); // make sure no obstacle costs exists before changing path cost to 0 if ( gubWorldMovementCosts[ sGridNo + 1 ][ EAST ][ 0 ] < TRAVELCOST_BLOCKED ) { FORCE_SET_MOVEMENTCOST( sGridNo + 1, EAST, 0, TRAVELCOST_NONE ); } SET_MOVEMENTCOST( sGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS - 1, SOUTHWEST, 0, TRAVELCOST_OBSTACLE ); if ( gubWorldMovementCosts[ sGridNo - 1 ][ WEST ][ 0 ] < TRAVELCOST_BLOCKED ) { FORCE_SET_MOVEMENTCOST( sGridNo - 1, WEST, 0, TRAVELCOST_NONE ); } SET_MOVEMENTCOST( sGridNo - 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( (INT16) (sGridNo - WORLD_COLS), STRUCTURE_OBSTACLE ) == FALSE && FindStructure( (INT16)(sGridNo + WORLD_COLS), STRUCTURE_OBSTACLE ) == FALSE ) { FORCE_SET_MOVEMENTCOST( sGridNo, NORTH, 0, TRAVELCOST_FENCE ); FORCE_SET_MOVEMENTCOST( sGridNo, SOUTH, 0, TRAVELCOST_FENCE ); } if ( FindStructure( (INT16)(sGridNo - 1), STRUCTURE_OBSTACLE ) == FALSE && FindStructure( (INT16)(sGridNo + 1), STRUCTURE_OBSTACLE ) == FALSE ) { FORCE_SET_MOVEMENTCOST( sGridNo, EAST, 0, TRAVELCOST_FENCE ); FORCE_SET_MOVEMENTCOST( sGridNo, 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( sGridNo + 1, NORTHEAST, 0, TRAVELCOST_WALL ); SET_MOVEMENTCOST( sGridNo + 1, EAST, 0, TRAVELCOST_DOOR_CLOSED_W ); SET_MOVEMENTCOST( sGridNo + 1, SOUTHEAST, 0, TRAVELCOST_WALL ); // corner SET_MOVEMENTCOST( sGridNo + 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( sGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_DOOR_OPEN_NW ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_DOOR_OPEN_NW ); SET_MOVEMENTCOST( sGridNo + 1, NORTHEAST, 0, TRAVELCOST_DOOR_OPEN_W_W ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_DOOR_OPEN_NW_W ); } break; case INSIDE_TOP_RIGHT: // doorpost SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_WALL ); SET_MOVEMENTCOST( sGridNo + 1,NORTHEAST, 0, TRAVELCOST_WALL ); // door SET_CURRMOVEMENTCOST( NORTH, TRAVELCOST_DOOR_OPEN_HERE ); SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_DOOR_OPEN_HERE ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_DOOR_OPEN_N ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_DOOR_OPEN_N ); SET_MOVEMENTCOST( sGridNo - 1, NORTHWEST, 0, TRAVELCOST_DOOR_OPEN_E ); SET_MOVEMENTCOST( sGridNo + 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( sGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_WALL ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_DOOR_CLOSED_N ) SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_WALL ); ; // corner SET_MOVEMENTCOST( sGridNo + 1 ,NORTHEAST, 0, TRAVELCOST_WALL ); } else { // door SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_DOOR_OPEN_N ); SET_CURRMOVEMENTCOST( WEST, TRAVELCOST_DOOR_OPEN_N ); SET_MOVEMENTCOST( sGridNo + 1, EAST, 0, TRAVELCOST_DOOR_OPEN_NW ); SET_MOVEMENTCOST( sGridNo + 1, NORTHEAST, 0, TRAVELCOST_DOOR_OPEN_NW ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_DOOR_OPEN_N_N ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_DOOR_OPEN_NW_N ); } break; case INSIDE_TOP_LEFT: // doorpost SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_WALL ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_WALL ); // corner SET_MOVEMENTCOST( sGridNo + 1 ,NORTHEAST, 0, TRAVELCOST_WALL ); // door SET_CURRMOVEMENTCOST( WEST, TRAVELCOST_DOOR_OPEN_HERE ); SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_DOOR_OPEN_HERE ); SET_MOVEMENTCOST( sGridNo + 1, EAST, 0, TRAVELCOST_DOOR_OPEN_W ); SET_MOVEMENTCOST( sGridNo + 1, SOUTHEAST, 0, TRAVELCOST_DOOR_OPEN_W ); SET_MOVEMENTCOST( sGridNo - WORLD_COLS, NORTHWEST, 0, TRAVELCOST_DOOR_OPEN_S ); SET_MOVEMENTCOST( sGridNo - 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( sGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_WALL ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_DOOR_CLOSED_N ); SET_MOVEMENTCOST( sGridNo + 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( sGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_DOOR_CLOSED_N); SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_DOOR_CLOSED_N); SET_MOVEMENTCOST( sGridNo + 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( sGridNo + 1, NORTHEAST, 0, TRAVELCOST_WALL ); SET_MOVEMENTCOST( sGridNo + 1, EAST, 0, TRAVELCOST_DOOR_CLOSED_W ); SET_MOVEMENTCOST( sGridNo + 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( sGridNo + 1, NORTHEAST, 0, TRAVELCOST_DOOR_CLOSED_W ); SET_MOVEMENTCOST( sGridNo + 1, EAST, 0, TRAVELCOST_DOOR_CLOSED_W ); SET_MOVEMENTCOST( sGridNo + 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( sGridNo + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_WALL ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_DOOR_CLOSED_N ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_WALL ); // DO CORNERS SET_MOVEMENTCOST( sGridNo - 1, NORTHWEST, 0, TRAVELCOST_WALL ); SET_MOVEMENTCOST( sGridNo + 1, NORTHEAST, 0, TRAVELCOST_WALL ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS - 1, SOUTHWEST, 0, TRAVELCOST_WALL ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_WALL ); //SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_OBSTACLE ); //SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_OBSTACLE ); //SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); //SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_OBSTACLE ); // corner //SET_MOVEMENTCOST( sGridNo + 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( sGridNo - 1, WEST, 0, TRAVELCOST_DOOR_OPEN_NE ); SET_MOVEMENTCOST( sGridNo - 1, NORTHWEST, 0, TRAVELCOST_WALL ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_DOOR_OPEN_N_N ); SET_MOVEMENTCOST( sGridNo + 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( sGridNo + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_DOOR_CLOSED_N ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_OBSTACLE ); // DO CORNERS SET_MOVEMENTCOST( sGridNo - 1, NORTHWEST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS - 1, SOUTHWEST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); // doorframe //SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_OBSTACLE ); //SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_OBSTACLE ); //SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); //SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_OBSTACLE ); // corner //SET_MOVEMENTCOST( sGridNo + 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( sGridNo - 1, WEST, 0, TRAVELCOST_DOOR_OPEN_E ); SET_MOVEMENTCOST( sGridNo - 1, SOUTHWEST, 0, TRAVELCOST_DOOR_OPEN_E ); SET_MOVEMENTCOST( sGridNo - WORLD_COLS, NORTHEAST, 0, TRAVELCOST_DOOR_OPEN_S ); SET_MOVEMENTCOST( sGridNo - 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( sGridNo + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo + 1, EAST, 0, TRAVELCOST_DOOR_CLOSED_W ); SET_MOVEMENTCOST( sGridNo + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE ); // DO CORNERS SET_MOVEMENTCOST( sGridNo - WORLD_COLS + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo - WORLD_COLS, NORTHWEST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_OBSTACLE ); //SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_OBSTACLE ); //SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_OBSTACLE ); //SET_MOVEMENTCOST( sGridNo + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); //SET_MOVEMENTCOST( sGridNo + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE ); // corner //SET_MOVEMENTCOST( sGridNo + 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( sGridNo - WORLD_COLS, NORTH, 0, TRAVELCOST_DOOR_OPEN_SW ); SET_MOVEMENTCOST( sGridNo - WORLD_COLS, NORTHWEST, 0, TRAVELCOST_DOOR_OPEN_SW ); SET_MOVEMENTCOST( sGridNo + 1, SOUTHEAST, 0, TRAVELCOST_DOOR_OPEN_W_W ); SET_MOVEMENTCOST( sGridNo - 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( sGridNo + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo + 1, EAST, 0, TRAVELCOST_DOOR_CLOSED_W ); SET_MOVEMENTCOST( sGridNo + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE ); // DO CORNERS SET_MOVEMENTCOST( sGridNo - WORLD_COLS + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo - WORLD_COLS, NORTHWEST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_OBSTACLE ); // doorframe /* SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_OBSTACLE ); SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo + 1,SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo + 1,NORTHEAST, 0, TRAVELCOST_OBSTACLE ); // corner SET_MOVEMENTCOST( sGridNo - 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( sGridNo - WORLD_COLS, NORTH, 0, TRAVELCOST_DOOR_OPEN_S ); SET_MOVEMENTCOST( sGridNo - WORLD_COLS, NORTHEAST, 0, TRAVELCOST_DOOR_OPEN_S ); SET_MOVEMENTCOST( sGridNo - 1, SOUTHWEST, 0, TRAVELCOST_DOOR_OPEN_E ); SET_MOVEMENTCOST( sGridNo - 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( sGridNo + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_DOOR_CLOSED_N ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_OBSTACLE ); // DO CORNERS SET_MOVEMENTCOST( sGridNo - 1, NORTHWEST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS - 1, SOUTHWEST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo + 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( sGridNo + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo + 1, EAST, 0, TRAVELCOST_DOOR_CLOSED_W ); SET_MOVEMENTCOST( sGridNo + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE ); // DO CORNERS SET_MOVEMENTCOST( sGridNo - WORLD_COLS + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo - WORLD_COLS, NORTHWEST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); SET_MOVEMENTCOST( sGridNo + 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( sGridNo + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_WALL ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_WALL ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_WALL ); // DO CORNERS SET_MOVEMENTCOST( sGridNo - 1, NORTHWEST, 0, TRAVELCOST_WALL ); SET_MOVEMENTCOST( sGridNo + 1, NORTHEAST, 0, TRAVELCOST_WALL ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS - 1, SOUTHWEST, 0, TRAVELCOST_WALL ); SET_MOVEMENTCOST( sGridNo + 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( sGridNo + 1, SOUTHEAST, 0, TRAVELCOST_WALL ); SET_MOVEMENTCOST( sGridNo + 1, EAST, 0, TRAVELCOST_WALL ); SET_MOVEMENTCOST( sGridNo + 1, NORTHEAST, 0, TRAVELCOST_WALL ); // DO CORNERS SET_MOVEMENTCOST( sGridNo - WORLD_COLS + 1, NORTHEAST, 0, TRAVELCOST_WALL ); SET_MOVEMENTCOST( sGridNo - WORLD_COLS, NORTHWEST, 0, TRAVELCOST_WALL ); SET_MOVEMENTCOST( sGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_WALL ); SET_MOVEMENTCOST( sGridNo + 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[ sGridNo ].pRoofHead != NULL)) { if (!fStructuresOnRoof) { for (ubDirLoop=0; ubDirLoop < 8; ubDirLoop++) { SET_MOVEMENTCOST( sGridNo, ubDirLoop, 1, TRAVELCOST_FLAT ); } } else { for (ubDirLoop=0; ubDirLoop < 8; ubDirLoop++) { SET_MOVEMENTCOST( sGridNo, ubDirLoop, 1, TRAVELCOST_OBSTACLE ); } } } else { for (ubDirLoop=0; ubDirLoop < 8; ubDirLoop++) { SET_MOVEMENTCOST( sGridNo, ubDirLoop, 1, TRAVELCOST_OBSTACLE ); } } } else { // NO STRUCTURES IN TILE // consider just the land // Get terrain type ubTerrainID = gpWorldLevelData[sGridNo].ubTerrainID; // = GetTerrainType( (INT16)sGridNo ); for (ubDirLoop=0; ubDirLoop < 8; ubDirLoop++) { SET_MOVEMENTCOST( sGridNo ,ubDirLoop, 0, gTileTypeMovementCost[ ubTerrainID ] ); } /* pLand = gpWorldLevelData[ sGridNo ].pLandHead; if ( pLand != NULL ) { // Set cost here // Get from tile database TileElem = gTileDatabase[ pLand->usIndex ]; // Get terrain type ubTerrainID = GetTerrainType( (INT16)sGridNo ); for (ubDirLoop=0; ubDirLoop < 8; ubDirLoop++) { SET_MOVEMENTCOST( sGridNo ,ubDirLoop, 0, gTileTypeMovementCost[ ubTerrainID ] ); } } */ // HIGHEST LEVEL if (gpWorldLevelData[ sGridNo ].pRoofHead != NULL) { for (ubDirLoop=0; ubDirLoop < 8; ubDirLoop++) { SET_MOVEMENTCOST( sGridNo, ubDirLoop, 1, TRAVELCOST_FLAT ); } } else { for (ubDirLoop=0; ubDirLoop < 8; ubDirLoop++) { SET_MOVEMENTCOST( sGridNo, ubDirLoop, 1, TRAVELCOST_OBSTACLE ); } } } } #define LOCAL_RADIUS 4 void RecompileLocalMovementCosts( INT16 sCentreGridNo ) { INT16 sGridNo; 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++ ) { sGridNo = MAPROWCOLTOPOS( sGridY, sGridX ); // times 2 for 2 levels, times 2 for UINT16s // memset( &(gubWorldMovementCosts[sGridNo]), 0, MAXDIR * 2 * 2 ); if (sGridNo < WORLD_MAX) { for( bDirLoop = 0; bDirLoop < MAXDIR; bDirLoop++) { gubWorldMovementCosts[sGridNo][bDirLoop][0] = 0; gubWorldMovementCosts[sGridNo][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++ ) { sGridNo = MAPROWCOLTOPOS( sGridY, sGridX ); if (sGridNo < WORLD_MAX) { CompileTileMovementCosts( sGridNo ); } } } } void RecompileLocalMovementCostsFromRadius( INT16 sCentreGridNo, INT8 bRadius ) { INT16 sGridNo; 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++ ) { sGridNo = MAPROWCOLTOPOS( sGridY, sGridX ); // times 2 for 2 levels, times 2 for UINT16s // memset( &(gubWorldMovementCosts[sGridNo]), 0, MAXDIR * 2 * 2 ); if (sGridNo < WORLD_MAX) { for( bDirLoop = 0; bDirLoop < MAXDIR; bDirLoop++) { gubWorldMovementCosts[sGridNo][bDirLoop][0] = 0; gubWorldMovementCosts[sGridNo][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++ ) { sGridNo = MAPROWCOLTOPOS( sGridY, sGridX ); if (sGridNo < WORLD_MAX) { CompileTileMovementCosts( sGridNo ); } } } } } 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 sGridNo; INT16 sGridX, sGridY; INT8 bDirLoop; for( sGridY = gsRecompileAreaTop; sGridY <= gsRecompileAreaBottom; sGridY++ ) { for( sGridX = gsRecompileAreaLeft; sGridX < gsRecompileAreaRight; sGridX++ ) { sGridNo = MAPROWCOLTOPOS( sGridY, sGridX ); if ( sGridNo < WORLD_MAX && gpWorldLevelData[ sGridNo ].ubExtFlags[0] & MAPELEMENT_EXT_RECALCULATE_MOVEMENT ) { // wipe MPs in this tile! for( bDirLoop = 0; bDirLoop < MAXDIR; bDirLoop++) { gubWorldMovementCosts[sGridNo][bDirLoop][0] = 0; gubWorldMovementCosts[sGridNo][bDirLoop][1] = 0; } // reset flag gpWorldLevelData[ sGridNo ].ubExtFlags[0] &= (~MAPELEMENT_EXT_RECALCULATE_MOVEMENT); } } } for( sGridY = gsRecompileAreaTop; sGridY <= gsRecompileAreaBottom; sGridY++ ) { for( sGridX = gsRecompileAreaLeft; sGridX <= gsRecompileAreaRight; sGridX++ ) { sGridNo = MAPROWCOLTOPOS( sGridY, sGridX ); if (sGridNo < WORLD_MAX) { CompileTileMovementCosts( sGridNo ); } } } } 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( ) { INT16 sGridNo; memset( gubWorldMovementCosts, 0, sizeof( gubWorldMovementCosts ) ); CompileWorldTerrainIDs(); for( sGridNo = 0; sGridNo < WORLD_MAX; sGridNo++ ) { CompileTileMovementCosts( sGridNo ); } } // 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_POD; //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 ); } if(gMapInformation.sCenterGridNo == -1 || (gMapInformation.sNorthGridNo == -1 && gMapInformation.sEastGridNo == -1 && gMapInformation.sSouthGridNo == -1 && gMapInformation.sWestGridNo == -1))//dnl { swprintf(gzErrorCatchString, L"SAVE ABORTED! Center entry point and at least one entry point (N,S,E,W) should be set."); gfErrorCatch = TRUE; FileClose(hfile); return(FALSE); } 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; float oldMajorMapVersion; UINT8 oldMinorMapVersion; //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, &oldMajorMapVersion, &oldMinorMapVersion ) ) //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. //ADB warning, even if the number of items is 0 we still need to store the position!!! //if( pSummary->usNumItems ) //{ pSummary->uiNumItemsPosition = pBuffer - pBufferHead - 4; //} //the size of WORLDITEM has changed at 6.27, 5.26 or earlier are outdated if (dMajorMapVersion >= 6.0 && ubMinorMapVersion > 26) { //Skip the contents of the world items. WORLDITEM dummyItem; for (int x = 0; x < pSummary->usNumItems; ++x) { dummyItem.Load(&pBuffer, dMajorMapVersion, ubMinorMapVersion); } } else { //ADB Shouldn't happen, we just saved as newest version //Skip the contents of the world items. pBuffer += sizeof( OLD_WORLDITEM_101 ) * 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 ) ); pSummary->MapInfo.ubMapVersion = gubMinorMapVersion; 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 priority.Load(&pBuffer, dMajorMapVersion, ubMinorMapVersion); 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; INT16 sMapIndex; BOOLEAN fExitGridFound; RenderProgressBar( 0, 98 ); //RenderProgressBar( 1, 98 ); LOADDATA( &cnt, pBuffer, 2 ); for( i = 0; i < cnt; i++ ) { LOADDATA( &sMapIndex, pBuffer, 2 ); LOADDATA( &exitGrid, pBuffer, 5 ); fExitGridFound = FALSE; for( loop = 0; loop < pSummary->ubNumExitGridDests; loop++ ) { if( pSummary->ExitGrid[ loop ].sGridNo == exitGrid.sGridNo && 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 ].sGridNo = exitGrid.sGridNo; 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, float* pMajorMapVersion, UINT8* pMinorMapVersion) { 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 ) ); if ( pMajorMapVersion ) { *pMajorMapVersion = dMajorMapVersion; } // Lesh: disable this because now we accept any version map //#ifdef RUSSIAN // if( dMajorMapVersion != 6.00 ) // { // return FALSE; // } //#endif LOADDATA( &ubMinorMapVersion, pBuffer, sizeof( UINT8 ) ); if (pMinorMapVersion) { *pMinorMapVersion = ubMinorMapVersion; } // 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 //ADB thankfully this isn't used, because the size has changed // 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 ) { //ADB what's this here for? commented out 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 //ADB Russian version of the game has some maps at version 6.0 while all others are 5.0 //so let's update! //if we are loading a 5.26 map (6.26 Russian) AND we are currently at 6.27 //( what would be 7.27 Russian except that we are about to fix this) //then read the data. if( dMajorMapVersion == 6.00 && ubMinorMapVersion < 27 && MAJOR_MAP_VERSION == 6.00) { UINT32 uiNums[37]; LOADDATA( uiNums, pBuffer, 37 * sizeof( UINT32 ) ); } //now the data is discarded and when saved, as 6.27, you won't have this problem! 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, dMajorMapVersion, ubMinorMapVersion ); 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, dMajorMapVersion, ubMinorMapVersion ); } 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 ); if(!(gMapInformation.sNorthGridNo == -1 && gMapInformation.sEastGridNo == -1 && gMapInformation.sSouthGridNo == -1 && gMapInformation.sWestGridNo == -1))//dnl just rough solution for skiping InitLoadedWorld if loaded map doesn't contain any entry point which lead into assertion 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 != NOBODY ) { if ( MercPtrs[ gusSelectedSoldier ]->bActive == FALSE ) { gusSelectedSoldier = NOBODY; } } 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 = NOBODY; 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 ); } } } // Reset attack busy since a militia might have been in the middle of radioing gTacticalStatus.ubAttackBusyCount = 0; 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( (INT16)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 ); }