mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
Added missing #includes Added LUA scripting and console Changed the way tracers are visualized, so they work more like real tracers instead of a light fountain Fixed signedness of many grid variables used in GetMouseMapPos calls Fixed enemy weapon choosing: Sometimes a mortar is chosen but later rejected, but the grenade class was not reset. Caused assertion failure Added checks so enemies don't try to chuck RPG grenades with their hands Now possible to shoot a someone in the head if he's in water Fixed InitSightArrays to also clear soldier interrupt duel points. This was causing an assertion failure elsewhere in the code because the interrupt list still had soldiers on it sometimes when this function was called. Soldiers are much less willing to forfeit their turn over an attempt to use more APs than they have Removed early setting of muzzle flash. This would allow enemies to get an interrupt before you even fired. Fixed item dropping by AI. If AI tried to drop something while standing it would cause deadlock Change to greatly speed up closing the sector inventory window in an unloaded sector Added conditional compile flag to always give robot weapon ready advantage, even for 360 degree sighting Check builddefines.h for the conditional flags. Of greatest interest might be LUA_CONSOLE. This will cause the game to bring up a command console when run. However this console is severely lacking in many areas. If anybody knows of an open-source terminal/console that could be used instead, it would be appreciated. The existing console does bad things when you try to close it, and since it counts as a separate app, it pauses the game while it has focus. LUA scripting is very limited, basically just proof of concept. There is one global variable, the Soldiers array. An array index gives you the soldier in that slot in the currently loaded sector. The soldier has a few things that can be accessed: name (short name); fullname (long name); grid (current grid #, can be changed); walkto(grid) (function to walk to another grid); runto(grid) (function to run to another grid) git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@924 3b4a5df2-a311-0410-b5c6-a8a6f20db521
494 lines
13 KiB
C++
494 lines
13 KiB
C++
#ifdef PRECOMPILEDHEADERS
|
|
#include "TileEngine All.h"
|
|
#else
|
|
#include "Types.h"
|
|
#include "Buildings.h"
|
|
#include "Isometric Utils.h"
|
|
#include "Pathai.h"
|
|
#include "Structure Wrap.h"
|
|
#include "Random.h"
|
|
#include "Overhead.h"
|
|
#include "Render Fun.h"
|
|
#include "Strategicmap.h"
|
|
#include "Sys Globals.h"
|
|
#include "worldman.h"
|
|
#endif
|
|
|
|
#define ROOF_LOCATION_CHANCE 8
|
|
|
|
UINT8 gubBuildingInfo[ WORLD_MAX ];
|
|
BUILDING gBuildings[ MAX_BUILDINGS ];
|
|
UINT8 gubNumberOfBuildings;
|
|
|
|
BUILDING * CreateNewBuilding( UINT8 * pubBuilding )
|
|
{
|
|
if (gubNumberOfBuildings + 1 >= MAX_BUILDINGS)
|
|
{
|
|
return( NULL );
|
|
}
|
|
// increment # of buildings
|
|
gubNumberOfBuildings++;
|
|
// clear entry
|
|
gBuildings[ gubNumberOfBuildings ].ubNumClimbSpots = 0;
|
|
*pubBuilding = gubNumberOfBuildings;
|
|
// return pointer (have to subtract 1 since we just added 1
|
|
return( &(gBuildings[ gubNumberOfBuildings ]) );
|
|
}
|
|
|
|
BUILDING * GenerateBuilding( INT16 sDesiredSpot )
|
|
{
|
|
|
|
UINT32 uiLoop;
|
|
UINT32 uiLoop2;
|
|
INT16 sTempGridNo, sNextTempGridNo, sVeryTemporaryGridNo;
|
|
INT16 sStartGridNo, sCurrGridNo, sPrevGridNo = NOWHERE, sRightGridNo;
|
|
INT8 bDirection, bTempDirection;
|
|
BOOLEAN fFoundDir, fFoundWall;
|
|
UINT32 uiChanceIn = ROOF_LOCATION_CHANCE; // chance of a location being considered
|
|
INT16 sWallGridNo;
|
|
INT8 bDesiredOrientation;
|
|
INT8 bSkipSpots = 0;
|
|
SOLDIERTYPE FakeSoldier;
|
|
BUILDING * pBuilding;
|
|
UINT8 ubBuildingID = 0;
|
|
INT32 iLoopCount = 0;
|
|
|
|
pBuilding = CreateNewBuilding( &ubBuildingID );
|
|
if (!pBuilding)
|
|
{
|
|
return( NULL );
|
|
}
|
|
|
|
// set up fake soldier for location testing
|
|
memset( &FakeSoldier, 0, sizeof( SOLDIERTYPE ) );
|
|
FakeSoldier.sGridNo = sDesiredSpot;
|
|
FakeSoldier.bLevel = 1;
|
|
FakeSoldier.bTeam = 1;
|
|
|
|
#ifdef ROOF_DEBUG
|
|
memset( gsCoverValue, 0x7F, sizeof( INT16 ) * WORLD_MAX );
|
|
#endif
|
|
|
|
// Set reachable
|
|
RoofReachableTest( sDesiredSpot, ubBuildingID );
|
|
|
|
// From sGridNo, search until we find a spot that isn't part of the building
|
|
bDirection = NORTHWEST;
|
|
sTempGridNo = sDesiredSpot;
|
|
// using diagonal directions to hopefully prevent picking a
|
|
// spot that
|
|
while( (gpWorldLevelData[ sTempGridNo ].uiFlags & MAPELEMENT_REACHABLE ) )
|
|
{
|
|
sNextTempGridNo = NewGridNo( sTempGridNo, DirectionInc( bDirection ) );
|
|
if ( sTempGridNo == sNextTempGridNo )
|
|
{
|
|
// hit edge of map!??!
|
|
return( NULL );
|
|
}
|
|
else
|
|
{
|
|
sTempGridNo = sNextTempGridNo;
|
|
}
|
|
}
|
|
|
|
// we've got our spot
|
|
sStartGridNo = sTempGridNo;
|
|
|
|
sCurrGridNo = sStartGridNo;
|
|
sVeryTemporaryGridNo = NewGridNo( sCurrGridNo, DirectionInc( EAST ) );
|
|
if ( gpWorldLevelData[ sVeryTemporaryGridNo ].uiFlags & MAPELEMENT_REACHABLE )
|
|
{
|
|
// go north first
|
|
bDirection = NORTH;
|
|
}
|
|
else
|
|
{
|
|
// go that way (east)
|
|
bDirection = EAST;
|
|
}
|
|
|
|
gpWorldLevelData[ sStartGridNo ].ubExtFlags[0] |= MAPELEMENT_EXT_ROOFCODE_VISITED;
|
|
|
|
uiLoop2 = 0;
|
|
while(uiLoop2 < WORLD_MAX)
|
|
{
|
|
// if point to (2 clockwise) is not part of building and is not visited,
|
|
// or is starting point, turn!
|
|
sRightGridNo = NewGridNo( sCurrGridNo, DirectionInc( gTwoCDirection[ bDirection ] ) );
|
|
sTempGridNo = sRightGridNo;
|
|
if ( ( ( !(gpWorldLevelData[ sTempGridNo ].uiFlags & MAPELEMENT_REACHABLE) && !(gpWorldLevelData[ sTempGridNo ].ubExtFlags[0] & MAPELEMENT_EXT_ROOFCODE_VISITED) ) || (sTempGridNo == sStartGridNo) ) && (sCurrGridNo != sStartGridNo) )
|
|
{
|
|
iLoopCount++;
|
|
|
|
if ( iLoopCount >= 10 )
|
|
{
|
|
return( NULL );
|
|
}
|
|
bDirection = gTwoCDirection[ bDirection ];
|
|
// try in that direction
|
|
continue;
|
|
}
|
|
iLoopCount = 0;
|
|
|
|
// if spot ahead is part of building, turn
|
|
sTempGridNo = NewGridNo( sCurrGridNo, DirectionInc( bDirection ) );
|
|
if ( gpWorldLevelData[ sTempGridNo ].uiFlags & MAPELEMENT_REACHABLE )
|
|
{
|
|
// first search for a spot that is neither part of the building or visited
|
|
|
|
// we KNOW that the spot in the original direction is blocked, so only loop 3 times
|
|
bTempDirection = gTwoCDirection[ bDirection ];
|
|
fFoundDir = FALSE;
|
|
for ( uiLoop = 0; uiLoop < 3; uiLoop++ )
|
|
{
|
|
sTempGridNo = NewGridNo( sCurrGridNo, DirectionInc( bTempDirection ) );
|
|
if ( !(gpWorldLevelData[ sTempGridNo ].uiFlags & MAPELEMENT_REACHABLE) && !(gpWorldLevelData[ sTempGridNo ].ubExtFlags[0] & MAPELEMENT_EXT_ROOFCODE_VISITED) )
|
|
{
|
|
// this is the way to go!
|
|
fFoundDir = TRUE;
|
|
break;
|
|
}
|
|
bTempDirection = gTwoCDirection[ bTempDirection ];
|
|
}
|
|
if (!fFoundDir)
|
|
{
|
|
// now search for a spot that is just not part of the building
|
|
bTempDirection = gTwoCDirection[ bDirection ];
|
|
fFoundDir = FALSE;
|
|
for ( uiLoop = 0; uiLoop < 3; uiLoop++ )
|
|
{
|
|
sTempGridNo = NewGridNo( sCurrGridNo, DirectionInc( bTempDirection ) );
|
|
if ( !(gpWorldLevelData[ sTempGridNo ].uiFlags & MAPELEMENT_REACHABLE) )
|
|
{
|
|
// this is the way to go!
|
|
fFoundDir = TRUE;
|
|
break;
|
|
}
|
|
bTempDirection = gTwoCDirection[ bTempDirection ];
|
|
}
|
|
if (!fFoundDir)
|
|
{
|
|
// WTF is going on?
|
|
return( NULL );
|
|
}
|
|
}
|
|
bDirection = bTempDirection;
|
|
// try in that direction
|
|
continue;
|
|
}
|
|
|
|
// move ahead
|
|
sPrevGridNo = sCurrGridNo;
|
|
sCurrGridNo = sTempGridNo;
|
|
sRightGridNo = NewGridNo( sCurrGridNo, DirectionInc( gTwoCDirection[ bDirection ] ) );
|
|
|
|
#ifdef ROOF_DEBUG
|
|
if (gsCoverValue[sCurrGridNo] == 0x7F7F)
|
|
{
|
|
gsCoverValue[sCurrGridNo] = 1;
|
|
}
|
|
else if (gsCoverValue[sCurrGridNo] >= 0)
|
|
{
|
|
gsCoverValue[sCurrGridNo]++;
|
|
}
|
|
|
|
DebugAI( String( "Roof code visits %d", sCurrGridNo ) );
|
|
#endif
|
|
|
|
if (sCurrGridNo == sStartGridNo)
|
|
{
|
|
// done
|
|
break;
|
|
}
|
|
|
|
if ( !(gpWorldLevelData[ sCurrGridNo ].ubExtFlags[0] & MAPELEMENT_EXT_ROOFCODE_VISITED) )
|
|
{
|
|
gpWorldLevelData[ sCurrGridNo ].ubExtFlags[0] |= MAPELEMENT_EXT_ROOFCODE_VISITED;
|
|
|
|
gubBuildingInfo[ sCurrGridNo ] = ubBuildingID;
|
|
|
|
// consider this location as possible climb gridno
|
|
// there must be a regular wall adjacent to this for us to consider it a
|
|
// climb gridno
|
|
|
|
// if the direction is east or north, the wall would be in our gridno;
|
|
// if south or west, the wall would be in the gridno two clockwise
|
|
fFoundWall = FALSE;
|
|
|
|
switch( bDirection )
|
|
{
|
|
case NORTH:
|
|
sWallGridNo = sCurrGridNo;
|
|
bDesiredOrientation = OUTSIDE_TOP_RIGHT;
|
|
break;
|
|
case EAST:
|
|
sWallGridNo = sCurrGridNo;
|
|
bDesiredOrientation = OUTSIDE_TOP_LEFT;
|
|
break;
|
|
case SOUTH:
|
|
sWallGridNo = (INT16) ( sCurrGridNo + DirectionInc( gTwoCDirection[ bDirection ] ) );
|
|
bDesiredOrientation = OUTSIDE_TOP_RIGHT;
|
|
break;
|
|
case WEST:
|
|
sWallGridNo = (INT16) ( sCurrGridNo + DirectionInc( gTwoCDirection[ bDirection ] ) );
|
|
bDesiredOrientation = OUTSIDE_TOP_LEFT;
|
|
break;
|
|
default:
|
|
// what the heck?
|
|
return( NULL );
|
|
}
|
|
|
|
if (bDesiredOrientation == OUTSIDE_TOP_LEFT)
|
|
{
|
|
if (WallExistsOfTopLeftOrientation( sWallGridNo ))
|
|
{
|
|
fFoundWall = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (WallExistsOfTopRightOrientation( sWallGridNo ))
|
|
{
|
|
fFoundWall = TRUE;
|
|
}
|
|
}
|
|
|
|
if (fFoundWall)
|
|
{
|
|
if (bSkipSpots > 0)
|
|
{
|
|
bSkipSpots--;
|
|
}
|
|
else if ( Random( uiChanceIn ) == 0 )
|
|
{
|
|
// don't consider people as obstacles
|
|
if ( NewOKDestination( &FakeSoldier, sCurrGridNo, FALSE, 0 ) )
|
|
{
|
|
pBuilding->sUpClimbSpots[ pBuilding->ubNumClimbSpots ] = sCurrGridNo;
|
|
pBuilding->sDownClimbSpots[ pBuilding->ubNumClimbSpots ] = sRightGridNo;
|
|
pBuilding->ubNumClimbSpots++;
|
|
|
|
if ( pBuilding->ubNumClimbSpots == MAX_CLIMBSPOTS_PER_BUILDING)
|
|
{
|
|
// gotta stop!
|
|
return( pBuilding );
|
|
}
|
|
|
|
// if location is added as a spot, reset uiChanceIn
|
|
uiChanceIn = ROOF_LOCATION_CHANCE;
|
|
#ifdef ROOF_DEBUG
|
|
gsCoverValue[sCurrGridNo] = 99;
|
|
#endif
|
|
// skip the next spot
|
|
bSkipSpots = 1;
|
|
}
|
|
else
|
|
{
|
|
// if location is not added, 100% chance of handling next location
|
|
// and the next until we can add one
|
|
uiChanceIn = 1;
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// didn't pick this location, so increase chance that next location
|
|
// will be considered
|
|
if (uiChanceIn > 2)
|
|
{
|
|
uiChanceIn--;
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// can't select this spot
|
|
if ( (sPrevGridNo != NOWHERE) && (pBuilding->ubNumClimbSpots > 0) )
|
|
{
|
|
if ( pBuilding->sDownClimbSpots[ pBuilding->ubNumClimbSpots - 1 ] == sCurrGridNo )
|
|
{
|
|
// unselect previous spot
|
|
pBuilding->ubNumClimbSpots--;
|
|
// overwrote a selected spot so go into automatic selection for later
|
|
uiChanceIn = 1;
|
|
#ifdef ROOF_DEBUG
|
|
// reset marker
|
|
gsCoverValue[sPrevGridNo] = 1;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// skip the next gridno
|
|
bSkipSpots = 1;
|
|
}
|
|
|
|
}
|
|
uiLoop2++;
|
|
}
|
|
// If we've run out of loop before we've run out of building, then there is
|
|
// something that has gone pear shaped
|
|
if(uiLoop2 >= WORLD_MAX)
|
|
{
|
|
UINT8 x = 0;
|
|
UINT8 y = 0;
|
|
while((sDesiredSpot - ((y + 1) * 160)) >= 0)
|
|
{
|
|
y++;
|
|
}
|
|
x = sDesiredSpot - (y * 160);
|
|
DebugMsg (TOPIC_JA2,DBG_LEVEL_2,String( "113/UC Warning! Building Walk Algorithm has covered the entire map! Building %d located at [%d,%d] must be bogus.", ubBuildingID, x, y ));
|
|
}
|
|
|
|
|
|
// at end could prune # of locations if there are too many
|
|
|
|
/*
|
|
#ifdef ROOF_DEBUG
|
|
SetRenderFlags( RENDER_FLAG_FULL );
|
|
RenderWorld();
|
|
RenderCoverDebug( );
|
|
InvalidateScreen( );
|
|
EndFrameBufferRender();
|
|
RefreshScreen( NULL );
|
|
#endif
|
|
*/
|
|
return( pBuilding );
|
|
}
|
|
|
|
BUILDING * FindBuilding( INT16 sGridNo )
|
|
{
|
|
UINT8 ubBuildingID;
|
|
//UINT8 ubRoomNo;
|
|
|
|
if (sGridNo <= 0 || sGridNo > WORLD_MAX)
|
|
{
|
|
return( NULL );
|
|
}
|
|
|
|
// id 0 indicates no building
|
|
ubBuildingID = gubBuildingInfo[ sGridNo ];
|
|
|
|
if ( ubBuildingID == NO_BUILDING )
|
|
{
|
|
return( NULL );
|
|
/*
|
|
// need extra checks to see if is valid spot...
|
|
// must have valid room information and be a flat-roofed
|
|
// building
|
|
if ( InARoom( sGridNo, &ubRoomNo ) && (FindStructure( sGridNo, STRUCTURE_NORMAL_ROOF ) != NULL) )
|
|
{
|
|
return( GenerateBuilding( sGridNo ) );
|
|
}
|
|
else
|
|
{
|
|
return( NULL );
|
|
}
|
|
*/
|
|
}
|
|
else if ( ubBuildingID > gubNumberOfBuildings ) // huh?
|
|
{
|
|
return( NULL );
|
|
}
|
|
|
|
return( &(gBuildings[ ubBuildingID ]) );
|
|
}
|
|
|
|
BOOLEAN InBuilding( INT16 sGridNo )
|
|
{
|
|
if ( FindBuilding( sGridNo ) == NULL )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
void GenerateBuildings( void )
|
|
{
|
|
UINT32 uiLoop;
|
|
|
|
// init building structures and variables
|
|
memset( &gubBuildingInfo, 0, WORLD_MAX * sizeof( UINT8 ) );
|
|
memset( &gBuildings, 0, MAX_BUILDINGS * sizeof( BUILDING ) );
|
|
gubNumberOfBuildings = 0;
|
|
|
|
if ( (gbWorldSectorZ > 0) || gfEditMode)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// reset ALL reachable flags
|
|
// do once before we start building generation for
|
|
// whole map
|
|
for ( uiLoop = 0; uiLoop < WORLD_MAX; uiLoop++ )
|
|
{
|
|
gpWorldLevelData[ uiLoop ].uiFlags &= ~(MAPELEMENT_REACHABLE);
|
|
gpWorldLevelData[ uiLoop ].ubExtFlags[0] &= ~(MAPELEMENT_EXT_ROOFCODE_VISITED);
|
|
}
|
|
|
|
// search through world
|
|
// for each location in a room try to find building info
|
|
for ( uiLoop = 0; uiLoop < WORLD_MAX; uiLoop++ )
|
|
{
|
|
if ( (gubWorldRoomInfo[ uiLoop ] != NO_ROOM) && (gubBuildingInfo[ uiLoop ] == NO_BUILDING) && (FindStructure( (INT16) uiLoop, STRUCTURE_NORMAL_ROOF ) != NULL) )
|
|
{
|
|
GenerateBuilding( (INT16) uiLoop );
|
|
}
|
|
}
|
|
}
|
|
|
|
INT16 FindClosestClimbPoint( INT16 sStartGridNo, INT16 sDesiredGridNo, BOOLEAN fClimbUp )
|
|
{
|
|
BUILDING * pBuilding;
|
|
UINT8 ubNumClimbSpots;
|
|
INT16 * psClimbSpots;
|
|
UINT8 ubLoop;
|
|
INT16 sDistance, sClosestDistance = 1000, sClosestSpot= NOWHERE;
|
|
|
|
pBuilding = FindBuilding( sDesiredGridNo );
|
|
if (!pBuilding)
|
|
{
|
|
return( NOWHERE );
|
|
}
|
|
|
|
ubNumClimbSpots = pBuilding->ubNumClimbSpots;
|
|
|
|
if (fClimbUp)
|
|
{
|
|
psClimbSpots = pBuilding->sUpClimbSpots;
|
|
}
|
|
else
|
|
{
|
|
psClimbSpots = pBuilding->sDownClimbSpots;
|
|
}
|
|
|
|
for ( ubLoop = 0; ubLoop < ubNumClimbSpots; ubLoop++ )
|
|
{
|
|
if ( (WhoIsThere2( pBuilding->sUpClimbSpots[ ubLoop ], 0 ) == NOBODY)
|
|
&& (WhoIsThere2( pBuilding->sDownClimbSpots[ ubLoop ], 1 ) == NOBODY) )
|
|
{
|
|
sDistance = PythSpacesAway( sStartGridNo, psClimbSpots[ ubLoop ] );
|
|
if (sDistance < sClosestDistance )
|
|
{
|
|
sClosestDistance = sDistance;
|
|
sClosestSpot = psClimbSpots[ ubLoop ];
|
|
}
|
|
}
|
|
}
|
|
|
|
return( sClosestSpot );
|
|
}
|
|
|
|
BOOLEAN SameBuilding( INT16 sGridNo1, INT16 sGridNo2 )
|
|
{
|
|
if ( gubBuildingInfo[ sGridNo1 ] == NO_BUILDING )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
if ( gubBuildingInfo[ sGridNo2 ] == NO_BUILDING )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
return( (BOOLEAN) (gubBuildingInfo[ sGridNo1] == gubBuildingInfo[ sGridNo2 ]) );
|
|
} |