::CONST <- getconsttable() ::ROOT <- getroottable() ::MAX_CLIENTS <- MaxClients().tointeger() ::VectorAngles <- function(forward) { local yaw, pitch if (forward.y == 0.0 && forward.x == 0.0) { yaw = 0.0 if (forward.z > 0.0) pitch = 270.0 else pitch = 90.0 } else { yaw = (atan2(forward.y, forward.x) * 180.0 / PI) if (yaw < 0.0) yaw += 360.0 pitch = (atan2(-forward.z, forward.Length2D()) * 180.0 / PI) if (pitch < 0.0) pitch += 360.0 } return QAngle(pitch, yaw, 0.0) } ::Lerp <- function( start, end, frac ) { return start + (end - start) * frac } if (!("ConstantNamingConvention" in ROOT)) foreach (a,b in Constants) foreach (k,v in b) { CONST[k] <- v != null ? v : 0 ROOT[k] <- v != null ? v : 0 } foreach(k, v in ::Entities.getclass()) if (k != "IsValid" && !(k in ROOT)) ROOT[k] <- ::Entities[k].bindenv(::Entities) foreach(k, v in ::NetProps.getclass()) if (k != "IsValid" && !(k in ROOT)) ROOT[k] <- ::NetProps[k].bindenv(::NetProps) local OTHER_CONSTANTS = { MASK_ALL = -1 MASK_SPLITAREAPORTAL = 48 MASK_SOLID_BRUSHONLY = 16395 MASK_WATER = 16432 MASK_BLOCKLOS = 16449 MASK_OPAQUE = 16513 MASK_DEADSOLID = 65547 MASK_PLAYERSOLID_BRUSHONLY = 81931 MASK_NPCWORLDSTATIC = 131083 MASK_NPCSOLID_BRUSHONLY = 147467 MASK_CURRENT = 16515072 MASK_SHOT_PORTAL = 33570819 MASK_SOLID = 33570827 MASK_BLOCKLOS_AND_NPCS = 33570881 MASK_OPAQUE_AND_NPCS = 33570945 MASK_VISIBLE_AND_NPCS = 33579137 MASK_PLAYERSOLID = 33636363 MASK_NPCSOLID = 33701899 MASK_SHOT_HULL = 100679691 MASK_SHOT = 1174421507 LIFE_ALIVE = 0 LIFE_DYING = 1 LIFE_DEAD = 2 LIFE_RESPAWNABLE = 3 LIFE_DISCARDBODY = 4 TF_STUN_NONE = 0 TF_STUN_MOVEMENT = 1 TF_STUN_CONTROLS = 2 TF_STUN_MOVEMENT_FORWARD_ONLY = 4 TF_STUN_SPECIAL_SOUND = 8 TF_STUN_DODGE_COOLDOWN = 16 TF_STUN_NO_EFFECTS = 32 TF_STUN_LOSER_STATE = 64 TF_STUN_BY_TRIGGER = 128 TF_STUN_SOUND = 256 SND_NOFLAGS = 0 SND_CHANGE_VOL = 1 SND_CHANGE_PITCH = 2 SND_STOP = 4 SND_SPAWNING = 8 SND_DELAY = 16 SND_STOP_LOOPING = 32 SND_SPEAKER = 64 SND_SHOULDPAUSE = 128 SND_IGNORE_PHONEMES = 256 SND_IGNORE_NAME = 512 SND_DO_NOT_OVERWRITE_EXISTING_ON_CHANNEL = 1024 DEG2RAD = 0.0174532924 RAD2DEG = 57.295779513 FLT_MIN = 1.175494e-38 FLT_MAX = 3.402823466e+38 INT_MIN = -2147483648 INT_MAX = 2147483647 DAMAGE_NO = 0 DAMAGE_EVENTS_ONLY = 1 DAMAGE_YES = 2 DAMAGE_AIM = 3 OBJ_DISPENSER = 0 OBJ_TELEPORTER = 1 OBJ_SENTRYGUN = 2 OBJ_ATTACHMENT_SAPPER = 3 OBJ_LAST = 4 TF_AMMO_DUMMY = 0 TF_AMMO_PRIMARY = 1 TF_AMMO_SECONDARY = 2 TF_AMMO_METAL = 3 TF_AMMO_GRENADES1 = 4 TF_AMMO_GRENADES2 = 5 TF_AMMO_GRENADES3 = 6 TFCOLLISION_GROUP_GRENADES = 20 TFCOLLISION_GROUP_OBJECT = 21 TFCOLLISION_GROUP_OBJECT_SOLIDTOPLAYERMOVEMENT = 22 TFCOLLISION_GROUP_COMBATOBJECT = 23 TFCOLLISION_GROUP_ROCKETS = 24 TFCOLLISION_GROUP_RESPAWNROOMS = 25 TFCOLLISION_GROUP_PUMPKIN_BOMB = 26 TFCOLLISION_GROUP_ROCKET_BUT_NOT_WITH_OTHER_ROCKETS = 27 // damagefilter redefinitions DMG_USE_HITLOCATIONS = DMG_AIRBOAT DMG_HALF_FALLOFF = DMG_RADIATION DMG_CRITICAL = DMG_ACID DMG_RADIUS_MAX = DMG_ENERGYBEAM DMG_IGNITE = DMG_PLASMA DMG_USEDISTANCEMOD = DMG_SLOWBURN DMG_NOCLOSEDISTANCEMOD = DMG_POISON DMG_MELEE = DMG_BLAST_SURFACE DMG_DONT_COUNT_DAMAGE_TOWARDS_CRIT_RATE = DMG_DISSOLVE } foreach(k,v in OTHER_CONSTANTS) if(!(k in ROOT)) { CONST[k] <- v ROOT[k] <- v } local PlayerStats = {} for(local i = 1; i <= MAX_CLIENTS; i++) { local hPlayer = PlayerInstanceFromIndex(i) // printl( hPlayer ) if(hPlayer && !hPlayer.IsFakeClient() && hPlayer.GetTeam() == TF_TEAM_RED) { local sNetworkID = GetPropString(hPlayer, "m_szNetworkIDString") PlayerStats[sNetworkID] <- { iDeaths = 0, iDowns = 0, iRevives = 0, iKills = 0, iAssists = 0 } } } local AI_Squads = {} local AI_Targets = {} local AI_SniperSpots = [ Vector( 2411, 4106, 230 ), Vector( 2078, 4106, 230 ), Vector( 384, 4106, 230 ), Vector( 795, 4106, 230 ), Vector( 1414, 3861, 36 ), Vector( 2936, 4507, 534 ) ] local AI_SniperSpotsInfo = {} ::RustEmpire <- { function OnGameEvent_recalculate_holidays(_) { foreach( index, val in AI_SniperSpots ) { if( !FindByName( "info_target", format( "sniper_spot_%d", index ) ) ) { local hSniperSpot = SpawnEntityFromTable( "info_target", { targetname = format( "sniper_spot_%d", index ).tostring() } ) hSniperSpot.SetOrigin( val ) AI_SniperSpotsInfo[index] <- { sName = hSniperSpot.GetName(), bOccupied = false, hOccupiedBy = null } } else AI_SniperSpotsInfo[index] <- { sName = format( "sniper_spot_%d", index ), bOccupied = false, hOccupiedBy = null } } for(local i = 1; i <= MAX_CLIENTS; i++) { local hPlayer = PlayerInstanceFromIndex(i) if( hPlayer && !hPlayer.IsFakeClient() ) { hPlayer.ValidateScriptScope() PlayerStats[GetPropString(hPlayer, "m_szNetworkIDString")] <- { iDeaths = 0, iDowns = 0, iRevives = 0, iKills = 0, iAssists = 0 } local scope = hPlayer.GetScriptScope() if( "hInfoTarget" in scope ) EntFireByHandle( scope.hInfoTarget, "kill", null, 0, null, null ) local str = GetPropString(hPlayer, "m_szNetworkIDString").tostring() + "_target" local hTarget = SpawnEntityFromTable( "info_target", { targetname = str } ) hTarget.SetOrigin( hPlayer.EyePosition() ) hTarget.SetLocalOrigin( hPlayer.EyePosition() ) hTarget.SetOwner( hPlayer ) hTarget.AcceptInput("SetParent", "!activator", hPlayer, null) hTarget.SetLocalOrigin( Vector( 0, 0, hPlayer.EyePosition() - hPlayer.GetOrigin() ) ) hTarget.ValidateScriptScope() hTarget.GetScriptScope().hOwnerEnt <- hPlayer scope.hInfoTarget <- hTarget } } local hTriggerPush while(hTriggerPush = FindByClassname(hTriggerPush, "trigger_push")) { EntityOutputs.AddOutput( hTriggerPush, "OnStartTouch", "!activator", "RunScriptCode", "if( activator && GetPropVector( activator, `m_vecAbsVelocity` ).z > 10 ) activator.SetAbsVelocity( Vector( 0, 0, 200 ) )", -1, -1 ) } delete ::RustEmpire } /* AI DIRECTOR SECTION Switched over to VScript for this incase I need to fuck with nav Goal: Calculate which player to target in order from best to worst based on kills, downs, deaths, and revives. Also take in account both the bot's and player's weapons for both threat value and engaging distance. Spawn an info_target on each player's head to serve as the InterruptAction target. Take different rolls depending on number of bots. EX: Say there are 7 bots, 4 are attacking, 3 can be more defensive or play sniper. Dynamically find Defensive points. Find points that are farther than the bot would normally attack from, find a spot outside of the target player's LoS. Try to stick to 25-60% farther away than normal for hold point Join squads based on number of bots and which target the bot is going after (threat level of the targeted player) Desired_Distance = PlayerDist - ( ( PlayerDist - BotDist ) / BotDist_Weight ) Weight = 2 means half way perfectly Weight cannot go below 1, otherwise weirdness will occur Low weight means stick to BotDist High weight means stick to PlayerDist +----------------+-----------+--------------+------------+ | PlayDist = 100 | LowWeight | MediumWeight | HighWeight | | | 1.1 | 2 | 5 | +----------------+-----------+--------------+------------+ | LowBotDist | 190 | 150 | 120 | | 200 | | | | +----------------+-----------+--------------+------------+ | MediumBotDist | 554 | 350 | 200 | | 600 | | | | +----------------+-----------+--------------+------------+ | HighBotDist | 918 | 550 | 280 | | 1000 | | | | +----------------+-----------+--------------+------------+ +-----------------+-----------+--------------+------------+ | PlayDist = 1500 | LowWeight | MediumWeight | HighWeight | | | 1.1 | 2 | 5 | +-----------------+-----------+--------------+------------+ | LowBotDist | 318 | 850 | 1240 | | 200 | | | | +-----------------+-----------+--------------+------------+ | MediumBotDist | 681 | 1050 | 1320 | | 600 | | | | +-----------------+-----------+--------------+------------+ | HighBotDist | 1045 | 1250 | 1400 | | 1000 | | | | +-----------------+-----------+--------------+------------+ (Hold AI) Find a pos that would be adequate Get radius around player which is greater than their dist or max of 3000 Get ( Cos( x ), Sin( x ) ) where x is a random number between 0 and 2pi (Uses radians) This will work for unit circle, just multiply the output by the size of the circle Make sure point to move to is near a wall Line trace in the nearest cardinal direction towards the target and set pos to hit pos - 64 (space) (round down to the nearest cardinal direction) First start by moving in the direction towards the player floor( ( angle - 180 ) / 90 ) * 90, then get left and right and go with the closest distance Make sure point does not have line of sight with target If it does then move perpendicular to the LoS trace in a direction (round down to the nearest cardinal direction) floor( ( angle + 90 ) / 90 ) * 90 Make sure there is still space Always face target Scan for any nearby enemies (33% of weapon's range) If no enemies detected: look at target, even through walls otherwise: look at closest target Squads will push through, non squads will sit Shotgunners will also hard push */ function OnGameEvent_player_death( event_table ) { local userid = event_table.userid local hPlayer = GetPlayerFromUserID( userid ) local attacker_id = event_table.attacker local hAttacker = GetPlayerFromUserID( attacker_id ) local hWeapon = event_table.weapon local iDamageBits = event_table.damagebits local assister_id = event_table.assister local hAssister = GetPlayerFromUserID( assister_id ) local iCilent_kill = event_table.silent_kill local iCrit_type = event_table.crit_type if( hPlayer.IsPlayer() && hPlayer.IsFakeClient() ) { if( hAttacker && hAttacker != hPlayer ) { local sNetworkID = GetPropString(hAttacker, "m_szNetworkIDString") PlayerStats[sNetworkID].iKills += 1 } if( hAssister && hAttacker != hPlayer ) { local sNetworkID2 = GetPropString(hAssister, "m_szNetworkIDString") PlayerStats[sNetworkID2].iAssists += 1 } if( hPlayer.GetScriptScope().AI_Mode == "sniper" ) { AI_Current_Snipers-- AI_SniperSpotsInfo[ hPlayer.GetScriptScope().iOccupiedSlot ].bOccupied = false AI_SniperSpotsInfo[ hPlayer.GetScriptScope().iOccupiedSlot ].hOccupiedBy = null } else if( hPlayer.GetScriptScope().AI_Mode == "protector" ) AI_Current_Protectors-- else AI_Current_Attackers-- if( ( "bIsBotInSquad" in hPlayer.GetScriptScope() ) && hPlayer.GetScriptScope().bIsBotInSquad ) { AI_Squads[hPlayer.GetScriptScope().iSquadNumber].iBotCount -= 1 if( hPlayer.GetScriptScope().bIsBotLeader ) AI_Squads[hPlayer.GetScriptScope().iSquadNumber].hLeader = null // if( AI_Squads[hPlayer.GetScriptScope().iSquadNumber].iBotCount <= 0 ) // AI_Squads.rawdelete( hPlayer.GetScriptScope().iSquadNumber ) hPlayer.GetScriptScope().bIsBotInSquad <- null hPlayer.GetScriptScope().bIsBotLeader <- null hPlayer.GetScriptScope().hSquadLeader <- null hPlayer.GetScriptScope().iSquadNumber <- null } // printl( hPlayer ) hPlayer.GetScriptScope().vecProtect_Point <- null hPlayer.GetScriptScope().AI_Mode <- null hPlayer.GetScriptScope().bHasLoSToTarget <- null hPlayer.GetScriptScope().UpdateDelay <- null hPlayer.GetScriptScope().bAboutToSpawn <- null hPlayer.TerminateScriptScope() } if( !hPlayer.IsFakeClient() && hPlayer.GetCustomAttribute( "duel loser account id", 0 ) == 1 && hAttacker != hPlayer ) { local sNetworkID = GetPropString(hPlayer, "m_szNetworkIDString") PlayerStats[sNetworkID].iDowns += 1 } else if ( !hPlayer.IsFakeClient() && hPlayer.GetCustomAttribute( "duel loser account id", 0 ) == 0 && hAttacker != hPlayer ) { local sNetworkID = GetPropString(hPlayer, "m_szNetworkIDString") PlayerStats[sNetworkID].iDeaths += 1 } } function OnScriptHook_OnTakeDamage( event_table ) { local hVictim = event_table.const_entity local hAttacker = event_table.attacker local hInflictor = event_table.inflictor local hWeapon = event_table.weapon local vecHit = event_table.damage_position local flDamage = event_table.damage if( hVictim && hAttacker && hVictim.IsPlayer() && hAttacker.IsPlayer() && hVictim.IsFakeClient() && hVictim.GetTeam() != hAttacker.GetTeam() ) hVictim.AddCustomAttribute( "spread penalty", Lerp( 1, 3, flDamage / 100 ), 0.5 ) } function OnGameEvent_player_spawn( event_table ) { local sNetworkID = event_table.userid local hPlayer = GetPlayerFromUserID( sNetworkID ) local iTeamNum = event_table.team if( hPlayer && !hPlayer.IsFakeClient() ) { // if( iTeamNum == TF_TEAM_RED ) // { hPlayer.ValidateScriptScope() PlayerStats[GetPropString(hPlayer, "m_szNetworkIDString")] <- { iDeaths = 0, iDowns = 0, iRevives = 0, iKills = 0, iAssists = 0 } local scope = hPlayer.GetScriptScope() if( "hInfoTarget" in scope ) EntFireByHandle( scope.hInfoTarget, "kill", null, 0, null, null ) local str = GetPropString(hPlayer, "m_szNetworkIDString").tostring() + "_target" local hTarget = SpawnEntityFromTable( "info_target", { targetname = str } ) hTarget.SetOrigin( hPlayer.EyePosition() ) hTarget.SetLocalOrigin( hPlayer.EyePosition() ) hTarget.SetOwner( hPlayer ) hTarget.AcceptInput("SetParent", "!activator", hPlayer, null) hTarget.ValidateScriptScope() hTarget.GetScriptScope().hOwnerEnt <- hPlayer scope.hInfoTarget <- hTarget // printl( scope.hInfoTarget ) // } } else if ( hPlayer && hPlayer.IsFakeClient() ) { if( iTeamNum == TF_TEAM_BLUE ) { AI_TotalBots = 0 for(local i = 1; i <= MAX_CLIENTS; i++) { local hOtherBot = PlayerInstanceFromIndex(i) if( hOtherBot && hOtherBot.IsFakeClient() && hOtherBot.IsAlive() && hOtherBot.GetTeam() == TF_TEAM_BLUE ) AI_TotalBots++ } hPlayer.TerminateScriptScope() hPlayer.ValidateScriptScope() local scope = hPlayer.GetScriptScope() scope.bAboutToSpawn <- true } } } function OnGameEvent_mvm_begin_wave(event_table) { for(local i = 1; i <= MAX_CLIENTS; i++) { local hPlayer = PlayerInstanceFromIndex(i) if( hPlayer && !hPlayer.IsFakeClient() ) { hPlayer.ValidateScriptScope() PlayerStats[GetPropString(hPlayer, "m_szNetworkIDString")] <- { iDeaths = 0, iDowns = 0, iRevives = 0, iKills = 0, iAssists = 0 } local scope = hPlayer.GetScriptScope() if( "hInfoTarget" in scope ) EntFireByHandle( scope.hInfoTarget, "kill", null, 0, null, null ) local str = GetPropString(hPlayer, "m_szNetworkIDString").tostring() + "_target" local hTarget = SpawnEntityFromTable( "info_target", { targetname = str } ) hTarget.SetOrigin( hPlayer.EyePosition() ) hTarget.SetLocalOrigin( hPlayer.EyePosition() ) hTarget.SetOwner( hPlayer ) hTarget.AcceptInput("SetParent", "!activator", hPlayer, null) hTarget.ValidateScriptScope() hTarget.GetScriptScope().hOwnerEnt <- hPlayer scope.hInfoTarget <- hTarget } } foreach( index, val in AI_SniperSpots ) { if( !FindByName( "info_target", format( "sniper_spot_%d", index ) ) ) { local hSniperSpot = SpawnEntityFromTable( "info_target", { targetname = format( "sniper_spot_%d", index ).tostring() } ) hSniperSpot.SetOrigin( val ) AI_SniperSpotsInfo[index] <- { sName = hSniperSpot.GetName(), bOccupied = false, hOccupiedBy = null } } else AI_SniperSpotsInfo[index] <- { sName = format( "sniper_spot_%d", index ), bOccupied = false, hOccupiedBy = null } } local hTriggerPush while(hTriggerPush = FindByClassname(hTriggerPush, "trigger_push")) { EntityOutputs.AddOutput( hTriggerPush, "OnStartTouch", "!activator", "RunScriptCode", "if( activator && GetPropVector( activator, `m_vecAbsVelocity` ).z > 10 ) activator.SetAbsVelocity( Vector( 0, 0, 200 ) )", -1, -1 ) } } hThinkEnt = SpawnEntityFromTable("logic_relay", {}) function OnTick() { for(local i = 1; i <= MAX_CLIENTS; i++) { local hPlayer = PlayerInstanceFromIndex(i) if(hPlayer && !hPlayer.IsFakeClient() && hPlayer.GetTeam() == TF_TEAM_RED) { // printl( AI_Squads.len() ) if( hPlayer.GetCustomAttribute( "tool escrow until date", 0 ) == 1 ) { hPlayer.RemoveCustomAttribute( "tool escrow until date" ) local sNetworkID = GetPropString(hPlayer, "m_szNetworkIDString") PlayerStats[sNetworkID].iRevives += 1 } } else if(hPlayer && hPlayer.IsFakeClient() && hPlayer.GetTeam() == TF_TEAM_BLUE ) { if( hPlayer.IsAlive() ) { local selfScope = hPlayer.GetScriptScope() if( ( "bAboutToSpawn" in selfScope ) && selfScope.bAboutToSpawn == true ) { selfScope.bAboutToSpawn <- false AI_SetTarget( hPlayer ) AI_SetMode( hPlayer ) AI_SetSquad( hPlayer ) selfScope.ReactionTime <- Time() + 1 selfScope.ReactionTimeResetDelay <- Time() + 2 hPlayer.SetMaxVisionRangeOverride( -1 ) hPlayer.AddBotAttribute(SUPPRESS_FIRE) local action = "Mobber" if( selfScope.AI_Mode == "protector" || selfScope.AI_Mode == "sniper" ) action = "Passive" EntFireByHandle( hPlayer, "$BotCommand", action, 0.5, hPlayer, hPlayer ) if( selfScope.AI_Mode == "sniper" ) { local random = RandomInt( 0, AI_SniperSpotsInfo.len() - 1 ) while( AI_SniperSpotsInfo[random].bOccupied ) random = RandomInt( 0, AI_SniperSpotsInfo.len() - 1 ) // DebugDrawBox( FindByName( "info_target", AI_SniperSpotsInfo[random].sName ).GetOrigin(), Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 255, 255, 0, 200, 10 ) AI_SniperSpotsInfo[random].bOccupied = true AI_SniperSpotsInfo[random].hOccupiedBy = hPlayer selfScope.iOccupiedSlot <- random } } if( !( "bAboutToSpawn" in selfScope ) || selfScope.bAboutToSpawn != false ) return local hSecondaryTarget = FindByClassnameNearest( "info_target", hPlayer.GetCenter(), AI_BotWeaponThreatTable[hPlayer.GetActiveWeapon().GetName()].Distance * 1.33 / hPlayer.GetActiveWeapon().GetAttribute("weapon spread bonus", 1 ) ) local hTargetEnt = selfScope.hTarget local flReactionTime = 0.4 local flReactionTimeResetDelay = 2 if( hSecondaryTarget && ( "hOwnerEnt" in hSecondaryTarget.GetScriptScope() ) && hSecondaryTarget.GetScriptScope().hOwnerEnt != hTargetEnt ) { hTargetEnt = hSecondaryTarget.GetScriptScope().hOwnerEnt selfScope.ReactionTime = Time() + ( flReactionTime * 1.5 ) } local Angle = VectorAngles( hTargetEnt.EyePosition() - hPlayer.EyePosition() ) local vecStart = hPlayer.EyePosition() - Vector( 0, 0, 8 ) local vecEnd = hTargetEnt.EyePosition() - Vector( 0, 0, 8 ) local Trace = { start = vecStart, end = vecEnd, ignore = hPlayer, mask = MASK_SHOT_HULL } local flDist = ( vecEnd - vecStart ).Length() local flDistMax = AI_GetDesiredDistance( hPlayer, hTargetEnt ) * 1.5 if( selfScope.AI_Mode == "protector") flDistMax *= 1.5 if( "AI_Mode" in selfScope ) { if( selfScope.AI_Mode == "sniper" ) { flReactionTime = 2 flReactionTimeResetDelay = 12 flDistMax = 8000 } } if( Angle.Pitch() > 180 ) Angle -= QAngle( 360, 0, 0 ) hPlayer.SnapEyeAngles( Angle ) if( selfScope.AI_Mode == "protector" && !("vecProtect_Point" in selfScope) ) AI_SetProtectionPoint( hPlayer, hTargetEnt ) if( !("UpdateDelay" in selfScope ) ) selfScope.UpdateDelay <- Time() if( Time() >= selfScope.UpdateDelay && hTargetEnt && hTargetEnt.IsAlive() ) { // hPlayer.AcceptInput( "$BotCommand", "switch_action Passive", hPlayer, null ) if( !("bIsBotInSquad" in selfScope) || selfScope.bIsBotInSquad != true || selfScope.bIsBotLeader == true || ( AI_Squads[selfScope.iSquadNumber].hLeader == null && hPlayer.HasBotTag( "ai_nosquadrejoin" ) ) ) { local bDoAI = true if( ("bIsBotLeader" in selfScope) && selfScope.bIsBotLeader ) { DebugDrawText( hPlayer.GetOrigin() + Vector(0, 0, hPlayer.GetBoundingMaxs().z + 16), ( selfScope.iSquadNumber.tostring() ) + " Leader", true, 0.5 ) bDoAI = false local iSquadMembersInRadius = 0 local flRadius = AI_Max_Squad_Distance * 1.5 for(local hSquadMember; hSquadMember = FindInSphere( hSquadMember, hPlayer.GetOrigin(), flRadius ); ) { if( hSquadMember.IsPlayer() && hSquadMember.IsFakeClient() && hSquadMember.IsAlive() && hSquadMember.GetTeam() == hPlayer.GetTeam() && ("bIsBotInSquad" in hSquadMember.GetScriptScope()) && hSquadMember.GetScriptScope().iSquadNumber == selfScope.iSquadNumber ) iSquadMembersInRadius++ } if( AI_Squads[selfScope.iSquadNumber].iBotCount <= iSquadMembersInRadius ) bDoAI = true } if( bDoAI ) { local flStandDist = AI_GetDesiredDistance( hPlayer, hTargetEnt ) if( ( ( "bIsBotInSquad" in selfScope ) && selfScope.bIsBotInSquad == true ) || hPlayer.HasBotTag( "ai_bumrush" ) ) flStandDist = 50 if( selfScope.AI_Mode == "attacker" ) { local pos = format( "%d %d %d", hTargetEnt.GetOrigin().x, hTargetEnt.GetOrigin().y, hTargetEnt.GetOrigin().z ) local posEye = format( "%d %d %d", hTargetEnt.EyePosition().x, hTargetEnt.EyePosition().y, hTargetEnt.EyePosition().z ) hPlayer.AcceptInput( "$BotCommand", format( "interrupt_action -pos %s -lookpos %s -killlook -alwayslook -distance %s -duration 1", pos, posEye, flStandDist.tostring() ), hPlayer, null ) } else if( selfScope.AI_Mode == "protector" && ("vecProtect_Point" in selfScope) ) { flStandDist = 50 if( ("flProtect_Point_Time" in selfScope ) && Time() >= selfScope.flProtect_Point_Time ) AI_SetProtectionPoint( hPlayer, hTargetEnt ) local pos = format( "%d %d %d", selfScope.vecProtect_Point.x, selfScope.vecProtect_Point.y, selfScope.vecProtect_Point.z ) local posEye = format( "%d %d %d", hTargetEnt.EyePosition().x, hTargetEnt.EyePosition().y, hTargetEnt.EyePosition().z ) hPlayer.AcceptInput( "$BotCommand", format( "interrupt_action -pos %s -lookpos %s -killlook -alwayslook -distance 50 -duration 1", pos, posEye).tostring(), hPlayer, null ) } else if( selfScope.AI_Mode == "sniper" && ("iOccupiedSlot" in selfScope) ) { flStandDist = 10 local hSniperSpot = FindByName( "info_target", AI_SniperSpotsInfo[selfScope.iOccupiedSlot].sName ) local vecPoint = hSniperSpot.GetOrigin() local pos = format( "%d %d %d", vecPoint.x, vecPoint.y, vecPoint.z ) local posEye = format( "%d %d %d", hTargetEnt.EyePosition().x, hTargetEnt.EyePosition().y, hTargetEnt.EyePosition().z ) hPlayer.AcceptInput( "$BotCommand", format( "interrupt_action -pos %s -lookpos %s -killlook -alwayslook -distance 10 -duration 1", pos, posEye).tostring(), hPlayer, null ) } } } else if(selfScope.bIsBotInSquad == true) { local hLeader = AI_Squads[selfScope.iSquadNumber].hLeader if( hLeader != null ) { local pos = format( "%d %d %d", hLeader.GetOrigin().x, hLeader.GetOrigin().y, hLeader.GetOrigin().z ) local posEye = format( "%d %d %d", hTargetEnt.EyePosition().x, hTargetEnt.EyePosition().y, hTargetEnt.EyePosition().z ) hPlayer.AcceptInput( "$BotCommand", format( "interrupt_action -pos %s -lookpos %s -killlook -alwayslook -distance %s -duration 1", pos, posEye, ( AI_Max_Squad_Distance ).tostring() ), hPlayer, null ) } else AI_JoinNewSquad( hPlayer ) } selfScope.UpdateDelay = Time() + 0.5 } if( ( "bIsBotInSquad" in selfScope ) && selfScope.bIsBotInSquad == true ) DebugDrawText( hPlayer.GetOrigin() + Vector(0, 0, hPlayer.GetBoundingMaxs().z), (selfScope.iSquadNumber).tostring(), true, 0.05 ) TraceLineEx( Trace ) if( !("bHasLoSToTarget" in selfScope ) ) selfScope.bHasLoSToTarget <- false selfScope.bHasLoSToTarget = "enthit" in Trace && Trace.enthit.GetTeam() == TF_TEAM_RED // printl( selfScope.ReactionTime - Time() ) // printl( flDist ) if("enthit" in Trace && Trace.enthit.GetTeam() == TF_TEAM_RED || hPlayer.GetActiveWeapon().GetSlot() == 2) { if( Time() >= selfScope.ReactionTime && flDist <= flDistMax || hPlayer.GetActiveWeapon().GetSlot() == 2 ) { selfScope.ReactionTimeResetDelay = Time() + flReactionTimeResetDelay hPlayer.RemoveBotAttribute(SUPPRESS_FIRE) if( !(hPlayer.GetActiveWeapon().GetSlot() == 2) && hPlayer.GetAbsVelocity().Length() < 5 ) { SetPropBool( hPlayer, "m_bLagCompensation", true ) hPlayer.GetActiveWeapon().PrimaryAttack() SetPropBool( hPlayer, "m_bLagCompensation", false ) } } } else if ( Time() >= selfScope.ReactionTimeResetDelay ) { selfScope.ReactionTime = Time() + flReactionTime hPlayer.AddBotAttribute(SUPPRESS_FIRE) } } } } } AI_Kill_AddThreat = 2 AI_Assist_AddThreat = 1 AI_Revives_AddThreat = 10 AI_Down_AddThreat = -8 AI_Deaths_AddThreat = -20 AI_Max_Squad_Size = 3 //how many attackers and protectors can be in one group AI_Max_Squad_Distance = 100 //how far squad members can be from the leader AI_Wonder_Max_Dist = 750 //Max distance to check for valid hold space away from start hold space AI_Wonder_Max_Height_Dif = 64 //Max height to snap a hold space up, how far to check up for valid space, and vertical offset for LoS check on finding valid hold space AI_Protector_Composition = 4 // Every x number of bots: become a protector AI_Sniper_Composition = 9 // Every x number of bots: become a sniper (overrides protector) AI_TotalBots = 0 AI_Current_Attackers = 0 AI_Current_Protectors = 0 // Protectors = floor( AI_TotalBots / AI_Protector_Composition ) AI_Current_Snipers = 0 // Snipers = floor( AI_TotalBots / AI_Sniper_Composition ) AI_PlayerWeaponThreatTable = { ["tf_weapon_fists"] = { Threat_mult = 0.9, Distance = 0 }, ["tf_weapon_bat"] = { Threat_mult = 1, Distance = 0 }, ["tf_weapon_shovel"] = { Threat_mult = 1, Distance = 0 }, ["tf_weapon_rocketlauncher"] = { Threat_mult = 1, Distance = 1000 }, // TEMP ["tf_weapon_handgun_scout_secondary"] = { Threat_mult = 0.5, Distance = 1000 }, ["tf_weapon_pistol_scout"] = { Threat_mult = 0.5, Distance = 1000 }, ["tf_weapon_pistol"] = { Threat_mult = 0.5, Distance = 1000 }, ["tf_weapon_smg"] = { Threat_mult = 1, Distance = 1500 }, ["tf_weapon_revolver"] = { Threat_mult = 1, Distance = 1500 }, ["tf_weapon_minigun"] = { Threat_mult = 4, Distance = 2000 }, ["tf_weapon_sentry_revenge"] = { Threat_mult = 1.2, Distance = 600 }, ["tf_weapon_shotgun_hwg"] = { Threat_mult = 1.2, Distance = 600 }, ["tf_weapon_shotgun_primary"] = { Threat_mult = 1.2, Distance = 600 }, ["tf_weapon_shotgun_soldier"] = { Threat_mult = 1.2, Distance = 600 }, ["tf_weapon_shotgun_pyro"] = { Threat_mult = 1.2, Distance = 600 }, ["tf_weapon_scattergun"] = { Threat_mult = 1.2, Distance = 150 }, ["tf_weapon_flaregun"] = { Threat_mult = 1.2, Distance = 400 } } AI_BotWeaponThreatTable = { ["tf_weapon_fists"] = { Distance = 0, Distance_Weight = 1 }, ["tf_weapon_bat"] = { Distance = 0, Distance_Weight = 1 }, ["tf_weapon_shovel"] = { Distance = 0, Distance_Weight = 1 }, ["tf_weapon_rocketlauncher"] = { Distance = 1000, Distance_Weight = 1 }, // TEMP ["tf_weapon_handgun_scout_secondary"] = { Distance = 800, Distance_Weight = 1.5 }, ["tf_weapon_pistol_scout"] = { Distance = 800, Distance_Weight = 1.5 }, ["tf_weapon_pistol"] = { Distance = 800, Distance_Weight = 1.5 }, ["tf_weapon_smg"] = { Distance = 1000, Distance_Weight = 2 }, ["tf_weapon_revolver"] = { Distance = 1000, Distance_Weight = 2 }, ["tf_weapon_minigun"] = { Distance = 800, Distance_Weight = 2 }, ["tf_weapon_sentry_revenge"] = { Distance = 350, Distance_Weight = 1.2 }, ["tf_weapon_shotgun_hwg"] = { Distance = 350, Distance_Weight = 1.2 }, ["tf_weapon_shotgun_primary"] = { Distance = 350, Distance_Weight = 1.2 }, ["tf_weapon_shotgun_soldier"] = { Distance = 350, Distance_Weight = 1.2 }, ["tf_weapon_shotgun_pyro"] = { Distance = 350, Distance_Weight = 1.2 }, ["tf_weapon_scattergun"] = { Distance = 500, Distance_Weight = 1.1 }, ["tf_weapon_flaregun"] = { Distance = 200, Distance_Weight = 1.1 } } function AI_HasShotgun( hBot ) { if( !hBot.GetActiveWeapon() || !( "GetName" in hBot.GetActiveWeapon() ) ) return false if( hBot.GetActiveWeapon().GetName().find("tf_weapon_shotgun_") != null || hBot.GetActiveWeapon().GetName().find("tf_weapon_scatter") || hBot.GetActiveWeapon().GetName() == "tf_weapon_sentry_revenge" || hBot.GetActiveWeapon().GetName() == "tf_weapon_flaregun" ) return true else return false } function AI_GetDesiredDistance( hBot, hPlayer ) { if( !hPlayer.GetActiveWeapon() || !hBot.GetActiveWeapon() || !( "GetName" in hPlayer.GetActiveWeapon() ) || !( "GetName" in hBot.GetActiveWeapon() ) ) return 500 local Player_Data = AI_PlayerWeaponThreatTable[hPlayer.GetActiveWeapon().GetName()] local Bot_Data = AI_BotWeaponThreatTable[hBot.GetActiveWeapon().GetName()] local fi_VerticalDist = abs( hPlayer.GetOrigin().z - hBot.GetOrigin().z ) local flDist = abs( ( Player_Data.Distance * hPlayer.GetActiveWeapon().GetAttribute("weapon spread bonus", 1 ) - ( ( ( Player_Data.Distance * hPlayer.GetActiveWeapon().GetAttribute("weapon spread bonus", 1 ) ) - ( Bot_Data.Distance / hBot.GetActiveWeapon().GetAttribute("weapon spread bonus", 1 ) ) ) / Bot_Data.Distance_Weight ) ) ) local scope = hBot.GetScriptScope() if( flDist > 500 && ( "bHasLoSToTarget" in hBot.GetScriptScope() ) && !hBot.GetScriptScope().bHasLoSToTarget ) flDist = 500 flDist -= fi_VerticalDist * 2 if( ( "bIsBotInSquad" in scope ) && scope.bIsBotInSquad == true && scope.bIsBotLeader == false ) flDist = flDist + AI_Max_Squad_Distance + 50 // printl( flDist ) return flDist } function AI_GetPlayerThreat( hPlayer ) { local sNetworkID = GetPropString(hPlayer, "m_szNetworkIDString") local iKills = PlayerStats[sNetworkID].iKills local iAssists = PlayerStats[sNetworkID].iAssists local iRevives = PlayerStats[sNetworkID].iRevives local iDowns = PlayerStats[sNetworkID].iDowns local iDeaths = PlayerStats[sNetworkID].iDeaths local ThreatLevel = iKills * AI_Kill_AddThreat ThreatLevel += iAssists * AI_Assist_AddThreat ThreatLevel += iRevives * AI_Revives_AddThreat ThreatLevel += iDowns * AI_Down_AddThreat ThreatLevel += iDeaths * AI_Deaths_AddThreat for (local i = 0; i <= 2; i++) { local hWeaponTemp = GetPropEntityArray(hPlayer, "m_hMyWeapons", i) if( hWeaponTemp ) ThreatLevel *= ( AI_PlayerWeaponThreatTable[hWeaponTemp.GetName()].Threat_mult * hWeaponTemp.GetAttribute( "event date", 1 ) ) } if( ThreatLevel < 1 ) ThreatLevel = 1 return ThreatLevel } function AI_SetTarget( hBot ) { local ThreatLevels = {} local Total = 0 local cumulativeProbability = 0 for(local i = 1; i <= MAX_CLIENTS; i++) { local hPlayer = PlayerInstanceFromIndex(i) if(hPlayer && !hPlayer.IsFakeClient() && hPlayer.GetTeam() == TF_TEAM_RED) { ThreatLevels[i] <- AI_GetPlayerThreat( hPlayer ) } } foreach( val in ThreatLevels ) Total += val local random = RandomFloat( 0, Total ) foreach( index, val in ThreatLevels ) { cumulativeProbability += val if (cumulativeProbability >= random) { hBot.ValidateScriptScope() hBot.GetScriptScope().hTarget <- PlayerInstanceFromIndex(index) } } } function AI_SetMode( hBot ) { local iNumberOfProtectors = floor( AI_TotalBots / AI_Protector_Composition ) local iNumberOfSnipers = floor( AI_TotalBots / AI_Sniper_Composition ) if( AI_Current_Snipers != iNumberOfSnipers || hBot.HasBotTag( "ai_mode_sniper" ) ) { hBot.GetScriptScope().AI_Mode <- "sniper" AI_Current_Snipers++ } else if( AI_Current_Protectors != iNumberOfProtectors || hBot.HasBotTag( "ai_mode_protector" ) ) { hBot.GetScriptScope().AI_Mode <- "protector" AI_Current_Protectors++ } else if( hBot.HasBotTag( "ai_mode_attacker" ) ) { hBot.GetScriptScope().AI_Mode <- "attacker" AI_Current_Attackers++ } else { hBot.GetScriptScope().AI_Mode <- "attacker" AI_Current_Attackers++ } } function AI_SetSquad( hBot ) { printl( hBot.HasBotTag( "ai_squadbot" ) ) if( !hBot.HasBotTag( "ai_squadbot" ) ) return local scope = hBot.GetScriptScope() // printl( AI_Squads.len() ) foreach( index, val in AI_Squads ) { if( val && val.iBotCount < AI_Max_Squad_Size ) { print( index ) print( " " ) printl( val.iBotCount ) if( val.hLeader != null ) { printl( "Joining Existing Squad" ) AI_Squads[index].iBotCount += 1 scope.bIsBotLeader <- false scope.bIsBotInSquad <- true scope.iSquadNumber <- index scope.hSquadLeader <- val.hLeader return } else if( val.hLeader == null && val.iBotCount <= 0 ) { printl( "Reusing Old Squad" ) AI_Squads[index] <- { iBotCount = 1, hLeader = hBot } scope.bIsBotLeader <- true scope.bIsBotInSquad <- true scope.iSquadNumber <- index scope.hSquadLeader <- hBot return } } } printl( "New Squad" ) AI_Squads[AI_Squads.len()] <- { iBotCount = 1, hLeader = hBot } scope.bIsBotLeader <- true scope.bIsBotInSquad <- true scope.iSquadNumber <- AI_Squads.len()-1 scope.hSquadLeader <- hBot } function AI_JoinNewSquad( hBot ) { local scope = hBot.GetScriptScope() foreach( index, val in AI_Squads ) { if( val && val.iBotCount < AI_Max_Squad_Size && val.hLeader != null ) { AI_Squads[index].iBotCount += 1 AI_Squads[scope.iSquadNumber].iBotCount -= 1 scope.bIsBotLeader <- false scope.bIsBotInSquad <- true scope.iSquadNumber <- index scope.hSquadLeader <- val.hLeader return } } if( scope.bIsBotInSquad == true ) { AI_Squads[scope.iSquadNumber].iBotCount -= 1 scope.bIsBotLeader <- false scope.bIsBotInSquad <- false scope.iSquadNumber <- null scope.hSquadLeader <- null } } function AI_SetProtectionPoint( hBot, hTarget ) { local function SetBasePos( hBot, hTarget ) { local random = RandomFloat(0, 2*PI) local x = cos( random ) local y = sin( random ) local radius = ( AI_GetDesiredDistance( hBot, hTarget ) * 2 ) > 3000 ? 3000 : AI_GetDesiredDistance( hBot, hTarget ) * 2 x *= radius y *= radius local vecPos = Vector( x + hTarget.GetOrigin().x, y + hTarget.GetOrigin().y, hTarget.GetOrigin().z ) // printl( random ) // print( x ) // print( y ) return vecPos } local function HasLoS( vecStart, hTarget ) { local trace = { start = vecStart, end = hTarget.EyePosition(), ignore = hTarget, mask = MASK_SHOT_HULL } TraceLineEx( trace ) return !( "hit" in trace && "enthit" in trace ) } local function MoveOutOfSight( vecStart, hTarget ) { for( local i = 1; i <= 5; i++ ) { local vecDelta = ( Vector( ( AI_Wonder_Max_Dist / i ) * 1, 0, AI_Wonder_Max_Height_Dif ) ) local NewPos = vecStart + vecDelta local traceHull = { start = NewPos + Vector( 0, 0, 72 + AI_Wonder_Max_Height_Dif ), end = NewPos + Vector( 0, 0, 32 + AI_Wonder_Max_Height_Dif ), hullmin = Vector( -16, -16, -0 ), hullmax = Vector( 16, 16, 0 ), ignore = hBot, mask = MASK_SHOT_HULL } //Enough Space local traceDownwards = { start = NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), end = NewPos - Vector( 0, 0, 2500 ), ignore = hBot, mask = MASK_SHOT_HULL } //Snap to floor + void detector TraceHull( traceHull ) TraceLineEx( traceDownwards ) DebugDrawLine( vecStart, NewPos, 0, 0, 255, false, 10) if( "hit" in traceHull && "enthit" in traceHull || "allsolid" in traceHull ) { DebugDrawBox( NewPos + Vector( 0, 0, 72 + AI_Wonder_Max_Height_Dif ), Vector( -16, -16, -96 ), Vector( 16, 16, 0 ), 255, 0, 0, 200, 10 ) continue } if( "hit" in traceDownwards && "enthit" in traceDownwards ) { DebugDrawLine( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), traceDownwards.pos, 0, 0, 255, false, 10 ) NewPos = traceDownwards.pos } if( HasLoS( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), hTarget ) == false ) return NewPos else DebugDrawLine( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), hTarget.EyePosition(), 255, 0, 0, false, 10) } for( local i = 1; i <= 5; i++ ) { local vecDelta = ( Vector( 0, ( AI_Wonder_Max_Dist / i ) * 1, AI_Wonder_Max_Height_Dif ) ) local NewPos = vecStart + vecDelta local traceHull = { start = NewPos + Vector( 0, 0, 72 + AI_Wonder_Max_Height_Dif ), end = NewPos + Vector( 0, 0, 32 + AI_Wonder_Max_Height_Dif ), hullmin = Vector( -16, -16, -0 ), hullmax = Vector( 16, 16, 0 ), ignore = hBot, mask = MASK_SHOT_HULL } //Enough Space local traceDownwards = { start = NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), end = NewPos - Vector( 0, 0, 2500 ), ignore = hBot, mask = MASK_SHOT_HULL } //Snap to floor + void detector TraceHull( traceHull ) TraceLineEx( traceDownwards ) DebugDrawLine( vecStart, NewPos, 0, 0, 255, false, 10) if( "hit" in traceHull && "enthit" in traceHull || "allsolid" in traceHull ) { DebugDrawBox( NewPos + Vector( 0, 0, 72 + AI_Wonder_Max_Height_Dif ), Vector( -16, -16, -96 ), Vector( 16, 16, 0 ), 255, 0, 0, 200, 10 ) continue } if( "hit" in traceDownwards && "enthit" in traceDownwards ) { DebugDrawLine( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), traceDownwards.pos, 0, 0, 255, false, 10 ) NewPos = traceDownwards.pos } if( HasLoS( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), hTarget ) == false ) return NewPos else DebugDrawLine( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), hTarget.EyePosition(), 255, 0, 0, false, 10) } for( local i = 1; i <= 5; i++ ) { local vecDelta = ( Vector( ( AI_Wonder_Max_Dist / i ) * -1, 0, AI_Wonder_Max_Height_Dif ) ) local NewPos = vecStart + vecDelta local traceHull = { start = NewPos + Vector( 0, 0, 72 + AI_Wonder_Max_Height_Dif ), end = NewPos + Vector( 0, 0, 32 + AI_Wonder_Max_Height_Dif ), hullmin = Vector( -16, -16, -0 ), hullmax = Vector( 16, 16, 0 ), ignore = hBot, mask = MASK_SHOT_HULL } //Enough Space local traceDownwards = { start = NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), end = NewPos - Vector( 0, 0, 2500 ), ignore = hBot, mask = MASK_SHOT_HULL } //Snap to floor + void detector TraceHull( traceHull ) TraceLineEx( traceDownwards ) DebugDrawLine( vecStart, NewPos, 0, 0, 255, false, 10) if( "hit" in traceHull && "enthit" in traceHull || "allsolid" in traceHull ) { DebugDrawBox( NewPos + Vector( 0, 0, 72 + AI_Wonder_Max_Height_Dif ), Vector( -16, -16, -96 ), Vector( 16, 16, 0 ), 255, 0, 0, 200, 10 ) continue } if( "hit" in traceDownwards && "enthit" in traceDownwards ) { DebugDrawLine( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), traceDownwards.pos, 0, 0, 255, false, 10 ) NewPos = traceDownwards.pos } if( HasLoS( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), hTarget ) == false ) return NewPos else DebugDrawLine( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), hTarget.EyePosition(), 255, 0, 0, false, 10) } for( local i = 1; i <= 5; i++ ) { local vecDelta = ( Vector( 0, ( AI_Wonder_Max_Dist / i ) * -1, AI_Wonder_Max_Height_Dif ) ) local NewPos = vecStart + vecDelta local traceHull = { start = NewPos + Vector( 0, 0, 72 + AI_Wonder_Max_Height_Dif ), end = NewPos + Vector( 0, 0, 32 + AI_Wonder_Max_Height_Dif ), hullmin = Vector( -16, -16, -0 ), hullmax = Vector( 16, 16, 0 ), ignore = hBot, mask = MASK_SHOT_HULL } //Enough Space local traceDownwards = { start = NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), end = NewPos - Vector( 0, 0, 2500 ), ignore = hBot, mask = MASK_SHOT_HULL } //Snap to floor + void detector TraceHull( traceHull ) TraceLineEx( traceDownwards ) DebugDrawLine( vecStart, NewPos, 0, 0, 255, false, 10) if( "hit" in traceHull && "enthit" in traceHull || "allsolid" in traceHull ) { DebugDrawBox( NewPos + Vector( 0, 0, 72 + AI_Wonder_Max_Height_Dif ), Vector( -16, -16, -96 ), Vector( 16, 16, 0 ), 255, 0, 0, 200, 10 ) continue } if( "hit" in traceDownwards && "enthit" in traceDownwards ) { DebugDrawLine( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), traceDownwards.pos, 0, 0, 255, false, 10 ) NewPos = traceDownwards.pos } if( HasLoS( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), hTarget ) == false ) return NewPos else DebugDrawLine( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), hTarget.EyePosition(), 255, 0, 0, false, 10) } for( local i = 1; i <= 5; i++ ) { local vecDelta = ( Vector( ( AI_Wonder_Max_Dist / i ) * 1, ( AI_Wonder_Max_Dist / i ) * 1, AI_Wonder_Max_Height_Dif ) ) local NewPos = vecStart + vecDelta local traceHull = { start = NewPos + Vector( 0, 0, 72 + AI_Wonder_Max_Height_Dif ), end = NewPos + Vector( 0, 0, 32 + AI_Wonder_Max_Height_Dif ), hullmin = Vector( -16, -16, -0 ), hullmax = Vector( 16, 16, 0 ), ignore = hBot, mask = MASK_SHOT_HULL } //Enough Space local traceDownwards = { start = NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), end = NewPos - Vector( 0, 0, 2500 ), ignore = hBot, mask = MASK_SHOT_HULL } //Snap to floor + void detector TraceHull( traceHull ) TraceLineEx( traceDownwards ) DebugDrawLine( vecStart, NewPos, 0, 0, 255, false, 10) if( "hit" in traceHull && "enthit" in traceHull || "allsolid" in traceHull ) { DebugDrawBox( NewPos + Vector( 0, 0, 72 + AI_Wonder_Max_Height_Dif ), Vector( -16, -16, -96 ), Vector( 16, 16, 0 ), 255, 0, 0, 200, 10 ) continue } if( "hit" in traceDownwards && "enthit" in traceDownwards ) { DebugDrawLine( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), traceDownwards.pos, 0, 0, 255, false, 10 ) NewPos = traceDownwards.pos } if( HasLoS( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), hTarget ) == false ) return NewPos else DebugDrawLine( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), hTarget.EyePosition(), 255, 0, 0, false, 10) } for( local i = 1; i <= 5; i++ ) { local vecDelta = ( Vector( ( AI_Wonder_Max_Dist / i ) * -1, ( AI_Wonder_Max_Dist / i ) * 1, AI_Wonder_Max_Height_Dif ) ) local NewPos = vecStart + vecDelta local traceHull = { start = NewPos + Vector( 0, 0, 72 + AI_Wonder_Max_Height_Dif ), end = NewPos + Vector( 0, 0, 32 + AI_Wonder_Max_Height_Dif ), hullmin = Vector( -16, -16, -0 ), hullmax = Vector( 16, 16, 0 ), ignore = hBot, mask = MASK_SHOT_HULL } //Enough Space local traceDownwards = { start = NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), end = NewPos - Vector( 0, 0, 2500 ), ignore = hBot, mask = MASK_SHOT_HULL } //Snap to floor + void detector TraceHull( traceHull ) TraceLineEx( traceDownwards ) DebugDrawLine( vecStart, NewPos, 0, 0, 255, false, 10) if( "hit" in traceHull && "enthit" in traceHull || "allsolid" in traceHull ) { DebugDrawBox( NewPos + Vector( 0, 0, 72 + AI_Wonder_Max_Height_Dif ), Vector( -16, -16, -96 ), Vector( 16, 16, 0 ), 255, 0, 0, 200, 10 ) continue } if( "hit" in traceDownwards && "enthit" in traceDownwards ) { DebugDrawLine( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), traceDownwards.pos, 0, 0, 255, false, 10 ) NewPos = traceDownwards.pos } if( HasLoS( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), hTarget ) == false ) return NewPos else DebugDrawLine( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), hTarget.EyePosition(), 255, 0, 0, false, 10) } for( local i = 1; i <= 5; i++ ) { local vecDelta = ( Vector( ( AI_Wonder_Max_Dist / i ) * 1, ( AI_Wonder_Max_Dist / i ) * -1, AI_Wonder_Max_Height_Dif ) ) local NewPos = vecStart + vecDelta local traceHull = { start = NewPos + Vector( 0, 0, 72 + AI_Wonder_Max_Height_Dif ), end = NewPos + Vector( 0, 0, 32 + AI_Wonder_Max_Height_Dif ), hullmin = Vector( -16, -16, -0 ), hullmax = Vector( 16, 16, 0 ), ignore = hBot, mask = MASK_SHOT_HULL } //Enough Space local traceDownwards = { start = NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), end = NewPos - Vector( 0, 0, 2500 ), ignore = hBot, mask = MASK_SHOT_HULL } //Snap to floor + void detector TraceHull( traceHull ) TraceLineEx( traceDownwards ) DebugDrawLine( vecStart, NewPos, 0, 0, 255, false, 10) if( "hit" in traceHull && "enthit" in traceHull || "allsolid" in traceHull ) { DebugDrawBox( NewPos + Vector( 0, 0, 72 + AI_Wonder_Max_Height_Dif ), Vector( -16, -16, -96 ), Vector( 16, 16, 0 ), 255, 0, 0, 200, 10 ) continue } if( "hit" in traceDownwards && "enthit" in traceDownwards ) { DebugDrawLine( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), traceDownwards.pos, 0, 0, 255, false, 10 ) NewPos = traceDownwards.pos } if( HasLoS( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), hTarget ) == false ) return NewPos else DebugDrawLine( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), hTarget.EyePosition(), 255, 0, 0, false, 10) } for( local i = 1; i <= 5; i++ ) { local vecDelta = ( Vector( ( AI_Wonder_Max_Dist / i ) * -1, ( AI_Wonder_Max_Dist / i ) * -1, AI_Wonder_Max_Height_Dif ) ) local NewPos = vecStart + vecDelta local traceHull = { start = NewPos + Vector( 0, 0, 72 + AI_Wonder_Max_Height_Dif ), end = NewPos + Vector( 0, 0, 32 + AI_Wonder_Max_Height_Dif ), hullmin = Vector( -16, -16, -0 ), hullmax = Vector( 16, 16, 0 ), ignore = hBot, mask = MASK_SHOT_HULL } //Enough Space local traceDownwards = { start = NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), end = NewPos - Vector( 0, 0, 2500 ), ignore = hBot, mask = MASK_SHOT_HULL } //Snap to floor + void detector TraceHull( traceHull ) TraceLineEx( traceDownwards ) DebugDrawLine( vecStart, NewPos, 0, 0, 255, false, 10) if( "hit" in traceHull && "enthit" in traceHull || "allsolid" in traceHull ) { DebugDrawBox( NewPos + Vector( 0, 0, 72 + AI_Wonder_Max_Height_Dif ), Vector( -16, -16, -96 ), Vector( 16, 16, 0 ), 255, 0, 0, 200, 10 ) continue } if( "hit" in traceDownwards && "enthit" in traceDownwards ) { DebugDrawLine( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), traceDownwards.pos, 0, 0, 255, false, 10 ) NewPos = traceDownwards.pos } if( HasLoS( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), hTarget ) == false ) return NewPos else DebugDrawLine( NewPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), hTarget.EyePosition(), 255, 0, 0, false, 10) } return false } local vecPosBase = SetBasePos( hBot, hTarget ) local vecPos = vecPosBase DebugDrawBox( vecPos, Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 0, 255, 0, 200, 10 ) local traceDownwards = { start = vecPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), end = vecPos - Vector( 0, 0, 2500 ), ignore = hBot, mask = MASK_SHOT_HULL } //Snap to floor + void detector TraceLineEx( traceDownwards ) if( "hit" in traceDownwards && "enthit" in traceDownwards ) { DebugDrawLine( vecPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), traceDownwards.pos, 0, 0, 255, false, 10 ) vecPos = traceDownwards.pos } else { DebugDrawLine( vecPos + Vector( 0, 0, 64 + AI_Wonder_Max_Height_Dif ), vecPos - Vector( 0, 0, 2500 ), 255, 0, 0, false, 10 ) DebugDrawBox( vecPos, Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 255, 0, 0, 200, 10 ) return } if( HasLoS( vecPos + Vector( 0, 0, 72 ), hTarget ) == true ) // don't do this lmao { DebugDrawLine( vecPos + Vector( 0, 0, 72 ), hTarget.EyePosition(), 255, 0, 0, false, 10) local bMoved = MoveOutOfSight( vecPos, hTarget ) if( bMoved ) vecPos = bMoved else return } local traceHull = { start = vecPos + Vector( 0, 0, 72 + AI_Wonder_Max_Height_Dif ), end = vecPos + Vector( 0, 0, 32 + AI_Wonder_Max_Height_Dif ), hullmin = Vector( -16, -16, -0 ), hullmax = Vector( 16, 16, 0 ), ignore = hBot, mask = MASK_SHOT_HULL } //Enough Space TraceHull( traceHull ) if( "hit" in traceHull && "enthit" in traceHull || "allsolid" in traceHull ) { DebugDrawBox( vecPos + Vector( 0, 0, 72 + AI_Wonder_Max_Height_Dif ), Vector( -16, -16, -96 ), Vector( 16, 16, 0 ), 255, 0, 0, 200, 10 ) return } if( NavMesh.GetNavArea( vecPos, 16 ) == null || NavMesh.GetNavArea( vecPos, 16 ).HasAttributeTF( TF_NAV_SPAWN_ROOM_BLUE ) ) return DebugDrawBox( vecPos, Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 255, 255, 0, 200, 10 ) hBot.GetScriptScope().vecProtect_Point <- vecPos hBot.GetScriptScope().flProtect_Point_Time <- Time() + RandomInt( 30, 60 ) } } __CollectGameEventCallbacks(RustEmpire) RustEmpire.hThinkEnt.ValidateScriptScope() RustEmpire.hThinkEnt.GetScriptScope().Think <- function() { RustEmpire.OnTick() return -1 } AddThinkToEnt(RustEmpire.hThinkEnt, "Think")