mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
Fix militia issue in auto-resolve: Militia were not always being promoted even when it said they were. Since first X slots are for militia already in the sector, militia from other sectors are not sorted by rank. This actually affects battle outcome! Added fix to editor to skip cached tiles in RaiseWorldLand. Otherwise it can crash when invoked within the game. ja2_2005Express projects: Added output directory for JA2 exe based on environment variable JA2GAMEPATH Restored editor built by default for debug mode Removed #define LUA_CONSOLE. It is no longer relevant. git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@1081 3b4a5df2-a311-0410-b5c6-a8a6f20db521
1455 lines
44 KiB
C++
1455 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 )
|
|
{
|
|
// Skip cached tiles
|
|
if (pStruct->usIndex >= NUMBEROFTILES)
|
|
{
|
|
pStruct = pStruct->pNext;
|
|
continue;
|
|
}
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
|