From 207facbc402f5639cbcd31f079214351ef605cf2 Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Tue, 22 Jun 2021 14:30:49 +0100 Subject: initial commit after moving to new repo --- .../ai/_ai_stationary_firing_positions.gnut | 261 +++++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 Northstar.CustomServers/scripts/vscripts/ai/_ai_stationary_firing_positions.gnut (limited to 'Northstar.CustomServers/scripts/vscripts/ai/_ai_stationary_firing_positions.gnut') diff --git a/Northstar.CustomServers/scripts/vscripts/ai/_ai_stationary_firing_positions.gnut b/Northstar.CustomServers/scripts/vscripts/ai/_ai_stationary_firing_positions.gnut new file mode 100644 index 000000000..50b6cc759 --- /dev/null +++ b/Northstar.CustomServers/scripts/vscripts/ai/_ai_stationary_firing_positions.gnut @@ -0,0 +1,261 @@ +global function AddStationaryAIPosition //Add stationary positions to pending list. +global function AddTestTargetPosForStationaryPositionValidation //Add test target location for validating stationary positions. +global function ValidateAndFinalizePendingStationaryPositions //Runs error-checking/validation logic on stationary positions and finalizes them for use by AI. +global function GetRandomStationaryPosition +global function GetClosestAvailableStationaryPosition +global function ClaimStationaryAIPosition +global function ReleaseStationaryAIPosition + +global enum eStationaryAIPositionTypes +{ + MORTAR_TITAN, + MORTAR_SPECTRE, + SNIPER_TITAN, + LAUNCHER_REAPER +} + +global struct StationaryAIPosition +{ + vector origin + bool inUse +} + +global struct ArrayDistanceEntryForStationaryAIPosition +{ + float distanceSqr + StationaryAIPosition& ent + vector origin +} + +struct +{ + array validationTestTargets + table > pendingPositions + table > stationaryPositions +} file + +void function AddTestTargetPosForStationaryPositionValidation( vector origin ) +{ + file.validationTestTargets.append( origin ) +} + +void function AddStationaryAIPosition( vector origin, int type ) +{ + AddPendingStationaryAIPosition_Internal( origin, type ) +} + +void function AddStationaryAIPosition_Internal( vector origin, int type ) +{ + StationaryAIPosition pos + pos.origin = origin + pos.inUse = false + + //Throw warnings for bad positions + foreach ( vector testTarget in file.validationTestTargets ) + { + switch( type ) + { + case eStationaryAIPositionTypes.MORTAR_TITAN: + if ( NavMesh_ClampPointForHullWithExtents( origin, HULL_TITAN, <100, 100, 20> ) == null ) + { + CodeWarning( "Mortar Titan Firing Position at " + origin + " does not have enough space to accomidate Titan, skipping." ) + return + } + break + + #if MP + case eStationaryAIPositionTypes.MORTAR_SPECTRE: + + array testLocations = MortarSpectreGetSquadFiringPositions( origin, testTarget ) + + foreach ( vector testLocation in testLocations ) + { + if ( NavMesh_ClampPointForHullWithExtents( testLocation, HULL_HUMAN, <100, 100, 20> ) == null ) + { + CodeWarning( "Mortar Spectre Firing Position at " + origin + " does not have enough space to accomidate squad, skipping." ) + return + } + } + + break + #endif //MP + + case eStationaryAIPositionTypes.SNIPER_TITAN: + if ( NavMesh_ClampPointForHullWithExtents( origin, HULL_TITAN, <100, 100, 20> ) == null ) + { + CodeWarning( "Sniper Titan Firing Position at " + origin + " does not have enough space to accomidate Titan, skipping." ) + return + } + break + + case eStationaryAIPositionTypes.LAUNCHER_REAPER: + if ( NavMesh_ClampPointForHullWithExtents( origin, HULL_MEDIUM, <100, 100, 20> ) == null ) + { + CodeWarning( "Tick Launching Reaper Firing Position at " + origin + " does not have enough space to accomidate Reaper, skipping." ) + return + } + break + } + } + + if ( !( type in file.stationaryPositions ) ) + { + file.stationaryPositions[ type ] <- [] + } + + file.stationaryPositions[ type ].append( pos ) +} + +//Function tests stationary AI positions for given type relative to given mortar target. +void function AddPendingStationaryAIPosition_Internal( vector origin, int type ) +{ + if ( !( type in file.pendingPositions ) ) + file.pendingPositions[ type ] <- [] + + //Add position to table so we can validate and add it when all entities finish loading. + file.pendingPositions[ type ].append( origin ) +} + +void function ValidateAndFinalizePendingStationaryPositions() +{ + + Assert( file.validationTestTargets.len(), "Test targets are required to validate stationary positions. Use AddTestTargetPosForStationaryPositionValidation to add them before running validation." ) + + foreach ( type, origins in file.pendingPositions ) + { + //Make sure we have pending positions for given ai type. + Assert( file.pendingPositions[ type ].len(), "Stationary Positions for type " + type + " could not be found in this map. Add Some." ) + + foreach ( vector origin in origins ) + { + AddStationaryAIPosition_Internal( origin, type ) + } + + //Make sure we have positions for given AI type after we validate and finalize positions. + Assert( file.stationaryPositions[ type ].len(), "No valid stationary positions for type " + type + " remain after validation. Adjust positions and retry." ) + } +} + +StationaryAIPosition function GetClosestAvailableStationaryPosition( vector origin, float maxDist, int type ) +{ + + array resultArray = [] + float maxDistSqr = maxDist * maxDist + + array positions = file.stationaryPositions[type] + + array allResults = ArrayDistanceResultsForStationaryAIPosition( positions, origin ) + allResults.sort( DistanceCompareClosestForStationaryAIPosition ) + + //Remove all in use stationary positions up front. + array freePositions + foreach ( result in allResults ) + { + StationaryAIPosition position = result.ent + if ( position.inUse ) + continue + + freePositions.append( result ) + } + + //Tell us if all spots for a given AI type are taken. + Assert( freePositions.len() > 0, "Could not find free mortar positions for type " + type + ", all positions are currently in use. Add more AddStationaryTitanPosition to the map." ) + + foreach( result in freePositions ) + { + StationaryAIPosition position = result.ent + + // if too far, throw warning and continue search beyond maxDist + if ( result.distanceSqr > maxDistSqr ) + { + CodeWarning( "Couldn't find a mortar position within " + maxDist + " units for type " + type + " around " + origin.tostring() + " that wasn't in use. Expanding Search. Add more AddStationaryTitanPositions to the map near this point." ) + } + + return position + } + + unreachable +} + +StationaryAIPosition function GetRandomStationaryPosition( vector origin, float maxDist, int type ) +{ + array resultArray = [] + array positions = file.stationaryPositions[type] + + //Remove all in use stationary positions up front. + array freePositions + foreach ( position in positions ) + { + if ( position.inUse ) + continue + + freePositions.append( position ) + } + + //Tell us if all spots for a given AI type are taken. + Assert( freePositions.len() > 0, "Could not find free mortar positions for type " + type + ", all positions are currently in use. Add more AddStationaryTitanPosition to the map." ) + + int attemptCount = 1 + while ( resultArray.len() == 0 ) + { + + //Expand our search radius each time we reattempt our search. + float maxDistSqr = ( maxDist * attemptCount ) * ( maxDist * attemptCount ) + + foreach( position in freePositions ) + { + float dist = Distance2DSqr( origin, position.origin ) + if ( dist <= maxDistSqr ) + resultArray.append( position ) + } + + if ( resultArray.len() == 0 ) + { + CodeWarning( "Couldn't find a mortar position within " + maxDist + " units for type " + type + " around " + origin.tostring() + " that wasn't in use. Expanding Search. Add more AddStationaryTitanPositions to the map near this point." ) + attemptCount += 1 + } + } + + return resultArray.getrandom() +} + +void function ClaimStationaryAIPosition( StationaryAIPosition stationaryTitanPositions ) +{ + Assert( stationaryTitanPositions.inUse == false ) + stationaryTitanPositions.inUse = true +} + +void function ReleaseStationaryAIPosition( StationaryAIPosition stationaryTitanPositions ) +{ + Assert( stationaryTitanPositions.inUse == true ) + stationaryTitanPositions.inUse = false +} + +array function ArrayDistanceResultsForStationaryAIPosition( array entArray, vector origin ) +{ + array allResults + + foreach ( ent in entArray ) + { + ArrayDistanceEntryForStationaryAIPosition entry + + vector entOrigin = ent.origin + entry.distanceSqr = DistanceSqr( entOrigin, origin ) + entry.ent = ent + entry.origin = entOrigin + + allResults.append( entry ) + } + + return allResults +} + +int function DistanceCompareClosestForStationaryAIPosition( ArrayDistanceEntryForStationaryAIPosition a, ArrayDistanceEntryForStationaryAIPosition b ) +{ + if ( a.distanceSqr > b.distanceSqr ) + return 1 + else if ( a.distanceSqr < b.distanceSqr ) + return -1 + + return 0; +} \ No newline at end of file -- cgit v1.2.3