Files
source/Editor/edit_sys.cpp
T

1448 lines
44 KiB
C++

// WANNE: EDTIOR: no changes
#ifdef PRECOMPILEDHEADERS
#include "Editor All.h"
#else
#include "builddefines.h"
#endif
#ifdef JA2EDITOR
#ifndef PRECOMPILEDHEADERS
#include "worlddef.h"
#include "worldman.h"
#include "smooth.h"
#include "newsmooth.h"
#include "edit_sys.h"
#include "editscreen.h"
#include "selectwin.h"
#include "EditorTerrain.h"
#include "EditorBuildings.h"
#include "EditorMercs.h"
#include "EditorDefines.h"
#include "Smoothing Utils.h"
#include "Cursor Modes.h"
#include "Render Fun.h"
#include "Isometric Utils.h"
#include "Editor Undo.h"
#include "Exit Grids.h"
#include "environment.h"
#include "Simple Render Utils.h"
#include "Road Smoothing.h"
#endif
BOOLEAN PasteHigherTextureFromRadius( INT32 iMapIndex, UINT32 uiNewType, UINT8 ubRadius );
BOOLEAN PasteExistingTexture( UINT32 iMapIndex, UINT16 usIndex );
BOOLEAN PasteExistingTextureFromRadius( INT32 iMapIndex, UINT16 usIndex, UINT8 ubRadius );
BOOLEAN SetLowerLandIndexWithRadius( INT32 iMapIndex, UINT32 uiNewType, UINT8 ubRadius, BOOLEAN fReplace );
void PasteTextureEx( INT16 sGridNo, UINT16 usType );
void PasteTextureFromRadiusEx( INT16 sGridNo, UINT16 usType, UINT8 ubRadius );
BOOLEAN gfWarning = FALSE;
BOOLEAN gfDoFill = FALSE;
UINT16 CurrentPaste = NO_TILE;
UINT16 gDebrisPaste = NO_TILE;
UINT16 gChangeElevation = FALSE;
UINT16 CurrentStruct = NO_TILE;
UINT32 gDoBanks = NO_BANKS;
UINT32 gDoCliffs = NO_CLIFFS;
//---------------------------------------------------------------------------------------------------------------
// QuickEraseMapTile
//
// Performs ersing operation when the DEL key is hit in the editor
//
void QuickEraseMapTile( UINT32 iMapIndex )
{
if ( iMapIndex >= 0x8000 )
return;
AddToUndoList( iMapIndex );
DeleteStuffFromMapTile( iMapIndex );
MarkWorldDirty();
}
//---------------------------------------------------------------------------------------------------------------
// DeleteStuffFromMapTile
//
// Common delete function for both QuickEraseMapTile and EraseMapTile
//
void DeleteStuffFromMapTile( UINT32 iMapIndex )
{
//UINT16 usUseIndex;
//UINT16 usType;
//UINT32 uiCheckType;
//UINT16 usDummy;
//GetTileType( gpWorldLevelData[ iMapIndex ].pLandHead->usIndex, &uiCheckType );
//RemoveLand( iMapIndex, gpWorldLevelData[ iMapIndex ].pLandHead->usIndex );
//SmoothTerrainRadius( iMapIndex, uiCheckType, 1, TRUE );
RemoveExitGridFromWorld( iMapIndex );
RemoveAllStructsOfTypeRange( iMapIndex, FIRSTTEXTURE, WIREFRAMES );
RemoveAllObjectsOfTypeRange( iMapIndex, FIRSTTEXTURE, WIREFRAMES );
RemoveAllShadowsOfTypeRange( iMapIndex, FIRSTTEXTURE, WIREFRAMES );
RemoveAllLandsOfTypeRange( iMapIndex, FIRSTTEXTURE, WIREFRAMES );
RemoveAllRoofsOfTypeRange( iMapIndex, FIRSTTEXTURE, WIREFRAMES );
RemoveAllOnRoofsOfTypeRange( iMapIndex, FIRSTTEXTURE, WIREFRAMES );
RemoveAllTopmostsOfTypeRange( iMapIndex, FIRSTTEXTURE, WIREFRAMES );
PasteRoomNumber( iMapIndex, 0 );
}
//---------------------------------------------------------------------------------------------------------------
// EraseMapTile
//
// Generic tile erasing function. Erases things from the world depending on the current drawing mode
//
void EraseMapTile( UINT32 iMapIndex )
{
INT32 iEraseMode;
UINT32 uiCheckType;
if ( iMapIndex >= 0x8000 )
return;
// Figure out what it is we are trying to erase
iEraseMode = iDrawMode - DRAW_MODE_ERASE;
switch ( iEraseMode )
{
case DRAW_MODE_NORTHPOINT:
case DRAW_MODE_WESTPOINT:
case DRAW_MODE_EASTPOINT:
case DRAW_MODE_SOUTHPOINT:
case DRAW_MODE_CENTERPOINT:
case DRAW_MODE_ISOLATEDPOINT:
SpecifyEntryPoint( iMapIndex );
break;
case DRAW_MODE_EXITGRID:
AddToUndoList( iMapIndex );
RemoveExitGridFromWorld( iMapIndex );
RemoveTopmost( (UINT16)iMapIndex, FIRSTPOINTERS8 );
break;
case DRAW_MODE_GROUND:
// Is there ground on this tile? if not, get out o here
if ( gpWorldLevelData[ iMapIndex ].pLandHead == NULL )
break;
// is there only 1 ground tile here? if so, get out o here
if ( gpWorldLevelData[ iMapIndex ].pLandHead->pNext == NULL )
break;
AddToUndoList( iMapIndex );
GetTileType( gpWorldLevelData[ iMapIndex ].pLandHead->usIndex, &uiCheckType );
RemoveLand( iMapIndex, gpWorldLevelData[ iMapIndex ].pLandHead->usIndex );
SmoothTerrainRadius( iMapIndex, uiCheckType, 1, TRUE );
break;
case DRAW_MODE_OSTRUCTS:
case DRAW_MODE_OSTRUCTS1:
case DRAW_MODE_OSTRUCTS2:
AddToUndoList( iMapIndex );
RemoveAllStructsOfTypeRange( iMapIndex, FIRSTOSTRUCT, LASTOSTRUCT );
RemoveAllStructsOfTypeRange( iMapIndex, FIRSTVEHICLE, SECONDVEHICLE );
RemoveAllStructsOfTypeRange( iMapIndex, FIRSTDEBRISSTRUCT, SECONDDEBRISSTRUCT );
RemoveAllStructsOfTypeRange( iMapIndex, NINTHOSTRUCT, TENTHOSTRUCT );
RemoveAllStructsOfTypeRange( iMapIndex, FIRSTLARGEEXPDEBRIS, SECONDLARGEEXPDEBRIS );
RemoveAllObjectsOfTypeRange( iMapIndex, DEBRIS2MISC, DEBRIS2MISC );
RemoveAllObjectsOfTypeRange( iMapIndex, ANOTHERDEBRIS, ANOTHERDEBRIS );
break;
case DRAW_MODE_DEBRIS:
AddToUndoList( iMapIndex );
RemoveAllObjectsOfTypeRange( iMapIndex, DEBRISROCKS, LASTDEBRIS );
RemoveAllObjectsOfTypeRange( iMapIndex, DEBRIS2MISC, DEBRIS2MISC );
RemoveAllObjectsOfTypeRange( iMapIndex, ANOTHERDEBRIS, ANOTHERDEBRIS );
break;
case DRAW_MODE_BANKS:
AddToUndoList( iMapIndex );
RemoveAllObjectsOfTypeRange( iMapIndex, FIRSTROAD, LASTROAD );
// Note, for this routine, cliffs are considered a subset of banks
RemoveAllStructsOfTypeRange( iMapIndex, ANIOSTRUCT, ANIOSTRUCT );
RemoveAllStructsOfTypeRange( iMapIndex, FIRSTCLIFF, LASTBANKS );
RemoveAllShadowsOfTypeRange( iMapIndex, FIRSTCLIFFSHADOW, LASTCLIFFSHADOW );
RemoveAllObjectsOfTypeRange( iMapIndex, FIRSTCLIFFHANG, LASTCLIFFHANG );
RemoveAllStructsOfTypeRange( iMapIndex, FENCESTRUCT, FENCESTRUCT );
RemoveAllShadowsOfTypeRange( iMapIndex, FENCESHADOW, FENCESHADOW );
break;
case DRAW_MODE_FLOORS:
AddToUndoList( iMapIndex );
RemoveAllLandsOfTypeRange( iMapIndex, FIRSTFLOOR, LASTFLOOR );
break;
case DRAW_MODE_ROOFS:
case DRAW_MODE_NEWROOF:
AddToUndoList( iMapIndex );
RemoveAllRoofsOfTypeRange( iMapIndex, FIRSTTEXTURE, LASTITEM );
RemoveAllOnRoofsOfTypeRange( iMapIndex, FIRSTTEXTURE, LASTITEM );
break;
case DRAW_MODE_WALLS:
case DRAW_MODE_DOORS:
case DRAW_MODE_WINDOWS:
case DRAW_MODE_BROKEN_WALLS:
AddToUndoList( iMapIndex );
RemoveAllStructsOfTypeRange( iMapIndex, FIRSTWALL, LASTWALL );
RemoveAllShadowsOfTypeRange( iMapIndex, FIRSTWALL, LASTWALL );
RemoveAllStructsOfTypeRange( iMapIndex, FIRSTDOOR, LASTDOOR );
RemoveAllShadowsOfTypeRange( iMapIndex, FIRSTDOORSHADOW, LASTDOORSHADOW );
break;
case DRAW_MODE_DECOR:
case DRAW_MODE_DECALS:
case DRAW_MODE_ROOM:
case DRAW_MODE_TOILET:
AddToUndoList( iMapIndex );
RemoveAllStructsOfTypeRange( iMapIndex, FIRSTWALLDECAL, LASTWALLDECAL );
RemoveAllStructsOfTypeRange( iMapIndex, FIFTHWALLDECAL, EIGTHWALLDECAL );
RemoveAllStructsOfTypeRange( iMapIndex, FIRSTDECORATIONS, LASTDECORATIONS );
RemoveAllStructsOfTypeRange( iMapIndex, FIRSTISTRUCT, LASTISTRUCT );
RemoveAllStructsOfTypeRange( iMapIndex, FIFTHISTRUCT, EIGHTISTRUCT );
RemoveAllStructsOfTypeRange( iMapIndex, FIRSTSWITCHES, FIRSTSWITCHES );
break;
case DRAW_MODE_CAVES:
AddToUndoList( iMapIndex );
RemoveAllStructsOfTypeRange( iMapIndex, FIRSTWALL, LASTWALL );
break;
case DRAW_MODE_ROOMNUM:
PasteRoomNumber( iMapIndex, 0 );
break;
case DRAW_MODE_ROADS:
RemoveAllObjectsOfTypeRange( iMapIndex, ROADPIECES, ROADPIECES );
break;
default:
//DeleteStuffFromMapTile( iMapIndex );
break;
}
}
//---------------------------------------------------------------------------------------------------------------
// PasteDebris
//
// Place some "debris" on the map at the current mouse coordinates. This function is called repeatedly if
// the current brush size is larger than 1 tile.
//
void PasteDebris( UINT32 iMapIndex )
{
UINT16 usUseIndex;
UINT16 usUseObjIndex;
INT32 iRandSelIndex;
// Get selection list for debris
pSelList = SelDebris;
pNumSelList = &iNumDebrisSelected;
if ( iMapIndex < 0x8000 )
{
AddToUndoList( iMapIndex );
// Remove any debris that is currently at this map location
if ( gpWorldLevelData[ iMapIndex ].pObjectHead != NULL )
{
RemoveAllObjectsOfTypeRange( iMapIndex, ANOTHERDEBRIS, FIRSTPOINTERS - 1 );
}
// Get a random debris from current selection
iRandSelIndex = GetRandomSelection( );
if ( iRandSelIndex != -1 )
{
// Add debris to the world
usUseIndex = pSelList[ iRandSelIndex ].usIndex;
usUseObjIndex = (UINT16)pSelList[ iRandSelIndex ].uiObject;
AddObjectToTail( iMapIndex, (UINT16)(gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex) );
}
}
}
void PasteSingleWall( UINT32 iMapIndex )
{
pSelList = SelSingleWall;
pNumSelList = &iNumWallsSelected;
PasteSingleWallCommon( iMapIndex );
}
void PasteSingleDoor( UINT32 iMapIndex )
{
pSelList = SelSingleDoor;
pNumSelList = &iNumDoorsSelected;
PasteSingleWallCommon( iMapIndex );
}
void PasteSingleWindow( UINT32 iMapIndex )
{
pSelList = SelSingleWindow;
pNumSelList = &iNumWindowsSelected;
PasteSingleWallCommon( iMapIndex );
}
void PasteSingleRoof( UINT32 iMapIndex )
{
pSelList = SelSingleRoof;
pNumSelList = &iNumRoofsSelected;
PasteSingleWallCommon( iMapIndex );
}
void PasteRoomNumber( UINT32 iMapIndex, UINT8 ubRoomNumber )
{
if( gubWorldRoomInfo[ iMapIndex ] != ubRoomNumber )
{
AddToUndoList( iMapIndex );
gubWorldRoomInfo[ iMapIndex ] = ubRoomNumber;
}
}
void PasteSingleBrokenWall( UINT32 iMapIndex )
{
UINT16 usIndex, usObjIndex, usTileIndex, usWallOrientation;
pSelList = SelSingleBrokenWall;
pNumSelList = &iNumBrokenWallsSelected;
usIndex = pSelList[ iCurBank ].usIndex;
usObjIndex = (UINT16)pSelList[ iCurBank ].uiObject;
usTileIndex = GetTileIndexFromTypeSubIndex( usObjIndex, usIndex, &usTileIndex );
GetWallOrientation( usTileIndex, &usWallOrientation );
if( usWallOrientation == INSIDE_TOP_LEFT || usWallOrientation == INSIDE_TOP_RIGHT )
EraseHorizontalWall( iMapIndex );
else
EraseVerticalWall( iMapIndex );
PasteSingleWallCommon( iMapIndex );
}
void PasteSingleDecoration( UINT32 iMapIndex )
{
pSelList = SelSingleDecor;
pNumSelList = &iNumDecorSelected;
PasteSingleWallCommon( iMapIndex );
}
void PasteSingleDecal( UINT32 iMapIndex )
{
pSelList = SelSingleDecal;
pNumSelList = &iNumDecalsSelected;
PasteSingleWallCommon( iMapIndex );
}
void PasteSingleFloor( UINT32 iMapIndex )
{
pSelList = SelSingleFloor;
pNumSelList = &iNumFloorsSelected;
PasteSingleWallCommon( iMapIndex );
}
void PasteSingleToilet( UINT32 iMapIndex )
{
pSelList = SelSingleToilet;
pNumSelList = &iNumToiletsSelected;
PasteSingleWallCommon( iMapIndex );
}
//---------------------------------------------------------------------------------------------------------------
// PasteSingleWallCommon
//
// Common paste routine for PasteSingleWall, PasteSingleDoor, PasteSingleDecoration, and
// PasteSingleDecor (above).
//
void PasteSingleWallCommon( UINT32 iMapIndex )
{
UINT16 usUseIndex;
UINT16 usUseObjIndex;
UINT16 usTempIndex;
if ( iMapIndex < 0x8000 )
{
AddToUndoList( iMapIndex );
usUseIndex = pSelList[ iCurBank ].usIndex;
usUseObjIndex = (UINT16)pSelList[ iCurBank ].uiObject;
// TEMP STUFF FOR ONROOF THINGS!
if ( (usUseObjIndex >= FIRSTONROOF) && (usUseObjIndex <= SECONDONROOF ) )
{
// Add to onroof section!
AddOnRoofToTail( iMapIndex, (UINT16)(gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex) );
if ( gTileDatabase[ (UINT16)(gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex) ].sBuddyNum != -1 )
{
AddOnRoofToTail( iMapIndex, gTileDatabase[ (UINT16)(gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex) ].sBuddyNum );
}
return;
}
// Make sure A-frames are on roof level!
if ( ( usUseIndex >= WALL_AFRAME_START && usUseIndex <= WALL_AFRAME_END ) )
{
AddRoofToTail( iMapIndex, (UINT16)(gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex) );
return;
}
if ( (usUseObjIndex >= FIRSTDOOR) && (usUseObjIndex <= LASTDOOR) )
{
// PLace shadow for doors
if( !gfBasement )
AddExclusiveShadow( iMapIndex, (UINT16)(gTileTypeStartIndex[ usUseObjIndex - FIRSTDOOR + FIRSTDOORSHADOW ] + usUseIndex ) );
}
// Is it a wall?
if ( ((usUseObjIndex >= FIRSTWALL) && (usUseObjIndex <= LASTWALL)) )
{
// ATE If it is a wall shadow, place differenty!
if ( usUseIndex == 29 || usUseIndex == 30 )
{
if( !gfBasement )
AddExclusiveShadow( iMapIndex, (UINT16)(gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex) );
}
else
{
// Slap down wall/window/door/decoration (no smoothing)
AddWallToStructLayer( iMapIndex, (UINT16)(gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex), TRUE );
}
}
// Is it a door/window/decoration?
else if ( ( (usUseObjIndex >= FIRSTDOOR) && (usUseObjIndex <= LASTDOOR)) ||
((usUseObjIndex >= FIRSTDECORATIONS) && (usUseObjIndex <= LASTDECORATIONS)) )
{
// Slap down wall/window/door/decoration (no smoothing)
AddWallToStructLayer( iMapIndex, (UINT16)(gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex), TRUE );
}
else if ( ((usUseObjIndex >= FIRSTROOF) && (usUseObjIndex <= LASTROOF)) ||
((usUseObjIndex >= FIRSTSLANTROOF) && (usUseObjIndex <= LASTSLANTROOF)) )
{
// Put a roof on this tile (even if nothing else is here)
RemoveAllRoofsOfTypeRange( iMapIndex, FIRSTROOF, LASTROOF );
AddRoofToTail( iMapIndex, (UINT16)(gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex) );
}
else if ( (usUseObjIndex >= FIRSTFLOOR) && (usUseObjIndex <= LASTFLOOR) )
{
// Drop a floor on this tile
if ( TypeExistsInLandLayer( iMapIndex, usUseObjIndex, &usTempIndex ) )
RemoveLand( iMapIndex, usTempIndex );
AddLandToHead( iMapIndex, (UINT16)(gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex) );
}
else if( usUseObjIndex >= FIRSTWALLDECAL && usUseObjIndex <= LASTWALLDECAL ||
usUseObjIndex >= FIFTHWALLDECAL && usUseObjIndex <= EIGTHWALLDECAL )
{
// Plop a decal here
RemoveAllStructsOfTypeRange( iMapIndex, FIRSTWALLDECAL, LASTWALLDECAL );
RemoveAllStructsOfTypeRange( iMapIndex, FIFTHWALLDECAL, EIGTHWALLDECAL );
AddStructToTail( iMapIndex, (UINT16)( gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex ) );
}
else if ( usUseObjIndex >= FIRSTISTRUCT && usUseObjIndex <= LASTISTRUCT ||
usUseObjIndex >= FIFTHISTRUCT && usUseObjIndex <= EIGHTISTRUCT )
{
AddStructToHead( iMapIndex, (UINT16)( gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex ) );
}
else if( usUseObjIndex == FIRSTSWITCHES )
{
AddStructToTail( iMapIndex, (UINT16)( gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex ) );
}
}
}
//---------------------------------------------------------------------------------------------------------------
// GetRandomIndexByRange
//
// Returns a randomly picked object index given the current selection list, and the type or types of objects we want
// from that list. If no such objects are in the list, we return 0xffff (-1).
UINT16 GetRandomIndexByRange( UINT16 usRangeStart, UINT16 usRangeEnd )
{
UINT16 usPickList[50];
UINT16 usNumInPickList;
UINT16 usWhich;
UINT16 usObject;
// Get a list of valid object to select from
usNumInPickList = 0;
for ( usWhich = 0; usWhich < *pNumSelList; usWhich++ )
{
usObject = (UINT16)pSelList[ usWhich ].uiObject;
if ( (usObject >= usRangeStart) && (usObject <= usRangeEnd) )
{
usPickList[ usNumInPickList ] = usObject;
usNumInPickList++;
}
}
return ( usNumInPickList ) ? usPickList[ rand() % usNumInPickList ] : 0xffff;
}
UINT16 GetRandomTypeByRange( UINT16 usRangeStart, UINT16 usRangeEnd )
{
UINT16 usPickList[50];
UINT16 usNumInPickList;
UINT16 i;
UINT16 usObject;
UINT32 uiType;
// Get a list of valid object to select from
usNumInPickList = 0;
for ( i = 0; i < *pNumSelList; i++ )
{
usObject = (UINT16)pSelList[ i ].uiObject;
if ( (usObject >= usRangeStart) && (usObject <= usRangeEnd) )
{
GetTileType( usObject, &uiType );
usPickList[ usNumInPickList ] = (UINT16)uiType;
usNumInPickList++;
}
}
return ( usNumInPickList ) ? usPickList[ rand() % usNumInPickList ] : 0xffff;
}
//---------------------------------------------------------------------------------------------------------------
// PasteStructure (See also PasteStructure1, PasteStructure2, and PasteStructureCommon)
//
// Puts a structure (trees, trucks, etc.) into the world
//
void PasteStructure( UINT32 iMapIndex )
{
pSelList = SelOStructs;
pNumSelList = &iNumOStructsSelected;
PasteStructureCommon( iMapIndex );
}
//---------------------------------------------------------------------------------------------------------------
// PasteStructure1 (See also PasteStructure, PasteStructure2, and PasteStructureCommon)
//
// Puts a structure (trees, trucks, etc.) into the world
//
void PasteStructure1( UINT32 iMapIndex )
{
pSelList = SelOStructs1;
pNumSelList = &iNumOStructs1Selected;
PasteStructureCommon( iMapIndex );
}
//---------------------------------------------------------------------------------------------------------------
// PasteStructure2 (See also PasteStructure, PasteStructure1, and PasteStructureCommon)
//
// Puts a structure (trees, trucks, etc.) into the world
//
void PasteStructure2( UINT32 iMapIndex )
{
pSelList = SelOStructs2;
pNumSelList = &iNumOStructs2Selected;
PasteStructureCommon( iMapIndex );
}
//---------------------------------------------------------------------------------------------------------------
// PasteStructureCommon
//
// This is the main (common) structure pasting function. The above three wrappers are only required because they
// each use different selection lists. Other than that, they are COMPLETELY identical.
//
void PasteStructureCommon( UINT32 iMapIndex )
{
BOOLEAN fDoPaste = FALSE;
UINT32 fHeadType;
UINT16 usUseIndex;
UINT16 usUseObjIndex;
INT32 iRandSelIndex;
BOOLEAN fOkayToAdd;
if ( iMapIndex < 0x8000 )
{
/*
if ( gpWorldLevelData[ iMapIndex ].pStructHead != NULL )
{
fDoPaste = FALSE;
}
else
{
// Nothing is here, paste
fDoPaste = TRUE;
}
*/
if ( /*fDoPaste &&*/ iMapIndex < 0x8000 )
{
iRandSelIndex = GetRandomSelection( );
if ( iRandSelIndex == -1 )
{
return;
}
AddToUndoList( iMapIndex );
usUseIndex = pSelList[ iRandSelIndex ].usIndex;
usUseObjIndex = (UINT16)pSelList[ iRandSelIndex ].uiObject;
// Check with Structure Database (aka ODB) if we can put the object here!
fOkayToAdd = OkayToAddStructureToWorld( (INT16)iMapIndex, 0, gTileDatabase[ (gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex) ].pDBStructureRef, INVALID_STRUCTURE_ID );
if ( fOkayToAdd || (gTileDatabase[ (gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex) ].pDBStructureRef == NULL) )
{
// Actual structure info is added by the functions below
AddStructToHead( iMapIndex, (UINT16)(gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex) );
// For now, adjust to shadows by a hard-coded amount,
// Add mask if in long grass
GetLandHeadType( iMapIndex, &fHeadType );
}
}
}
else if ( CurrentStruct == ERASE_TILE && iMapIndex < 0x8000 )
{
RemoveAllStructsOfTypeRange( iMapIndex, FIRSTOSTRUCT, LASTOSTRUCT );
RemoveAllShadowsOfTypeRange( iMapIndex, FIRSTSHADOW, LASTSHADOW );
}
}
//---------------------------------------------------------------------------------------------------------------
// PasteBanks
//
// Places a river bank or cliff into the world
//
void PasteBanks( UINT32 iMapIndex, UINT16 usStructIndex , BOOLEAN fReplace)
{
BOOLEAN fDoPaste = FALSE;
UINT16 usUseIndex;
UINT16 usUseObjIndex;
UINT16 usIndex;
pSelList = SelBanks;
pNumSelList = &iNumBanksSelected;
usUseIndex = pSelList[ iCurBank ].usIndex;
usUseObjIndex = (UINT16)pSelList[ iCurBank ].uiObject;
if ( iMapIndex < 0x8000 )
{
fDoPaste = TRUE;
if ( gpWorldLevelData[ iMapIndex ].pStructHead != NULL )
{
// CHECK IF THE SAME TILE IS HERE
if ( gpWorldLevelData[ iMapIndex ].pStructHead->usIndex == (UINT16)( gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex ) )
{
fDoPaste = FALSE;
}
}
else
{
// Nothing is here, paste
fDoPaste = TRUE;
}
if ( fDoPaste )
{
usIndex = gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex;
AddToUndoList( iMapIndex );
{
if ( usUseObjIndex == FIRSTROAD )
{
AddObjectToHead( iMapIndex, (UINT16)( gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex ) );
}
else
{
AddStructToHead( iMapIndex, (UINT16)( gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex ) );
// Add shadows
if ( !gfBasement && usUseObjIndex == FIRSTCLIFF )
{
//AddShadowToHead( iMapIndex, (UINT16)( gTileTypeStartIndex[ usUseObjIndex - FIRSTCLIFF + FIRSTCLIFFSHADOW ] + usUseIndex ) );
AddObjectToHead( iMapIndex, (UINT16)( gTileTypeStartIndex[ usUseObjIndex - FIRSTCLIFF + FIRSTCLIFFHANG ] + usUseIndex ) );
}
}
}
}
}
}
void PasteRoads( UINT32 iMapIndex )
{
UINT16 usUseIndex;
pSelList = SelRoads;
pNumSelList = &iNumRoadsSelected;
usUseIndex = pSelList[ iCurBank ].usIndex;
PlaceRoadMacroAtGridNo( iMapIndex, usUseIndex );
}
//---------------------------------------------------------------------------------------------------------------
// PasteTexture
//
// Puts a ground texture in the world. Ground textures are then "smoothed" in order to blend the edges with one
// another. The current drawing brush also affects this function.
//
void PasteTexture( UINT32 iMapIndex )
{
ChooseWeightedTerrainTile(); //Kris
PasteTextureCommon( iMapIndex );
}
//---------------------------------------------------------------------------------------------------------------
// PasteTextureCommon
//
// The PasteTexture function calls this one to actually put a ground tile down. If the brush size is larger than
// one tile, then the above function will call this one and indicate that they should all be placed into the undo
// stack as the same undo command.
//
void PasteTextureCommon( UINT32 iMapIndex )
{
UINT8 ubLastHighLevel;
UINT16 usTileIndex;
//UINT16 Dummy;
if ( CurrentPaste != NO_TILE && iMapIndex < 0x8000 )
{
// Set undo, then set new
AddToUndoList( iMapIndex );
if ( CurrentPaste == DEEPWATERTEXTURE )
{
// IF WE ARE PASTING DEEP WATER AND WE ARE NOT OVER WATER, IGNORE!
if ( TypeExistsInLandLayer( iMapIndex, REGWATERTEXTURE, &usTileIndex ) )
{
if ( !gTileDatabase[ usTileIndex ].ubFullTile )
{
return;
}
}
else
{
return;
}
}
// Don't draw over floors
if ( TypeRangeExistsInLandLayer( iMapIndex, FIRSTFLOOR, FOURTHFLOOR, &usTileIndex ) )
{
return;
}
// Compare heights and do appropriate action
if ( AnyHeigherLand( iMapIndex, CurrentPaste, &ubLastHighLevel ) )
{
// Here we do the following:
// - Remove old type from layer
// - Smooth World with old type
// - Add a 3 by 3 square of new type at head
// - Smooth World with new type
PasteHigherTexture( iMapIndex, CurrentPaste );
}
else
{
PasteTextureEx( (INT16)iMapIndex, CurrentPaste );
SmoothTerrainRadius( iMapIndex, CurrentPaste, 1, TRUE );
}
}
}
//---------------------------------------------------------------------------------------------------------------
// PasteHigherTexture
//
// Some ground textures should be placed "above" others. That is, grass needs to be placed "above" sand etc.
// This function performs the appropriate actions.
//
void PasteHigherTexture( UINT32 iMapIndex, UINT32 fNewType )
{
UINT16 NewTile;
UINT8 ubLastHighLevel;
UINT32 *puiDeletedTypes = NULL;
UINT8 ubNumTypes;
UINT8 cnt;
// Here we do the following:
// - Remove old type from layer
// - Smooth World with old type
// - Add a 3 by 3 square of new type at head
// - Smooth World with new type
//if ( iMapIndex < 0x8000 && TypeRangeExistsInLandLayer( iMapIndex, FIRSTFLOOR, LASTFLOOR, &NewTile ) )
//ATE: DONOT DO THIS!!!!!!! - I know what was intended - not to draw over floors - this
// I don't know is the right way to do it!
//return;
if ( iMapIndex < 0x8000 && AnyHeigherLand( iMapIndex, fNewType, &ubLastHighLevel ))
{
AddToUndoList( iMapIndex );
// - For all heigher level, remove
RemoveHigherLandLevels( iMapIndex, fNewType, &puiDeletedTypes, &ubNumTypes );
// Set with a radius of 1 and smooth according to height difference
SetLowerLandIndexWithRadius( iMapIndex, fNewType, 1 , TRUE );
// Smooth all deleted levels
for ( cnt = 0; cnt < ubNumTypes; cnt++ )
{
SmoothTerrainRadius( iMapIndex, puiDeletedTypes[ cnt ], 1, TRUE );
}
MemFree( puiDeletedTypes );
}
else if ( iMapIndex < 0x8000 )
{
AddToUndoList( iMapIndex );
GetTileIndexFromTypeSubIndex( fNewType, REQUIRES_SMOOTHING_TILE, &NewTile );
SetLandIndex( iMapIndex, NewTile, fNewType, FALSE );
// Smooth item then adding here
SmoothTerrain( iMapIndex, fNewType, &NewTile, FALSE );
if ( NewTile != NO_TILE )
{
// Change tile
SetLandIndex( iMapIndex, NewTile, fNewType, FALSE );
}
}
}
//---------------------------------------------------------------------------------------------------------------
// PasteHigherTextureFromRadius
//
// Like above function except it performs it's operation on a redial area.
//
BOOLEAN PasteHigherTextureFromRadius( INT32 iMapIndex, UINT32 uiNewType, UINT8 ubRadius )
{
INT16 sTop, sBottom;
INT16 sLeft, sRight;
INT16 cnt1, cnt2;
INT32 iNewIndex;
INT32 iXPos,iYPos;
// Determine start and end indicies and num rows
sTop = ubRadius;
sBottom = -ubRadius;
sLeft = -ubRadius;
sRight = ubRadius;
iXPos = (iMapIndex % WORLD_COLS);
iYPos = (iMapIndex - iXPos) / WORLD_COLS;
if ( (iXPos + (INT32)sLeft) < 0 )
sLeft = (INT16)(-iXPos);
if ( (iXPos + (INT32)sRight) >= WORLD_COLS )
sRight = (INT16)(WORLD_COLS - iXPos - 1);
if ( (iYPos + (INT32)sTop) >= WORLD_ROWS )
sTop = (INT16)(WORLD_ROWS - iYPos - 1);
if ( (iYPos + (INT32)sBottom) < 0 )
sBottom = (INT16)(-iYPos);
if ( iMapIndex >= 0x8000 )
return (FALSE);
for( cnt1 = sBottom; cnt1 <= sTop; cnt1++ )
{
for( cnt2 = sLeft; cnt2 <= sRight; cnt2++ )
{
iNewIndex = iMapIndex + ( WORLD_COLS * cnt1 ) + cnt2;
PasteHigherTexture( iNewIndex, uiNewType );
}
}
return( TRUE );
}
//---------------------------------------------------------------------------------------------------------------
// PasteExistingTexture
//
BOOLEAN PasteExistingTexture( UINT32 iMapIndex, UINT16 usIndex )
{
UINT32 uiNewType;
UINT16 usNewIndex;
//UINT16 Dummy;
// If here, we want to make, esentially, what is a type in
// a level other than TOP-MOST the TOP-MOST level.
// We should:
// - remove what was top-most
// - re-adjust the world to reflect missing top-most peice
if ( iMapIndex >= 0x8000 )
return ( FALSE );
//if ( TypeRangeExistsInLandLayer( iMapIndex, FIRSTFLOOR, LASTFLOOR, &Dummy ) )
// return( FALSE );
// Get top tile index
// Remove all land peices except
GetTileType( usIndex, &uiNewType );
DeleteAllLandLayers( iMapIndex );
// ADD BASE LAND AT LEAST!
usNewIndex = (UINT16)(rand( ) % 10 );
// Adjust for type
usNewIndex += gTileTypeStartIndex[ gCurrentBackground ];
// Set land index
AddLandToHead( iMapIndex, usNewIndex );
SetLandIndex( iMapIndex, usIndex, uiNewType, FALSE );
// ATE: Set this land peice to require smoothing again!
SmoothAllTerrainTypeRadius( iMapIndex, 2, TRUE );
return( TRUE );
}
//---------------------------------------------------------------------------------------------------------------
// PasteExistingTextureFromRadius
//
// As above, but on a radial area
//
BOOLEAN PasteExistingTextureFromRadius( INT32 iMapIndex, UINT16 usIndex, UINT8 ubRadius )
{
INT16 sTop, sBottom;
INT16 sLeft, sRight;
INT16 cnt1, cnt2;
INT32 iNewIndex;
INT32 leftmost;
// Determine start end end indicies and num rows
sTop = ubRadius;
sBottom = -ubRadius;
sLeft = - ubRadius;
sRight = ubRadius;
if ( iMapIndex >= 0x8000 )
return ( FALSE );
for( cnt1 = sBottom; cnt1 <= sTop; cnt1++ )
{
leftmost = ( ( iMapIndex + ( WORLD_COLS * cnt1 ) )/ WORLD_COLS ) * WORLD_COLS;
for( cnt2 = sLeft; cnt2 <= sRight; cnt2++ )
{
iNewIndex = iMapIndex + ( WORLD_COLS * cnt1 ) + cnt2;
if ( iNewIndex >=0 && iNewIndex < WORLD_MAX &&
iNewIndex >= leftmost && iNewIndex < ( leftmost + WORLD_COLS ) )
{
AddToUndoList( iMapIndex );
PasteExistingTexture( iNewIndex, usIndex );
}
}
}
return( TRUE );
}
//---------------------------------------------------------------------------------------------------------------
// SetLowerLandIndexWithRadius
//
// Puts a land index "under" an existing ground texture. Affects a radial area.
//
BOOLEAN SetLowerLandIndexWithRadius( INT32 iMapIndex, UINT32 uiNewType, UINT8 ubRadius, BOOLEAN fReplace )
{
UINT16 usTempIndex;
INT16 sTop, sBottom;
INT16 sLeft, sRight;
INT16 cnt1, cnt2;
INT32 iNewIndex;
BOOLEAN fDoPaste = FALSE;
INT32 leftmost;
UINT8 ubLastHighLevel;
UINT32 *puiSmoothTiles = NULL;
INT16 sNumSmoothTiles = 0;
UINT16 usTemp;
UINT16 NewTile; //,Dummy;
// Determine start end end indicies and num rows
sTop = ubRadius;
sBottom = -ubRadius;
sLeft = - ubRadius;
sRight = ubRadius;
if ( iMapIndex >= 0x8000 )
return ( FALSE );
for( cnt1 = sBottom; cnt1 <= sTop; cnt1++ )
{
leftmost = ( ( iMapIndex + ( WORLD_COLS * cnt1 ) )/ WORLD_COLS ) * WORLD_COLS;
for( cnt2 = sLeft; cnt2 <= sRight; cnt2++ )
{
iNewIndex = iMapIndex + ( WORLD_COLS * cnt1 ) + cnt2;
if ( iNewIndex >=0 && iNewIndex < WORLD_MAX &&
iNewIndex >= leftmost && iNewIndex < ( leftmost + WORLD_COLS ) )
{
if ( fReplace )
{
fDoPaste = TRUE;
}
else
{
if ( TypeExistsInLandLayer( iNewIndex, uiNewType, &usTempIndex ) )
{
fDoPaste = TRUE;
}
}
//if ( fDoPaste && !TypeRangeExistsInLandLayer( iMapIndex, FIRSTFLOOR, LASTFLOOR, &Dummy ) )
if ( fDoPaste )
{
if ( iMapIndex == iNewIndex )
{
AddToUndoList( iMapIndex );
// Force middle one to NOT smooth, and set to random 'full' tile
usTemp = ( rand( ) % 10 ) + 1;
GetTileIndexFromTypeSubIndex( uiNewType, usTemp, &NewTile );
SetLandIndex( iNewIndex, NewTile, uiNewType, FALSE );
}
else if ( AnyHeigherLand( iNewIndex, uiNewType, &ubLastHighLevel ) )
{
AddToUndoList( iMapIndex );
// Force middle one to NOT smooth, and set to random 'full' tile
usTemp = ( rand( ) % 10 ) + 1;
GetTileIndexFromTypeSubIndex( uiNewType, usTemp, &NewTile );
SetLandIndex( iNewIndex, NewTile, uiNewType, FALSE );
}
else
{
AddToUndoList( iMapIndex );
// Set tile to 'smooth target' tile
GetTileIndexFromTypeSubIndex( uiNewType, REQUIRES_SMOOTHING_TILE, &NewTile );
SetLandIndex( iNewIndex, NewTile, uiNewType, FALSE );
// If we are top-most, add to smooth list
sNumSmoothTiles++;
puiSmoothTiles = (UINT32 *) MemRealloc( puiSmoothTiles, sNumSmoothTiles * sizeof( UINT32 ) );
puiSmoothTiles[ sNumSmoothTiles-1 ] = iNewIndex;
}
}
}
}
}
// Once here, smooth any tiles that need it
if ( sNumSmoothTiles > 0 )
{
for ( cnt1 = 0; cnt1 < sNumSmoothTiles; cnt1++ )
{
SmoothTerrainRadius( puiSmoothTiles[ cnt1 ], uiNewType, 10, FALSE );
}
MemFree( puiSmoothTiles );
}
return( TRUE );
}
// ATE FIXES
void PasteTextureEx( INT16 sGridNo, UINT16 usType )
{
UINT16 usIndex;
UINT8 ubTypeLevel;
UINT16 NewTile;
// CHECK IF THIS TEXTURE EXISTS!
if ( TypeExistsInLandLayer( sGridNo, usType, &usIndex ) )
{
if ( GetTypeLandLevel( sGridNo, usType, &ubTypeLevel ) )
{
// If top-land , do not change
if ( ubTypeLevel != LANDHEAD )
{
PasteExistingTexture( sGridNo, usIndex );
}
}
}
else
{
// Fill with just first tile, smoothworld() will pick proper piece later
GetTileIndexFromTypeSubIndex( usType, REQUIRES_SMOOTHING_TILE, &NewTile );
SetLandIndex( sGridNo, NewTile, usType, FALSE );
}
}
void PasteTextureFromRadiusEx( INT16 sGridNo, UINT16 usType, UINT8 ubRadius )
{
INT16 sTop, sBottom;
INT16 sLeft, sRight;
INT16 cnt1, cnt2;
INT32 iNewIndex;
INT32 leftmost;
// Determine start end end indicies and num rows
sTop = ubRadius;
sBottom = -ubRadius;
sLeft = - ubRadius;
sRight = ubRadius;
if ( sGridNo >= 0x8000 )
return;
for( cnt1 = sBottom; cnt1 <= sTop; cnt1++ )
{
leftmost = ( ( sGridNo + ( WORLD_COLS * cnt1 ) )/ WORLD_COLS ) * WORLD_COLS;
for( cnt2 = sLeft; cnt2 <= sRight; cnt2++ )
{
iNewIndex = sGridNo + ( WORLD_COLS * cnt1 ) + cnt2;
if ( iNewIndex >=0 && iNewIndex < WORLD_MAX &&
iNewIndex >= leftmost && iNewIndex < ( leftmost + WORLD_COLS ) )
{
PasteTextureEx( sGridNo, usType );
}
}
}
return;
}
// FUNCTION TO GIVE NEAREST GRIDNO OF A CLIFF
#define LAND_DROP_1 FIRSTCLIFF1
#define LAND_DROP_2 FIRSTCLIFF11
#define LAND_DROP_3 FIRSTCLIFF12
#define LAND_DROP_4 FIRSTCLIFF15
#define LAND_DROP_5 FIRSTCLIFF8
void RaiseWorldLand( )
{
INT32 cnt;
UINT32 sTempGridNo;
LEVELNODE *pStruct;
TILE_ELEMENT *pTileElement;
BOOLEAN fRaise;
BOOLEAN fRaiseSet;
BOOLEAN fSomethingRaised = FALSE;
UINT8 ubLoop;
UINT16 usIndex;
BOOLEAN fStopRaise = FALSE;
INT32 iCounterA = 0, iCounterB = 0;
INT32 iStartNumberOfRaises = 0;
INT32 iNumberOfRaises = 0;
BOOLEAN fAboutToRaise = FALSE;
fRaise=FALSE;
fRaiseSet=FALSE;
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
gpWorldLevelData[cnt].uiFlags &= (~MAPELEMENT_RAISE_LAND_START );
gpWorldLevelData[cnt].uiFlags &= (~MAPELEMENT_RAISE_LAND_END );
}
for ( cnt = 0; cnt < WORLD_MAX; cnt++ )
{
// Get Structure levelnode
pStruct = gpWorldLevelData[ cnt ].pStructHead;
gpWorldLevelData[cnt].sHeight=0;
while( pStruct )
{
pTileElement = &(gTileDatabase[ pStruct->usIndex ]);
if (pTileElement->fType==FIRSTCLIFF)
{
fSomethingRaised = TRUE;
// DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("Cliff found at count=%d",cnt));
if( pTileElement->ubNumberOfTiles > 1 )
{
// DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("Cliff has %d children", pTileElement->ubNumberOfTiles));
for (ubLoop = 0; ubLoop < pTileElement->ubNumberOfTiles; ubLoop++)
{
usIndex=pStruct->usIndex;
// need means to turn land raising on and off based on the tile ID and the offset in the
// tile database when reading into the mapsystem
// turning off of land raising can only be done
// presently by CLIFF object/tileset 1
// so simply detect this tile set and turn off instead of on
// element 1 is 12 tiles and is unique
sTempGridNo = cnt + pTileElement->pTileLocData[ubLoop].bTileOffsetX + pTileElement->pTileLocData[ubLoop].bTileOffsetY * WORLD_COLS;
// Check for valid gridno
if ( OutOfBounds( (INT16)cnt, (INT16)sTempGridNo ) )
{
continue;
}
//if (pTileElement->ubNumberOfTiles==10)
if((usIndex==LAND_DROP_1)||(usIndex==LAND_DROP_2) ||(usIndex==LAND_DROP_4))
{
gpWorldLevelData[sTempGridNo].uiFlags &= (~MAPELEMENT_RAISE_LAND_START );
gpWorldLevelData[sTempGridNo].uiFlags |= MAPELEMENT_RAISE_LAND_END;
}
else if( ( usIndex==LAND_DROP_5 ) && ( ubLoop == 4 ) )
{
gpWorldLevelData[sTempGridNo].uiFlags &= (~MAPELEMENT_RAISE_LAND_START );
gpWorldLevelData[sTempGridNo].uiFlags |= MAPELEMENT_RAISE_LAND_END;
if( !( gpWorldLevelData[sTempGridNo + 1 ].uiFlags & MAPELEMENT_RAISE_LAND_START ) )
{
gpWorldLevelData[sTempGridNo + 1].uiFlags |= MAPELEMENT_RAISE_LAND_START;
}
}
else if( ( usIndex== LAND_DROP_3 ) && ( ( ubLoop == 0 ) || ( ubLoop == 1 ) || ( ubLoop == 2 )) )
{
gpWorldLevelData[sTempGridNo].uiFlags &= (~MAPELEMENT_RAISE_LAND_START );
gpWorldLevelData[sTempGridNo].uiFlags |= MAPELEMENT_RAISE_LAND_END;
}
else
{
gpWorldLevelData[sTempGridNo].uiFlags |= MAPELEMENT_RAISE_LAND_START;
}
}
}
else
{
if( usIndex==LAND_DROP_3 )
{
gpWorldLevelData[cnt].uiFlags &= (~MAPELEMENT_RAISE_LAND_START );
gpWorldLevelData[cnt].uiFlags |= MAPELEMENT_RAISE_LAND_END;
}
else
{
//if (pTileElement->ubNumberOfTiles==10)
if(usIndex==LAND_DROP_1)
{
gpWorldLevelData[cnt].uiFlags &= (~MAPELEMENT_RAISE_LAND_START );
gpWorldLevelData[cnt].uiFlags |= MAPELEMENT_RAISE_LAND_END;
}
else
gpWorldLevelData[cnt].uiFlags |= MAPELEMENT_RAISE_LAND_START;
}
}
}
pStruct=pStruct->pNext;
}
}
if (fSomethingRaised == FALSE)
{
// no cliffs
return;
}
// run through again, this pass is for placing raiselandstart in rows that have raiseland end but no raiselandstart
for (cnt=WORLD_MAX-1; cnt >=0 ; cnt--)
{
if(cnt%WORLD_ROWS==WORLD_ROWS-1)
{
// start of new row
fRaiseSet=FALSE;
}
if (gpWorldLevelData[cnt].uiFlags&MAPELEMENT_RAISE_LAND_START)
{
fRaiseSet=TRUE;
}
else if((gpWorldLevelData[cnt].uiFlags&MAPELEMENT_RAISE_LAND_END)&&(!fRaiseSet))
{
// there is a dropoff without a rise.
// back up and set beginning to raiseland start
gpWorldLevelData[cnt+((WORLD_ROWS-1)-(cnt%WORLD_ROWS))].uiFlags &= (~MAPELEMENT_RAISE_LAND_END );
gpWorldLevelData[cnt+((WORLD_ROWS-1)-(cnt%WORLD_ROWS))].uiFlags|=MAPELEMENT_RAISE_LAND_START;
if(cnt+((WORLD_ROWS-1)-(cnt%WORLD_ROWS))-WORLD_ROWS >0)
{
gpWorldLevelData[cnt+((WORLD_ROWS-1)-(cnt%WORLD_ROWS))-WORLD_ROWS].uiFlags &= (~MAPELEMENT_RAISE_LAND_END );
gpWorldLevelData[cnt+((WORLD_ROWS-1)-(cnt%WORLD_ROWS))-WORLD_ROWS].uiFlags|=MAPELEMENT_RAISE_LAND_START;
}
fRaiseSet=TRUE;
}
}
fRaiseSet=FALSE;
// Look for a cliff face that is along either the lower edge or the right edge of the map, this is used for a special case fill
// start at y=159, x= 80 and go to x=159, y=80
// now check along x=159, y=80 to x=80, y=0
for (cnt=( ( WORLD_COLS * WORLD_ROWS ) - ( WORLD_ROWS / 2 ) * ( WORLD_ROWS - 2 ) - 1 ); cnt >WORLD_ROWS-1 ; cnt-=(WORLD_ROWS+1))
{
if( fAboutToRaise == TRUE )
{
fRaiseSet=TRUE;
fAboutToRaise = FALSE;
}
if ((gpWorldLevelData[cnt].uiFlags&MAPELEMENT_RAISE_LAND_START)||(gpWorldLevelData[cnt-1].uiFlags&MAPELEMENT_RAISE_LAND_START)||(gpWorldLevelData[ cnt + 1 ].uiFlags&MAPELEMENT_RAISE_LAND_START))
{
fAboutToRaise = TRUE;
fRaiseSet = FALSE;
}
else if((gpWorldLevelData[cnt].uiFlags&MAPELEMENT_RAISE_LAND_END)||(gpWorldLevelData[cnt-1].uiFlags&MAPELEMENT_RAISE_LAND_END) || ( gpWorldLevelData[cnt+1].uiFlags&MAPELEMENT_RAISE_LAND_END) )
{
fRaiseSet=FALSE;
}
if (fRaiseSet)
{
gpWorldLevelData[cnt+((WORLD_ROWS-1)-(cnt%WORLD_ROWS))].uiFlags|=MAPELEMENT_RAISE_LAND_START;
//gpWorldLevelData[cnt].uiFlags|=MAPELEMENT_RAISE_LAND_START;
//gpWorldLevelData[cnt-1].uiFlags|=MAPELEMENT_RAISE_LAND_START;
//DebugMsg(TOPIC_JA2, DBG_LEVEL_3, String("Land Raise start at count: %d is raised",cnt ));
//DebugMsg(TOPIC_JA2, DBG_LEVEL_3, String("Land Raise start at count: %d is raised",cnt - 1 ));
}
}
//fRaiseSet = FALSE;
// Now go through the world, starting at x=max(x) and y=max(y) and work backwards
// if a cliff is found turn raise flag on, if the end of a screen is found, turn off
// the system uses world_cord=x+y*(row_size)
for (cnt=WORLD_MAX-1; cnt >= 0; cnt--)
{
// reset the RAISE to FALSE
// End of the row
if ( !(cnt % WORLD_ROWS) )
{
iNumberOfRaises = 0;
iStartNumberOfRaises = 0;
}
if( ( gpWorldLevelData[cnt].uiFlags & MAPELEMENT_RAISE_LAND_END ) )
{
if( cnt > 1 )
{
if( ( !( gpWorldLevelData[ cnt - 1 ].uiFlags & MAPELEMENT_RAISE_LAND_END) && !( gpWorldLevelData[ cnt - 2 ].uiFlags & MAPELEMENT_RAISE_LAND_END ) ) )
{
iNumberOfRaises--;
}
}
}
else if( gpWorldLevelData[cnt].uiFlags & MAPELEMENT_RAISE_LAND_START )
{
// check tile before and after, if either are raise land flagged, then don't increment number of
// raises
if( cnt < WORLD_MAX - 2 )
{
if( ( !( gpWorldLevelData[ cnt + 1 ].uiFlags & MAPELEMENT_RAISE_LAND_START) && !( gpWorldLevelData[ cnt + 2 ].uiFlags & MAPELEMENT_RAISE_LAND_START ) ) )
{
iNumberOfRaises++;
}
}
}
// look at number of raises.. if negative, then we have more downs than ups, restart row with raises + 1;
// now raise land of any tile while the flag is on
if( iNumberOfRaises < 0 )
{
// something wrong, reset cnt
iStartNumberOfRaises++;
cnt += WORLD_ROWS - cnt % WORLD_ROWS;
iNumberOfRaises = iStartNumberOfRaises;
continue;
}
if( iNumberOfRaises >= 0 )
{
//DebugMsg(TOPIC_JA2, DBG_LEVEL_3, String("Land Raise start at count: %d is raised",cnt ));
gpWorldLevelData[cnt].sHeight=iNumberOfRaises * WORLD_CLIFF_HEIGHT;
}
}
for (cnt=WORLD_MAX-1; cnt >= 0; cnt--)
{
if( ( cnt < WORLD_MAX - WORLD_ROWS ) && ( cnt > WORLD_ROWS ) )
{
if( ( gpWorldLevelData[cnt + WORLD_ROWS ].sHeight == gpWorldLevelData[cnt - WORLD_ROWS ].sHeight ) && ( gpWorldLevelData[ cnt ].sHeight!= gpWorldLevelData[cnt - WORLD_ROWS ].sHeight ) )
{
gpWorldLevelData[cnt].sHeight = gpWorldLevelData[cnt + WORLD_ROWS ].sHeight;
}
else if( ( gpWorldLevelData[ cnt ].sHeight > gpWorldLevelData[cnt - WORLD_ROWS ].sHeight )&& ( gpWorldLevelData[cnt + WORLD_ROWS ].sHeight != gpWorldLevelData[cnt - WORLD_ROWS ].sHeight ) && ( gpWorldLevelData[cnt ].sHeight > gpWorldLevelData[cnt + WORLD_ROWS ].sHeight ) )
{
if( gpWorldLevelData[cnt - WORLD_ROWS ].sHeight > gpWorldLevelData[cnt + WORLD_ROWS ].sHeight )
{
gpWorldLevelData[ cnt ].sHeight = gpWorldLevelData[cnt - WORLD_ROWS ].sHeight;
}
else
{
gpWorldLevelData[ cnt ].sHeight = gpWorldLevelData[cnt + WORLD_ROWS ].sHeight;
}
}
}
}
//*/
}
void EliminateObjectLayerRedundancy()
{
INT32 i, numRoads, numAnothers;
UINT32 uiType;
LEVELNODE *pObject, *pValidRoad, *pValidAnother;
UINT16 usIndex;
for( i = 0; i < WORLD_MAX; i++ )
{ //Eliminate all but the last ROADPIECE and ANOTHERDEBRIS
pObject = gpWorldLevelData[ i ].pObjectHead;
pValidRoad = pValidAnother = NULL;
numRoads = numAnothers = 0;
while( pObject )
{
GetTileType( pObject->usIndex, &uiType );
if( uiType == ROADPIECES )
{ //keep track of the last valid road piece, and count the total
pValidRoad = pObject;
numRoads++;
}
else if( uiType == ANOTHERDEBRIS )
{ //keep track of the last valid another debris, and count the total
pValidAnother = pObject;
numAnothers++;
}
pObject = pObject->pNext;
}
if( pValidRoad && numRoads > 1 )
{ //we have more than two roadpieces on the same gridno, so get rid of them, replacing it
//with the visible one.
usIndex = pValidRoad->usIndex;
RemoveAllObjectsOfTypeRange( i, ROADPIECES, ROADPIECES );
AddObjectToHead( i, usIndex );
}
if( pValidAnother && numAnothers > 1 )
{ //we have more than two anotherdebris on the same gridno, so get rid of them, replacing it
//with the visible one.
usIndex = pValidAnother->usIndex;
RemoveAllObjectsOfTypeRange( i, ANOTHERDEBRIS, ANOTHERDEBRIS );
AddObjectToHead( i, usIndex );
}
}
}
#endif //JA2EDITOR