From b48fd143624f2b887699acd98d9a4c55b792ab0e Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Tue, 23 Nov 2021 00:11:29 +0000 Subject: spawn changes and complex rings --- .../scripts/vscripts/gamemodes/_gamemode_ctf.nut | 122 +++++-------- .../mod/scripts/vscripts/mp/levels/mp_complex3.nut | 13 +- .../mod/scripts/vscripts/mp/spawn.nut | 203 +++++---------------- 3 files changed, 104 insertions(+), 234 deletions(-) (limited to 'Northstar.CustomServers/mod') diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut index 704f55d3b..dad94f672 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut @@ -63,93 +63,65 @@ void function CaptureTheFlag_Init() void function RateSpawnpoints_CTF( int checkClass, array spawnpoints, int team, entity player ) { - // ok this is the 3rd time rewriting this due to not understanding ctf spawns properly - // legit just - // if there are no enemies in base, spawn them in base - // if there are, spawn them outside of it ( but ideally still close ) - // max distance away should be like, angel city markets - - int spawnTeam = team - if ( HasSwitchedSides() ) - spawnTeam = GetOtherTeam( team ) - - array startSpawns = SpawnPoints_GetPilotStart( spawnTeam ) - array enemyPlayers = GetPlayerArrayOfTeam_Alive( GetOtherTeam( spawnTeam ) ) - - vector startSpawnAverage - bool enemyInBase = false - foreach ( entity startSpawn in startSpawns ) + // ctf spawn algo iteration 4 i despise extistence + array startSpawns = SpawnPoints_GetPilotStart( team ) + array enemyStartSpawns = SpawnPoints_GetPilotStart( GetOtherTeam( team ) ) + array enemyPlayers = GetPlayerArrayOfTeam_Alive( team ) + + // get average startspawn position and max dist between spawns + // could probably cache this, tbh, not like it should change outside of halftimes + vector averageFriendlySpawns + float maxFriendlySpawnDist + + foreach ( entity spawn in startSpawns ) { - startSpawnAverage += startSpawn.GetOrigin() - - foreach ( entity enemy in enemyPlayers ) + foreach ( entity otherSpawn in startSpawns ) { - if ( Distance( startSpawn.GetOrigin(), enemy.GetOrigin() ) <= 1000.0 ) - { - enemyInBase = true - break - } - } + float dist = Distance2D( spawn.GetOrigin(), otherSpawn.GetOrigin() ) + if ( dist > maxFriendlySpawnDist ) + maxFriendlySpawnDist = dist + } + + averageFriendlySpawns += spawn.GetOrigin() } - startSpawnAverage /= startSpawns.len() + averageFriendlySpawns /= startSpawns.len() + + // get average enemy startspawn position + vector averageEnemySpawns + + foreach ( entity spawn in enemyStartSpawns ) + averageEnemySpawns += spawn.GetOrigin() + + averageEnemySpawns /= enemyStartSpawns.len() - print( "spawn for " + player + " is there an enemy in base?" + enemyInBase ) + // from here, rate spawns + float baseDistance = Distance2D( averageFriendlySpawns, averageEnemySpawns ) + float spawnIterations = ( baseDistance / maxFriendlySpawnDist ) / 2 foreach ( entity spawn in spawnpoints ) { - float rating = 0.0 - - bool isStart = false - foreach ( entity startSpawn in startSpawns ) - { - if ( Distance2D( spawn.GetOrigin(), startSpawn.GetOrigin() ) < 1500.0 ) // this was for some reason the only distance i could get to work - { - isStart = true - break - } - } - - if ( isStart ) - { - if ( !enemyInBase ) - rating = 1000 + RandomFloat( 100.0 ) - else - rating = -1000.0 - } - else if ( !isStart && enemyInBase ) + // ratings should max/min out at 100 / -100 + // start by prioritizing closer spawns, but not so much that enemies won't really affect them + float rating = 10 * ( 1.0 - Distance2D( averageFriendlySpawns, spawn.GetOrigin() ) / baseDistance ) + float remainingZonePower = 1.0 // this is used to ensure that players that are in multiple zones at once shouldn't affect all those zones too hard + + for ( int i = 0; i < spawnIterations; i++ ) { - entity friendlyFlag - entity enemyFlag - if ( team == TEAM_IMC ) - { - friendlyFlag = file.imcFlagSpawn - enemyFlag = file.militiaFlagSpawn - } - else - { - friendlyFlag = file.militiaFlagSpawn - enemyFlag = file.imcFlagSpawn - } - - float dist = Distance2D( spawn.GetOrigin(), enemyFlag.GetOrigin() ) - float flagDist = Distance2D( startSpawnAverage, enemyFlag.GetOrigin() ) + vector zonePos = averageFriendlySpawns + Normalize( averageEnemySpawns - averageFriendlySpawns ) * ( i * maxFriendlySpawnDist ) + + float zonePower + foreach ( entity player in enemyPlayers ) + if ( Distance2D( player.GetOrigin(), zonePos ) < maxFriendlySpawnDist ) + zonePower += 1.0 / enemyPlayers.len() - if ( dist < ( flagDist / 2 ) ) // spawns shouldn't be closer to enemies than they are to us - rating = -1000.0 - if ( dist > flagDist * 1.1 ) // spawn is behind startspawns - rating = -1000.0 - else - { - rating = dist // closer spawns are better - - foreach( entity enemy in enemyPlayers ) // reduce rating if enemies are near by - if ( Distance( enemy.GetOrigin(), spawn.GetOrigin() ) < 500.0 ) - rating /= 2 - } + zonePower = min( zonePower, remainingZonePower ) + remainingZonePower -= zonePower + // scale rating based on distance between spawn and zone, baring in mind max 100 rating + rating -= ( zonePower * 100 ) * ( 1.0 - Distance2D( spawn.GetOrigin(), zonePos ) / baseDistance ) } - spawn.CalculateRating( checkClass, team, rating, rating ) + spawn.CalculateRating( checkClass, player.GetTeam(), rating, rating ) } } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_complex3.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_complex3.nut index 37b891699..2568b6231 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_complex3.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_complex3.nut @@ -1 +1,12 @@ -//fuck \ No newline at end of file +global function CodeCallback_MapInit + +void function CodeCallback_MapInit() +{ + AddCallback_EntitiesDidLoad( InitComplexRings ) +} + +void function InitComplexRings() +{ + entity rings = GetEntByScriptName( "rings_pristine" ) + thread PlayAnim( rings, "animated_slow" ) +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut index 26e4c7135..61fabb3cb 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut @@ -30,9 +30,7 @@ struct { bool respawnsEnabled = true string spawnpointGamemodeOverride - array preferSpawnNodes table noSpawnAreas - bool sidesSwitched = false bool frontlineBased = false float lastImcFrontlineRatingTime @@ -42,33 +40,13 @@ struct { } file void function Spawn_Init() -{ - AddCallback_GameStateEnter( eGameState.SwitchingSides, OnSwitchingSides ) - AddCallback_EntitiesDidLoad( InitPreferSpawnNodes ) - +{ AddSpawnCallback( "info_spawnpoint_human", InitSpawnpoint ) AddSpawnCallback( "info_spawnpoint_human_start", InitSpawnpoint ) AddSpawnCallback( "info_spawnpoint_titan", InitSpawnpoint ) AddSpawnCallback( "info_spawnpoint_titan_start", InitSpawnpoint ) } -void function InitPreferSpawnNodes() -{ - foreach ( entity hardpoint in GetEntArrayByClass_Expensive( "info_hardpoint" ) ) - { - if ( !hardpoint.HasKey( "hardpointGroup" ) ) - continue - - if ( hardpoint.kv.hardpointGroup != "A" && hardpoint.kv.hardpointGroup != "B" && hardpoint.kv.hardpointGroup != "C" ) - continue - - file.preferSpawnNodes.append( hardpoint.GetOrigin() ) - } - - //foreach ( entity frontline in GetEntArrayByClass_Expensive( "info_frontline" ) ) - // file.preferSpawnNodes.append( frontline.GetOrigin() ) -} - void function InitSpawnpoint( entity spawnpoint ) { spawnpoint.s.lastUsedTime <- -999 @@ -109,12 +87,8 @@ void function NoSpawnAreaLifetime( NoSpawnArea noSpawnArea ) void function DeleteNoSpawnArea( string noSpawnIdx ) { - try // unsure if the trycatch is necessary but better safe than sorry - { + if ( noSpawnIdx in file.noSpawnAreas ) delete file.noSpawnAreas[ noSpawnIdx ] - } - catch ( exception ) - {} } void function SetSpawnpointGamemodeOverride( string gamemode ) @@ -152,6 +126,7 @@ bool function InitRatings( entity player, int team ) return frontline.friendlyCenter == < 0, 0, 0 > && file.frontlineBased // if true, use startspawns } +// this sucks Frontline function GetCurrentFrontline( int team ) { float lastFrontlineRatingTime @@ -173,40 +148,6 @@ Frontline function GetCurrentFrontline( int team ) print( "rerating frontline..." ) Frontline frontline = GetFrontline( team ) - // this doesn't work lol - /*if ( frontline.friendlyCenter == < 0, 0, 0 > ) - { - // recalculate to startspawnpoint positions - array startSpawns = SpawnPoints_GetPilotStart( team ) - - vector averagePos - vector averageDir - foreach ( entity spawnpoint in startSpawns ) - { - averagePos.x += spawnpoint.GetOrigin().x - averagePos.y += spawnpoint.GetOrigin().y - averagePos.z += spawnpoint.GetOrigin().z - - averageDir.x += spawnpoint.GetAngles().x - averageDir.y += spawnpoint.GetAngles().y - averageDir.z += spawnpoint.GetAngles().z - } - - averagePos.x /= startSpawns.len() - averagePos.y /= startSpawns.len() - averagePos.z /= startSpawns.len() - - averageDir.x /= startSpawns.len() - averageDir.y /= startSpawns.len() - averageDir.z /= startSpawns.len() - - print( "average " + averagePos ) - - frontline.friendlyCenter = averagePos - frontline.origin = averagePos - frontline.combatDir = averageDir * -1 - }*/ - if ( team == TEAM_IMC ) { file.lastImcFrontlineRatingTime = Time() @@ -227,7 +168,7 @@ Frontline function GetCurrentFrontline( int team ) entity function FindSpawnPoint( entity player, bool isTitan, bool useStartSpawnpoint ) { int team = player.GetTeam() - if ( file.sidesSwitched ) + if ( HasSwitchedSides() ) team = GetOtherTeam( team ) useStartSpawnpoint = InitRatings( player, player.GetTeam() ) || useStartSpawnpoint // force startspawns if no frontline @@ -302,23 +243,23 @@ entity function GetBestSpawnpoint( entity player, array spawnpoints ) bool function IsSpawnpointValid( entity spawnpoint, int team ) { - //if ( !spawnpoint.HasKey( "ignoreGamemode" ) || ( spawnpoint.HasKey( "ignoreGamemode" ) && spawnpoint.kv.ignoreGamemode == "0" ) ) // used by script-spawned spawnpoints - //{ - // if ( file.spawnpointGamemodeOverride != "" ) - // { - // string gamemodeKey = "gamemode_" + file.spawnpointGamemodeOverride - // if ( spawnpoint.HasKey( gamemodeKey ) && ( spawnpoint.kv[ gamemodeKey ] == "0" || spawnpoint.kv[ gamemodeKey ] == "" ) ) - // return false - // } - // else if ( GameModeRemove( spawnpoint ) ) - // return false - //} + if ( !spawnpoint.HasKey( "ignoreGamemode" ) || ( spawnpoint.HasKey( "ignoreGamemode" ) && spawnpoint.kv.ignoreGamemode == "0" ) ) // used by script-spawned spawnpoints + { + if ( file.spawnpointGamemodeOverride != "" ) + { + string gamemodeKey = "gamemode_" + file.spawnpointGamemodeOverride + if ( spawnpoint.HasKey( gamemodeKey ) && ( spawnpoint.kv[ gamemodeKey ] == "0" || spawnpoint.kv[ gamemodeKey ] == "" ) ) + return false + } + else if ( GameModeRemove( spawnpoint ) ) + return false + } if ( Riff_FloorIsLava() && spawnpoint.GetOrigin().z < GetLethalFogTop() ) return false int compareTeam = spawnpoint.GetTeam() - if ( file.sidesSwitched && ( compareTeam == TEAM_MILITIA || compareTeam == TEAM_IMC ) ) + if ( HasSwitchedSides() && ( compareTeam == TEAM_MILITIA || compareTeam == TEAM_IMC ) ) compareTeam = GetOtherTeam( compareTeam ) if ( spawnpoint.GetTeam() > 0 && compareTeam != team && !IsFFAGame() ) @@ -344,96 +285,42 @@ bool function IsSpawnpointValid( entity spawnpoint, int team ) if ( projectile.GetTeam() != team ) return false - if ( Time() - spawnpoint.s.lastUsedTime <= 1.0 ) - return false - - return true -} - -void function RateSpawnpoints_Generic( int checkClass, array spawnpoints, int team, entity player ) -{ - // calculate ratings for preferred nodes - // this tries to prefer nodes with more teammates, then activity on them - // todo: in the future it might be good to have this prefer nodes with enemies up to a limit of some sort - // especially in ffa modes i could deffo see this falling apart a bit rn - // perhaps dead players could be used to calculate some sort of activity rating? so high-activity points with an even balance of friendly/unfriendly players are preferred - array preferSpawnNodeRatings - foreach ( vector preferSpawnNode in file.preferSpawnNodes ) + // los check + array enemyLosPlayers + if ( IsFFAGame() ) + enemyLosPlayers = GetPlayerArray() + else + enemyLosPlayers = GetPlayerArrayOfTeam( GetOtherTeam( team ) ) + + foreach ( entity enemyPlayer in enemyLosPlayers ) { - float currentRating + if ( enemyPlayer.GetTeam() == team || !IsAlive( enemyPlayer ) ) + continue - // this seems weird, not using rn - //Frontline currentFrontline = GetCurrentFrontline( team ) - //if ( !IsFFAGame() || currentFrontline.friendlyCenter != < 0, 0, 0 > ) - // currentRating += max( 0.0, ( 1000.0 - Distance2D( currentFrontline.origin, preferSpawnNode ) ) / 200 ) + // check distance, constant here is basically arbitrary + if ( Distance( enemyPlayer, spawnpoint ) > 1000.0 ) + continue - foreach ( entity nodePlayer in GetPlayerArray() ) - { - float currentChange = 0.0 - - // the closer a player is to a node the more they matter - float dist = Distance2D( preferSpawnNode, nodePlayer.GetOrigin() ) - if ( dist > 600.0 ) - continue - - currentChange = ( 600.0 - dist ) / 5 - if ( player == nodePlayer ) - currentChange *= -3 // always try to stay away from places we've already spawned - else if ( !IsAlive( nodePlayer ) ) // dead players mean activity which is good, but they're also dead so they don't matter as much as living ones - currentChange *= 0.6 - if ( nodePlayer.GetTeam() != player.GetTeam() ) // if someone isn't on our team and alive they're probably bad - { - if ( IsFFAGame() ) // in ffa everyone is on different teams, so this isn't such a big deal - currentChange *= -0.2 - else - currentChange *= -0.6 - } - - currentRating += currentChange - } + // check fov, constant here is stolen from every other place this is done + if ( VectorDot_PlayerToOrigin( enemyPlayer, spawnpoint.GetOrigin() ) < 0.8 ) + continue - preferSpawnNodeRatings.append( currentRating ) + // check actual los + if ( TraceLineSimple( enemyPlayer.EyePosition(), spawnpoint.GetOrigin() + < 0, 0, 48 >, enemyPlayer ) == 1.0 ) + return false } - foreach ( entity spawnpoint in spawnpoints ) - { - float currentRating - float petTitanModifier - // scale how much a given spawnpoint matters to us based on how far it is from each node - bool spawnHasRecievedInitialBonus = false - for ( int i = 0; i < file.preferSpawnNodes.len(); i++ ) - { - // bonus if autotitan is nearish - if ( IsAlive( player.GetPetTitan() ) && Distance( player.GetPetTitan().GetOrigin(), file.preferSpawnNodes[ i ] ) < 1200.0 ) - petTitanModifier += 10.0 - - float dist = Distance2D( spawnpoint.GetOrigin(), file.preferSpawnNodes[ i ] ) - if ( dist > 750.0 ) - continue - - if ( dist < 600.0 && !spawnHasRecievedInitialBonus ) - { - currentRating += 10.0 - spawnHasRecievedInitialBonus = true // should only get a bonus for simply being by a node once to avoid over-rating - } - - currentRating += ( preferSpawnNodeRatings[ i ] * ( ( 750.0 - dist ) / 75 ) ) + max( RandomFloat( 1.25 ), 0.9 ) - if ( dist < 250.0 ) // shouldn't get TOO close to an active node - currentRating *= 0.7 - - if ( spawnpoint.s.lastUsedTime < 10.0 ) - currentRating *= 0.7 - } - - float rating = spawnpoint.CalculateRating( checkClass, team, currentRating, currentRating + petTitanModifier ) - //print( "spawnpoint at " + spawnpoint.GetOrigin() + " has rating: " + ) + if ( Time() - spawnpoint.s.lastUsedTime <= 1.0 ) + return false - if ( rating != 0.0 || currentRating != 0.0 ) - print( "rating = " + rating + ", internal rating = " + currentRating ) - } + return true } -void function OnSwitchingSides() -{ - file.sidesSwitched = true +void function RateSpawnpoints_Generic( int checkClass, array spawnpoints, int team, entity player ) +{ + // generic spawns v2 + array startSpawns = checkClass == TD_TITAN ? SpawnPoints_GetTitanStart( team ) : SpawnPoints_GetPilotStart( team ) + + // realistically, this should spawn people fairly spread out across the map, preferring being closer to their startspawns + // should spawn like, near fights, but not in them } \ No newline at end of file -- cgit v1.2.3