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@1172 3b4a5df2-a311-0410-b5c6-a8a6f20db521
469 lines
12 KiB
C++
469 lines
12 KiB
C++
#ifdef PRECOMPILEDHEADERS
|
|
#include "Editor All.h"
|
|
#else
|
|
#include "builddefines.h"
|
|
#endif
|
|
|
|
#ifdef JA2EDITOR
|
|
|
|
#ifndef PRECOMPILEDHEADERS
|
|
#include <stdlib.h>
|
|
#include "worlddef.h" //for LEVELNODE def
|
|
#include "worldman.h" //for RemoveXXXX()
|
|
#include "Isometric Utils.h" //for GridNoOnVisibleWorldTile()
|
|
#include "SmartMethod.h"
|
|
#include "Smoothing Utils.h"
|
|
#include "Editor Undo.h"
|
|
#include "EditorDefines.h"
|
|
#include "edit_sys.h"
|
|
#include "environment.h"
|
|
#endif
|
|
|
|
extern UINT16 PickAWallPiece( UINT16 usWallPieceType );
|
|
|
|
//This method isn't foolproof, but because erasing large areas of buildings could result in
|
|
//multiple wall types for each building. When processing the region, it is necessary to
|
|
//calculate the roof type by searching for the nearest roof tile.
|
|
UINT16 SearchForWallType( UINT32 iMapIndex )
|
|
{
|
|
UINT32 uiTileType;
|
|
LEVELNODE *pWall;
|
|
INT16 sOffset;
|
|
INT16 x, y, sRadius = 0;
|
|
if( gfBasement )
|
|
{
|
|
UINT16 usWallType;
|
|
usWallType = GetRandomIndexByRange( FIRSTWALL, LASTWALL );
|
|
if( usWallType == 0xffff )
|
|
usWallType = FIRSTWALL;
|
|
return usWallType;
|
|
}
|
|
while( sRadius < 32 )
|
|
{
|
|
//NOTE: start at the higher y value and go negative because it is possible to have another
|
|
// structure type one tile north, but not one tile south -- so it'll find the correct wall first.
|
|
for( y = sRadius; y >= -sRadius; y-- ) for( x = -sRadius; x <= sRadius; x++ )
|
|
{
|
|
if( abs(x) == abs(sRadius) || abs(y) == abs(sRadius) )
|
|
{
|
|
sOffset = y * WORLD_COLS + x;
|
|
if( !GridNoOnVisibleWorldTile( (INT16)(iMapIndex + sOffset) ) )
|
|
{
|
|
continue;
|
|
}
|
|
pWall = gpWorldLevelData[ iMapIndex + sOffset ].pStructHead;
|
|
while( pWall )
|
|
{
|
|
GetTileType( pWall->usIndex, &uiTileType );
|
|
if( uiTileType >= FIRSTWALL && uiTileType <= LASTWALL )
|
|
{ //found a roof, so return its type.
|
|
return (UINT16)uiTileType;
|
|
}
|
|
//if( uiTileType >= FIRSTWINDOW && uiTileType <= LASTWINDOW )
|
|
//{ //Window types can be converted to a wall type.
|
|
// return (UINT16)(FIRSTWALL + uiTileType - FIRSTWINDOW );
|
|
//}
|
|
pWall = pWall->pNext;
|
|
}
|
|
}
|
|
}
|
|
sRadius++;
|
|
}
|
|
return 0xffff;
|
|
}
|
|
|
|
//This method isn't foolproof, but because erasing large areas of buildings could result in
|
|
//multiple roof types for each building. When processing the region, it is necessary to
|
|
//calculate the roof type by searching for the nearest roof tile.
|
|
UINT16 SearchForRoofType( UINT32 iMapIndex )
|
|
{
|
|
UINT32 uiTileType;
|
|
LEVELNODE *pRoof;
|
|
INT16 x, y, sRadius = 0;
|
|
INT16 sOffset;
|
|
while( sRadius < 32 )
|
|
{
|
|
for( y = -sRadius; y <= sRadius; y++ ) for( x = -sRadius; x <= sRadius; x++ )
|
|
{
|
|
if( abs(x) == abs(sRadius) || abs(y) == abs(sRadius) )
|
|
{
|
|
sOffset = y * WORLD_COLS + x;
|
|
if( !GridNoOnVisibleWorldTile( (INT16)(iMapIndex + sOffset) ) )
|
|
{
|
|
continue;
|
|
}
|
|
pRoof = gpWorldLevelData[ iMapIndex + sOffset ].pRoofHead;
|
|
while( pRoof )
|
|
{
|
|
GetTileType( pRoof->usIndex, &uiTileType );
|
|
if( uiTileType >= FIRSTROOF && uiTileType <= LASTROOF )
|
|
{ //found a roof, so return its type.
|
|
return (UINT16)uiTileType;
|
|
}
|
|
pRoof = pRoof->pNext;
|
|
}
|
|
}
|
|
}
|
|
sRadius++;
|
|
}
|
|
return 0xffff;
|
|
}
|
|
|
|
BOOLEAN RoofAtGridNo( UINT32 iMapIndex )
|
|
{
|
|
LEVELNODE *pRoof;
|
|
UINT32 uiTileType;
|
|
pRoof = gpWorldLevelData[ iMapIndex ].pRoofHead;
|
|
// Look through all objects and Search for type
|
|
while( pRoof )
|
|
{
|
|
if ( pRoof->usIndex != NO_TILE )
|
|
{
|
|
GetTileType( pRoof->usIndex, &uiTileType );
|
|
if ( uiTileType >= FIRSTROOF && uiTileType <= SECONDSLANTROOF )
|
|
return TRUE;
|
|
pRoof = pRoof->pNext;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOLEAN BuildingAtGridNo( UINT32 iMapIndex )
|
|
{
|
|
if( RoofAtGridNo( iMapIndex ) )
|
|
return TRUE;
|
|
if( FloorAtGridNo( iMapIndex ) )
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
BOOLEAN ValidDecalPlacement( UINT32 iMapIndex )
|
|
{
|
|
if( GetVerticalWall( iMapIndex ) || GetHorizontalWall( iMapIndex )
|
|
|| GetVerticalFence( iMapIndex ) || GetHorizontalFence( iMapIndex ) )
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
LEVELNODE* GetVerticalWall( UINT32 iMapIndex )
|
|
{
|
|
LEVELNODE *pStruct;
|
|
UINT32 uiTileType;
|
|
UINT16 usWallOrientation;
|
|
pStruct = gpWorldLevelData[ iMapIndex ].pStructHead;
|
|
while( pStruct )
|
|
{
|
|
if ( pStruct->usIndex != NO_TILE )
|
|
{
|
|
GetTileType( pStruct->usIndex, &uiTileType );
|
|
if ( uiTileType >= FIRSTWALL && uiTileType <= LASTWALL ||
|
|
uiTileType >= FIRSTDOOR && uiTileType <= LASTDOOR )
|
|
{
|
|
GetWallOrientation( pStruct->usIndex, &usWallOrientation );
|
|
if( usWallOrientation == INSIDE_TOP_RIGHT || usWallOrientation == OUTSIDE_TOP_RIGHT )
|
|
{
|
|
return pStruct;
|
|
}
|
|
}
|
|
}
|
|
pStruct = pStruct->pNext;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
LEVELNODE* GetHorizontalWall( UINT32 iMapIndex )
|
|
{
|
|
LEVELNODE *pStruct;
|
|
UINT32 uiTileType;
|
|
UINT16 usWallOrientation;
|
|
pStruct = gpWorldLevelData[ iMapIndex ].pStructHead;
|
|
while( pStruct )
|
|
{
|
|
if ( pStruct->usIndex != NO_TILE )
|
|
{
|
|
GetTileType( pStruct->usIndex, &uiTileType );
|
|
if ( uiTileType >= FIRSTWALL && uiTileType <= LASTWALL ||
|
|
uiTileType >= FIRSTDOOR && uiTileType <= LASTDOOR )
|
|
{
|
|
GetWallOrientation( pStruct->usIndex, &usWallOrientation );
|
|
if( usWallOrientation == INSIDE_TOP_LEFT || usWallOrientation == OUTSIDE_TOP_LEFT )
|
|
{
|
|
return pStruct;
|
|
}
|
|
}
|
|
}
|
|
pStruct = pStruct->pNext;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
UINT16 GetVerticalWallType( UINT32 iMapIndex )
|
|
{
|
|
LEVELNODE *pWall;
|
|
UINT32 uiTileType;
|
|
pWall = GetVerticalWall( iMapIndex );
|
|
if( pWall )
|
|
{
|
|
GetTileType( pWall->usIndex, &uiTileType );
|
|
if( uiTileType >= FIRSTDOOR && uiTileType <= LASTDOOR )
|
|
uiTileType = SearchForWallType( iMapIndex );
|
|
return (UINT16)uiTileType;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
UINT16 GetHorizontalWallType( UINT32 iMapIndex )
|
|
{
|
|
LEVELNODE *pWall;
|
|
UINT32 uiTileType;
|
|
pWall = GetHorizontalWall( iMapIndex );
|
|
if( pWall )
|
|
{
|
|
GetTileType( pWall->usIndex, &uiTileType );
|
|
if( uiTileType >= FIRSTDOOR && uiTileType <= LASTDOOR )
|
|
uiTileType = SearchForWallType( iMapIndex );
|
|
return (UINT16)uiTileType;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LEVELNODE* GetVerticalFence( UINT32 iMapIndex )
|
|
{
|
|
LEVELNODE *pStruct;
|
|
UINT32 uiTileType;
|
|
UINT16 usWallOrientation;
|
|
pStruct = gpWorldLevelData[ iMapIndex ].pStructHead;
|
|
while( pStruct )
|
|
{
|
|
if ( pStruct->usIndex != NO_TILE )
|
|
{
|
|
GetTileType( pStruct->usIndex, &uiTileType );
|
|
if ( uiTileType == FENCESTRUCT )
|
|
{
|
|
GetWallOrientation( pStruct->usIndex, &usWallOrientation );
|
|
if( usWallOrientation == INSIDE_TOP_RIGHT || usWallOrientation == OUTSIDE_TOP_RIGHT )
|
|
{
|
|
return pStruct;
|
|
}
|
|
}
|
|
}
|
|
pStruct = pStruct->pNext;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
LEVELNODE* GetHorizontalFence( UINT32 iMapIndex )
|
|
{
|
|
LEVELNODE *pStruct;
|
|
UINT32 uiTileType;
|
|
UINT16 usWallOrientation;
|
|
pStruct = gpWorldLevelData[ iMapIndex ].pStructHead;
|
|
while( pStruct )
|
|
{
|
|
if ( pStruct->usIndex != NO_TILE )
|
|
{
|
|
GetTileType( pStruct->usIndex, &uiTileType );
|
|
if ( uiTileType == FENCESTRUCT )
|
|
{
|
|
GetWallOrientation( pStruct->usIndex, &usWallOrientation );
|
|
if( usWallOrientation == INSIDE_TOP_LEFT || usWallOrientation == OUTSIDE_TOP_LEFT )
|
|
{
|
|
return pStruct;
|
|
}
|
|
}
|
|
}
|
|
pStruct = pStruct->pNext;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void EraseHorizontalWall( UINT32 iMapIndex )
|
|
{
|
|
LEVELNODE *pWall;
|
|
pWall = GetHorizontalWall( iMapIndex );
|
|
if( pWall )
|
|
{
|
|
AddToUndoList( iMapIndex );
|
|
RemoveStruct( iMapIndex, pWall->usIndex );
|
|
RemoveAllShadowsOfTypeRange( iMapIndex, FIRSTWALL, LASTWALL );
|
|
}
|
|
}
|
|
|
|
void EraseVerticalWall( UINT32 iMapIndex )
|
|
{
|
|
LEVELNODE *pWall;
|
|
pWall = GetVerticalWall( iMapIndex );
|
|
if( pWall )
|
|
{
|
|
AddToUndoList( iMapIndex );
|
|
RemoveStruct( iMapIndex, pWall->usIndex );
|
|
RemoveAllShadowsOfTypeRange( iMapIndex, FIRSTWALL, LASTWALL );
|
|
}
|
|
}
|
|
|
|
void ChangeHorizontalWall( UINT32 iMapIndex, UINT16 usNewPiece )
|
|
{
|
|
LEVELNODE *pWall;
|
|
UINT32 uiTileType;
|
|
UINT16 usTileIndex;
|
|
INT16 sIndex;
|
|
pWall = GetHorizontalWall( iMapIndex );
|
|
if( pWall )
|
|
{
|
|
GetTileType( pWall->usIndex, &uiTileType );
|
|
if( uiTileType >= FIRSTWALL && uiTileType <= LASTWALL )
|
|
{ //Okay, we have the wall, now change it's type.
|
|
sIndex = PickAWallPiece( usNewPiece );
|
|
AddToUndoList( iMapIndex );
|
|
GetTileIndexFromTypeSubIndex( uiTileType, sIndex, &usTileIndex );
|
|
ReplaceStructIndex( iMapIndex, pWall->usIndex, usTileIndex );
|
|
}
|
|
}
|
|
}
|
|
|
|
void ChangeVerticalWall( UINT32 iMapIndex, UINT16 usNewPiece )
|
|
{
|
|
LEVELNODE *pWall;
|
|
UINT32 uiTileType;
|
|
UINT16 usTileIndex;
|
|
INT16 sIndex;
|
|
pWall = GetVerticalWall( iMapIndex );
|
|
if( pWall )
|
|
{
|
|
GetTileType( pWall->usIndex, &uiTileType );
|
|
if( uiTileType >= FIRSTWALL && uiTileType <= LASTWALL )
|
|
{ //Okay, we have the wall, now change it's type.
|
|
sIndex = PickAWallPiece( usNewPiece );
|
|
AddToUndoList( iMapIndex );
|
|
GetTileIndexFromTypeSubIndex( uiTileType, sIndex, &usTileIndex );
|
|
ReplaceStructIndex( iMapIndex, pWall->usIndex, usTileIndex );
|
|
}
|
|
}
|
|
}
|
|
|
|
void RestoreWalls( UINT32 iMapIndex )
|
|
{
|
|
LEVELNODE *pWall = NULL;
|
|
UINT32 uiTileType;
|
|
UINT16 usWallType;
|
|
UINT16 usWallOrientation;
|
|
UINT8 ubSaveWallUIValue;
|
|
BOOLEAN fDone = FALSE;
|
|
|
|
pWall = GetHorizontalWall( iMapIndex );
|
|
if( pWall )
|
|
{
|
|
GetTileType( pWall->usIndex, &uiTileType );
|
|
usWallType = (UINT16)uiTileType;
|
|
if( uiTileType >= FIRSTDOOR && uiTileType <= LASTDOOR )
|
|
usWallType = SearchForWallType( iMapIndex );
|
|
GetWallOrientation( pWall->usIndex, &usWallOrientation );
|
|
AddToUndoList( iMapIndex );
|
|
RemoveStruct( iMapIndex, pWall->usIndex );
|
|
RemoveAllShadowsOfTypeRange( iMapIndex, FIRSTWALL, LASTWALL );
|
|
switch( usWallOrientation )
|
|
{
|
|
case OUTSIDE_TOP_LEFT:
|
|
BuildWallPiece( iMapIndex, INTERIOR_BOTTOM, usWallType );
|
|
break;
|
|
case INSIDE_TOP_LEFT:
|
|
BuildWallPiece( iMapIndex, EXTERIOR_BOTTOM, usWallType );
|
|
break;
|
|
}
|
|
fDone = TRUE;
|
|
}
|
|
pWall = GetVerticalWall( iMapIndex );
|
|
if( pWall )
|
|
{
|
|
GetTileType( pWall->usIndex, &uiTileType );
|
|
usWallType = (UINT16)uiTileType;
|
|
if( uiTileType >= FIRSTDOOR && uiTileType <= LASTDOOR )
|
|
usWallType = SearchForWallType( iMapIndex );
|
|
GetWallOrientation( pWall->usIndex, &usWallOrientation );
|
|
AddToUndoList( iMapIndex );
|
|
RemoveStruct( iMapIndex, pWall->usIndex );
|
|
RemoveAllShadowsOfTypeRange( iMapIndex, FIRSTWALL, LASTWALL );
|
|
switch( usWallOrientation )
|
|
{
|
|
case OUTSIDE_TOP_RIGHT:
|
|
BuildWallPiece( iMapIndex, INTERIOR_RIGHT, usWallType );
|
|
break;
|
|
case INSIDE_TOP_RIGHT:
|
|
BuildWallPiece( iMapIndex, EXTERIOR_RIGHT, usWallType );
|
|
break;
|
|
}
|
|
fDone = TRUE;
|
|
}
|
|
if( fDone )
|
|
{
|
|
return;
|
|
}
|
|
//we are in a special case here. The user is attempting to restore a wall, though nothing
|
|
//is here. We will hook into the smart wall method by tricking it into using the local wall
|
|
//type, but only if we have adjacent walls.
|
|
fDone = FALSE;
|
|
if( pWall = GetHorizontalWall( iMapIndex - 1 ) )
|
|
fDone = TRUE;
|
|
if( !fDone && (pWall = GetHorizontalWall( iMapIndex + 1 )) )
|
|
fDone = TRUE;
|
|
if( !fDone && (pWall = GetVerticalWall( iMapIndex - WORLD_COLS )) )
|
|
fDone = TRUE;
|
|
if( !fDone && (pWall = GetVerticalWall( iMapIndex + WORLD_COLS )) )
|
|
fDone = TRUE;
|
|
if( !fDone )
|
|
return;
|
|
//found a wall. Let's back up the current wall value, and restore it after pasting a smart wall.
|
|
if( pWall )
|
|
{
|
|
GetTileType( pWall->usIndex, &uiTileType );
|
|
usWallType = (UINT16)uiTileType;
|
|
if( uiTileType >= FIRSTDOOR && uiTileType <= LASTDOOR )
|
|
usWallType = SearchForWallType( iMapIndex );
|
|
if( usWallType != 0xffff )
|
|
{
|
|
ubSaveWallUIValue = gubWallUIValue; //save the wall UI value.
|
|
gubWallUIValue = (UINT8)usWallType; //trick the UI value
|
|
PasteSmartWall( iMapIndex ); //paste smart wall with fake UI value
|
|
gubWallUIValue = ubSaveWallUIValue; //restore the real UI value.
|
|
}
|
|
}
|
|
}
|
|
|
|
UINT16 GetWallClass( LEVELNODE *pWall )
|
|
{
|
|
UINT16 row, col, rowVariants;
|
|
UINT16 usWallIndex;
|
|
if( !pWall )
|
|
return 0xffff;
|
|
GetSubIndexFromTileIndex( pWall->usIndex, &usWallIndex );
|
|
for ( row = 0; row < NUM_WALL_TYPES; row++ )
|
|
{
|
|
rowVariants = gbWallTileLUT[row][0];
|
|
for( col = 1; col <= rowVariants; col++ )
|
|
{
|
|
if( usWallIndex == gbWallTileLUT[row][col] )
|
|
{
|
|
return row; //row is the wall class
|
|
}
|
|
}
|
|
}
|
|
return 0xffff;
|
|
}
|
|
|
|
UINT16 GetVerticalWallClass( UINT16 iMapIndex )
|
|
{
|
|
LEVELNODE *pWall;
|
|
if( pWall = GetVerticalWall( iMapIndex ) )
|
|
return GetWallClass( pWall );
|
|
return 0xffff;
|
|
}
|
|
|
|
UINT16 GetHorizontalWallClass( UINT16 iMapIndex )
|
|
{
|
|
LEVELNODE *pWall;
|
|
if( pWall = GetVerticalWall( iMapIndex ) )
|
|
return GetWallClass( pWall );
|
|
return 0xffff;
|
|
}
|
|
|
|
#endif |