mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@21 3b4a5df2-a311-0410-b5c6-a8a6f20db521
1447 lines
44 KiB
C++
1447 lines
44 KiB
C++
#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
|
|
|
|
|
|
|
|
|
|
|
|
|