mirror of
				https://github.com/ineedbots/iw5_bot_warfare.git
				synced 2025-10-30 20:16:57 +00:00 
			
		
		
		
	Compare commits
	
		
			23 Commits
		
	
	
		
			v2.2.0
			...
			7a8041f065
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 7a8041f065 | ||
|  | d92d2c03c4 | ||
|  | 12ca117bdc | ||
|  | 0300692cdd | ||
|  | d2ddce2169 | ||
|  | 7028290495 | ||
|  | 39c6f5054f | ||
|  | b47088538e | ||
|  | 1e0daca087 | ||
|  | dfe2ba0c47 | ||
|  | c8df9ef311 | ||
|  | 0b22a6b8a6 | ||
|  | 60a8f65180 | ||
|  | 5719080f45 | ||
|  | 1bf8314acd | ||
|  | f31a306b0a | ||
|  | c4a222089c | ||
|  | a1651baa5a | ||
|  | 748d261c02 | ||
|  | 06dfea7790 | ||
|  | a9ea7acec3 | ||
|  | 26a5adae13 | ||
|  | a37aadfc2b | 
| @@ -1,10 +1,10 @@ | |||||||
| name: main | name: gsc-tool | ||||||
| 
 | 
 | ||||||
| on: [push] | on: [push] | ||||||
| 
 | 
 | ||||||
| jobs: | jobs: | ||||||
|   main-win: |   main-win: | ||||||
|     name: Test on Windows |     name: Compile on Windows | ||||||
|     runs-on: windows-latest |     runs-on: windows-latest | ||||||
| 
 | 
 | ||||||
|     steps: |     steps: | ||||||
| @@ -18,4 +18,4 @@ jobs: | |||||||
| 
 | 
 | ||||||
|       - name: Run script |       - name: Run script | ||||||
|         run: | |         run: | | ||||||
|           ci/main.bat |           ci/gsc-tool.bat | ||||||
							
								
								
									
										16
									
								
								.github/workflows/pregsc.ymloff
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								.github/workflows/pregsc.ymloff
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | name: pregsc | ||||||
|  |  | ||||||
|  | on: [push] | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   main-win: | ||||||
|  |     name: Run on Windows | ||||||
|  |     runs-on: windows-latest | ||||||
|  |  | ||||||
|  |     steps: | ||||||
|  |       - name: Check out files | ||||||
|  |         uses: actions/checkout@main | ||||||
|  |  | ||||||
|  |       - name: Run script | ||||||
|  |         run: | | ||||||
|  |           ci/pregsc.bat | ||||||
							
								
								
									
										8
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,8 +1,14 @@ | |||||||
| *.zip | *.zip | ||||||
| *.log | *.log | ||||||
| *.stat | *.stat | ||||||
|  | *.exe | ||||||
|  | *.gscbin | ||||||
|  | !ci/ | ||||||
|  | out/ | ||||||
| logs/ | logs/ | ||||||
| demos/ | demos/ | ||||||
| missingasset.csv | missingasset.csv | ||||||
| *.exe |  | ||||||
| compiled/ | compiled/ | ||||||
|  | source/ | ||||||
|  | pregsc/ | ||||||
|  | pregsc.dat | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								README.md
									
									
									
									
									
								
							| @@ -87,7 +87,7 @@ You can find the ModDB release post [here](https://www.moddb.com/mods/bot-warfar | |||||||
| | bots_team_amount                 | When `bots_team` is set to `custom`. The amount of bots to be placed on the axis team. The remainder will be placed on the allies team. | 0 | | | bots_team_amount                 | When `bots_team` is set to `custom`. The amount of bots to be placed on the axis team. The remainder will be placed on the allies team. | 0 | | ||||||
| | bots_team_force                  | If the server should force bots' teams according to the `bots_team` value. When `bots_team` is `autoassign`, unbalanced teams will be balanced. This dvar is ignored when `bots_team` is `custom`. | 0     | | | bots_team_force                  | If the server should force bots' teams according to the `bots_team` value. When `bots_team` is `autoassign`, unbalanced teams will be balanced. This dvar is ignored when `bots_team` is `custom`. | 0     | | ||||||
| | bots_team_mode                   | When `bots_team_force` is `true` and `bots_team` is `autoassign`, players/bots counting method. <ul><li>`0` - counts both players and bots.</li><li>`1` - only counts bots</li></ul> | 0 | | | bots_team_mode                   | When `bots_team_force` is `true` and `bots_team` is `autoassign`, players/bots counting method. <ul><li>`0` - counts both players and bots.</li><li>`1` - only counts bots</li></ul> | 0 | | ||||||
| | bots_skill                       | Bots' difficulty.<ul><li>`0` - Random difficulty for each bot.</li><li>`1` - Easiest difficulty for all bots.</li><li>`2` to `6` - Between easy and hard difficulty for all bots.</li><li>`7` - The hardest difficulty for all bots.</li><li>`8` - custom (look at the `bots_skill_<team>_<difficulty>` dvars</li></ul> | 0 | | | bots_skill                       | Bots' difficulty.<ul><li>`0` - Random difficulty for each bot.</li><li>`1` - Easiest difficulty for all bots.</li><li>`2` to `6` - Between easy and hard difficulty for all bots.</li><li>`7` - The hardest difficulty for all bots.</li><li>`8` - custom (look at the `bots_skill_<team>_<difficulty>` dvars)</li></ul> | 0 | | ||||||
| | bots_skill_axis_hard             | When `bots_skill` is set to `8`, the amount of hard difficulty bots to set on the axis team. | 0            | | | bots_skill_axis_hard             | When `bots_skill` is set to `8`, the amount of hard difficulty bots to set on the axis team. | 0            | | ||||||
| | bots_skill_axis_med              | When `bots_skill` is set to `8`, the amount of medium difficulty bots to set on the axis team. The remaining bots on the team will be set to easy difficulty. | 0 | | | bots_skill_axis_med              | When `bots_skill` is set to `8`, the amount of medium difficulty bots to set on the axis team. The remaining bots on the team will be set to easy difficulty. | 0 | | ||||||
| | bots_skill_allies_hard           | When `bots_skill` is set to `8`, the amount of hard difficulty bots to set on the allies team. | 0          | | | bots_skill_allies_hard           | When `bots_skill` is set to `8`, the amount of hard difficulty bots to set on the allies team. | 0          | | ||||||
| @@ -112,10 +112,15 @@ You can find the ModDB release post [here](https://www.moddb.com/mods/bot-warfar | |||||||
| | bots_play_aim                    | If the bots can aim.                                                                           | 1          | | | bots_play_aim                    | If the bots can aim.                                                                           | 1          | | ||||||
|  |  | ||||||
| ## Changelog | ## Changelog | ||||||
|  | - v2.3.0 | ||||||
|  |   - Fixed bots aiming in ac130/chopper being broken at times | ||||||
|  |   - Bots properly use pred missiles | ||||||
|  |   - Smoothed bot aim at range | ||||||
|  |   - Fixed bots_manage_fill_spec players being counted with bots_manage_fill_mode 1 (bot only) | ||||||
|  |  | ||||||
| - v2.2.0 | - v2.2.0 | ||||||
|   - Bots can now melee lunge |   - Bots can now melee lunge | ||||||
|   - Fixed some chat related script runtime errors |   - Fixed some chat related script runtime errors | ||||||
|   - Waypoints only load from csv now |  | ||||||
|   - Fix bots possibly being stuck in sab |   - Fix bots possibly being stuck in sab | ||||||
|   - Major cleanup |   - Major cleanup | ||||||
|  |  | ||||||
| @@ -131,6 +136,7 @@ You can find the ModDB release post [here](https://www.moddb.com/mods/bot-warfar | |||||||
| - apdonato - http://rsebots.blogspot.ca/ | - apdonato - http://rsebots.blogspot.ca/ | ||||||
| - Ability | - Ability | ||||||
| - Salvation | - Salvation | ||||||
|  | - Xensik - https://github.com/xensik/gsc-tool | ||||||
|  |  | ||||||
| ### Waypoint Creators | ### Waypoint Creators | ||||||
| - FragsAreUs - https://github.com/FragsAreUs | - FragsAreUs - https://github.com/FragsAreUs | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								ci/gsc-tool.bat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								ci/gsc-tool.bat
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | @echo off | ||||||
|  |  | ||||||
|  | xcopy /y .\ci\*.gscbin .\ | ||||||
|  | rm .\scripts\mp\bots_adapter_piw5.gsc | ||||||
|  |  | ||||||
|  | gsc-tool.exe -m comp -g iw5 -s pc .\ | ||||||
| @@ -1,6 +0,0 @@ | |||||||
| @echo off |  | ||||||
|  |  | ||||||
| xcopy /y ci . |  | ||||||
| rm scripts\mp\bots_adapter_piw5.gsc |  | ||||||
|  |  | ||||||
| gsc-tool.exe -m comp -g iw5 -s pc . |  | ||||||
							
								
								
									
										10
									
								
								ci/pregsc.bat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								ci/pregsc.bat
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | @echo off | ||||||
|  |  | ||||||
|  | if not exist ".\source\" mkdir .\source\ | ||||||
|  | if not exist ".\source\scripts\" mkdir .\source\scripts\ | ||||||
|  | if not exist ".\source\maps\" mkdir .\source\maps\ | ||||||
|  |  | ||||||
|  | xcopy /y /s /e .\scripts\ .\source\scripts\ | ||||||
|  | xcopy /y /s /e .\maps\ .\source\maps\ | ||||||
|  |  | ||||||
|  | preGSC.exe -noforeach -nopause -infold .\source\ -outfold .\pregsc\ | ||||||
| @@ -15,7 +15,7 @@ | |||||||
| */ | */ | ||||||
| init() | init() | ||||||
| { | { | ||||||
| 	level.bw_version = "2.2.0"; | 	level.bw_version = "2.3.0"; | ||||||
| 	 | 	 | ||||||
| 	if ( getdvar( "bots_main" ) == "" ) | 	if ( getdvar( "bots_main" ) == "" ) | ||||||
| 	{ | 	{ | ||||||
| @@ -218,8 +218,11 @@ init() | |||||||
| 	if ( !isdefined( game[ "botWarfare" ] ) ) | 	if ( !isdefined( game[ "botWarfare" ] ) ) | ||||||
| 	{ | 	{ | ||||||
| 		game[ "botWarfare" ] = true; | 		game[ "botWarfare" ] = true; | ||||||
|  | 		game[ "botWarfareInitTime" ] = gettime(); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
|  | 	level.bot_inittime = gettime(); | ||||||
|  | 	 | ||||||
| 	level.defuseobject = undefined; | 	level.defuseobject = undefined; | ||||||
| 	level.bots_smokelist = List(); | 	level.bots_smokelist = List(); | ||||||
| 	level.bots_fraglist = List(); | 	level.bots_fraglist = List(); | ||||||
| @@ -277,6 +280,7 @@ init() | |||||||
| 	level.bots_fullautoguns[ "remote" ] = true; | 	level.bots_fullautoguns[ "remote" ] = true; | ||||||
| 	 | 	 | ||||||
| 	level thread fixGamemodes(); | 	level thread fixGamemodes(); | ||||||
|  | 	level thread fixPredMissile(); | ||||||
| 	 | 	 | ||||||
| 	level thread onPlayerConnect(); | 	level thread onPlayerConnect(); | ||||||
| 	level thread addNotifyOnAirdrops(); | 	level thread addNotifyOnAirdrops(); | ||||||
| @@ -285,6 +289,26 @@ init() | |||||||
| 	level thread auditModels(); | 	level thread auditModels(); | ||||||
| 	 | 	 | ||||||
| 	level thread handleBots(); | 	level thread handleBots(); | ||||||
|  | 	level thread onPlayerChat(); | ||||||
|  |  | ||||||
|  | 	array_thread( getentarray( "misc_turret", "classname" ), ::turret_monitoruse_watcher ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | 	Change func pointer to ours, so that we can link the player ref to the rocket | ||||||
|  | */ | ||||||
|  | fixPredMissile() | ||||||
|  | { | ||||||
|  | 	for ( i = 0; i < 19; i++ ) | ||||||
|  | 	{ | ||||||
|  | 		if ( isdefined( level.killstreakfuncs ) && isdefined( level.killstreakfuncs[ "predator_missile" ] ) ) | ||||||
|  | 		{ | ||||||
|  | 			level.killstreakfuncs[ "predator_missile" ] = ::tryUsePredatorMissileFix; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		wait 0.05; | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
| @@ -847,6 +871,23 @@ onPlayerConnect() | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | 	When a bot disconnects. | ||||||
|  | */ | ||||||
|  | onDisconnectPlayer() | ||||||
|  | { | ||||||
|  | 	name = self.name; | ||||||
|  | 	 | ||||||
|  | 	self waittill( "disconnect" ); | ||||||
|  | 	waittillframeend; | ||||||
|  | 	 | ||||||
|  | 	for ( i = 0; i < level.bots.size; i++ ) | ||||||
|  | 	{ | ||||||
|  | 		bot = level.bots[ i ]; | ||||||
|  | 		bot BotNotifyBotEvent( "connection", "disconnected", self, name ); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
| 	When a bot disconnects. | 	When a bot disconnects. | ||||||
| */ | */ | ||||||
| @@ -864,6 +905,14 @@ connected() | |||||||
| { | { | ||||||
| 	self endon( "disconnect" ); | 	self endon( "disconnect" ); | ||||||
| 	 | 	 | ||||||
|  | 	for ( i = 0; i < level.bots.size; i++ ) | ||||||
|  | 	{ | ||||||
|  | 		bot = level.bots[ i ]; | ||||||
|  | 		bot BotNotifyBotEvent( "connection", "connected", self, self.name ); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	self thread onDisconnectPlayer(); | ||||||
|  | 	 | ||||||
| 	if ( !isdefined( self.pers[ "bot_host" ] ) ) | 	if ( !isdefined( self.pers[ "bot_host" ] ) ) | ||||||
| 	{ | 	{ | ||||||
| 		self thread doHostCheck(); | 		self thread doHostCheck(); | ||||||
| @@ -1390,11 +1439,11 @@ addBots_loop() | |||||||
| 	if ( fillMode == 0 || fillMode == 2 ) | 	if ( fillMode == 0 || fillMode == 2 ) | ||||||
| 	{ | 	{ | ||||||
| 		amount += players; | 		amount += players; | ||||||
| 	} | 		 | ||||||
| 	 | 		if ( getdvarint( "bots_manage_fill_spec" ) ) | ||||||
| 	if ( getdvarint( "bots_manage_fill_spec" ) ) | 		{ | ||||||
| 	{ | 			amount += spec; | ||||||
| 		amount += spec; | 		} | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	if ( amount < fillAmount ) | 	if ( amount < fillAmount ) | ||||||
| @@ -1552,3 +1601,57 @@ doFiringThread() | |||||||
| 	wait 1; | 	wait 1; | ||||||
| 	self.bots_firing = false; | 	self.bots_firing = false; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | 	When a player chats | ||||||
|  | */ | ||||||
|  | onPlayerChat() | ||||||
|  | { | ||||||
|  | 	for ( ;; ) | ||||||
|  | 	{ | ||||||
|  | 		level waittill( "say", message, player, is_hidden ); | ||||||
|  | 		 | ||||||
|  | 		for ( i = 0; i < level.bots.size; i++ ) | ||||||
|  | 		{ | ||||||
|  | 			bot = level.bots[ i ]; | ||||||
|  | 			 | ||||||
|  | 			bot BotNotifyBotEvent( "chat", "chat", message, player, is_hidden ); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | 	Monitors turret usage | ||||||
|  | */ | ||||||
|  | turret_monitoruse_watcher() | ||||||
|  | { | ||||||
|  | 	self endon( "death" ); | ||||||
|  |  | ||||||
|  | 	for ( ;; ) | ||||||
|  | 	{ | ||||||
|  | 		self waittill ( "trigger", player ); | ||||||
|  |  | ||||||
|  | 		self monitor_player_turret( player ); | ||||||
|  |  | ||||||
|  | 		self.owner = undefined; | ||||||
|  |  | ||||||
|  | 		if ( isdefined( player ) ) | ||||||
|  | 		{ | ||||||
|  | 			player.turret = undefined; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | 	While player uses turret | ||||||
|  | */ | ||||||
|  | monitor_player_turret( player ) | ||||||
|  | { | ||||||
|  | 	player endon( "death" ); | ||||||
|  | 	player endon( "disconnect" ); | ||||||
|  |  | ||||||
|  | 	player.turret = self; | ||||||
|  | 	self.owner = player; | ||||||
|  |  | ||||||
|  | 	self waittill( "turret_deactivate" ); | ||||||
|  | } | ||||||
|   | |||||||
| @@ -328,10 +328,43 @@ start_chat_watch() | |||||||
| 			case "box_cap": | 			case "box_cap": | ||||||
| 				self thread bot_chat_box_cap_watch( a, b, c, d, e, f, g ); | 				self thread bot_chat_box_cap_watch( a, b, c, d, e, f, g ); | ||||||
| 				break; | 				break; | ||||||
|  | 				 | ||||||
|  | 			case "connection": | ||||||
|  | 				self thread bot_chat_connection_player_watch( a, b, c, d, e, f, g ); | ||||||
|  | 				break; | ||||||
|  | 				 | ||||||
|  | 			case "chat": | ||||||
|  | 				self thread bot_chat_chat_player_watch( a, b, c, d, e, f, g ); | ||||||
|  | 				break; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | 	When another player chats | ||||||
|  | */ | ||||||
|  | bot_chat_chat_player_watch( chatstr, message, player, is_hidden, e, f, g ) | ||||||
|  | { | ||||||
|  | 	self endon( "disconnect" ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | 	When a player connected | ||||||
|  | */ | ||||||
|  | bot_chat_connection_player_watch( conn, player, playername, d, e, f, g ) | ||||||
|  | { | ||||||
|  | 	self endon( "disconnect" ); | ||||||
|  | 	 | ||||||
|  | 	switch ( conn ) | ||||||
|  | 	{ | ||||||
|  | 		case "connected": | ||||||
|  | 			break; | ||||||
|  | 			 | ||||||
|  | 		case "disconnected": | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
| 	start_startgame_watch | 	start_startgame_watch | ||||||
| */ | */ | ||||||
|   | |||||||
| @@ -375,11 +375,208 @@ watchUsingRemote() | |||||||
| 			self watchUsingTurret(); | 			self watchUsingTurret(); | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
|  | 		if ( isdefined( self.rocket ) ) | ||||||
|  | 		{ | ||||||
|  | 			self watchUsingPred(); | ||||||
|  | 			self BotBuiltinBotAction( "-remote" ); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
| 		self.bot.targets = []; | 		self.bot.targets = []; | ||||||
| 		self notify( "kill_goal" ); | 		self notify( "kill_goal" ); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | 	Returns the angle delta | ||||||
|  | */ | ||||||
|  | getRemoteAngleSpeed( len ) | ||||||
|  | { | ||||||
|  | 	furthest = 10.0; | ||||||
|  | 	max_speed = 127; | ||||||
|  | 	 | ||||||
|  | 	switch ( self.pers[ "bots" ][ "skill" ][ "base" ] ) | ||||||
|  | 	{ | ||||||
|  | 		case 1: | ||||||
|  | 			furthest = 5.0; | ||||||
|  | 			max_speed = 20; | ||||||
|  | 			break; | ||||||
|  | 			 | ||||||
|  | 		case 2: | ||||||
|  | 			furthest = 6.0; | ||||||
|  | 			max_speed = 35; | ||||||
|  | 			break; | ||||||
|  | 			 | ||||||
|  | 		case 3: | ||||||
|  | 			furthest = 7.0; | ||||||
|  | 			max_speed = 55; | ||||||
|  | 			break; | ||||||
|  | 			 | ||||||
|  | 		case 4: | ||||||
|  | 			furthest = 8.0; | ||||||
|  | 			max_speed = 65; | ||||||
|  | 			break; | ||||||
|  | 			 | ||||||
|  | 		case 5: | ||||||
|  | 			furthest = 9.0; | ||||||
|  | 			max_speed = 75; | ||||||
|  | 			break; | ||||||
|  | 			 | ||||||
|  | 		case 6: | ||||||
|  | 			furthest = 10.0; | ||||||
|  | 			max_speed = 100; | ||||||
|  | 			break; | ||||||
|  | 			 | ||||||
|  | 		case 7: | ||||||
|  | 			furthest = 15.0; | ||||||
|  | 			max_speed = 127; | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	if ( len >= furthest ) | ||||||
|  | 	{ | ||||||
|  | 		return max_speed; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	if ( len <= 0.0 ) | ||||||
|  | 	{ | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	return Round( ( len / furthest ) * max_speed ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | 	time to boost the rocket | ||||||
|  | */ | ||||||
|  | getRemoteBoostTime() | ||||||
|  | { | ||||||
|  | 	switch ( self.pers[ "bots" ][ "skill" ][ "base" ] ) | ||||||
|  | 	{ | ||||||
|  | 		case 1: | ||||||
|  | 			return 99999; | ||||||
|  | 			 | ||||||
|  | 		case 2: | ||||||
|  | 			return 15000; | ||||||
|  | 			 | ||||||
|  | 		case 3: | ||||||
|  | 			return 10000; | ||||||
|  | 			 | ||||||
|  | 		case 4: | ||||||
|  | 			return 5000; | ||||||
|  | 			 | ||||||
|  | 		case 5: | ||||||
|  | 			return 2500; | ||||||
|  | 			 | ||||||
|  | 		case 6: | ||||||
|  | 			return 1000; | ||||||
|  | 			 | ||||||
|  | 		case 7: | ||||||
|  | 			return 500; | ||||||
|  | 			 | ||||||
|  | 		default: | ||||||
|  | 			return 500; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | 	While in rocket | ||||||
|  | */ | ||||||
|  | watchUsingPred() | ||||||
|  | { | ||||||
|  | 	self.rocket endon( "death" ); | ||||||
|  | 	 | ||||||
|  | 	self BotBuiltinBotRemoteAngles( 0, 0 ); | ||||||
|  | 	self BotBuiltinBotAction( "+remote" ); | ||||||
|  | 	 | ||||||
|  | 	pressedFire = false; | ||||||
|  | 	sTime = gettime(); | ||||||
|  | 	 | ||||||
|  | 	while ( isdefined( self.rocket ) ) | ||||||
|  | 	{ | ||||||
|  | 		self.bot.targets = []; // dont want to fire from aim thread | ||||||
|  | 		// because geteye doesnt return the eye of the missile | ||||||
|  | 		 | ||||||
|  | 		target = undefined; | ||||||
|  | 		myeye = self.rocket.origin; | ||||||
|  | 		myangles = self.rocket.angles; | ||||||
|  | 		bestfov = 0.0; | ||||||
|  | 		 | ||||||
|  | 		for ( i = level.players.size - 1; i >= 0; i-- ) | ||||||
|  | 		{ | ||||||
|  | 			player = level.players[ i ]; | ||||||
|  | 			 | ||||||
|  | 			if ( !isdefined( player ) || !isdefined( player.team ) ) | ||||||
|  | 			{ | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			if ( player == self || ( level.teambased && player.team == self.team ) ) | ||||||
|  | 			{ | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			if ( player.sessionstate != "playing" || !isreallyalive( player ) ) | ||||||
|  | 			{ | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			if ( player _hasperk( "specialty_blindeye" ) ) | ||||||
|  | 			{ | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			if ( !bullettracepassed( myeye, player.origin + ( 0, 0, 25 ), false, self.rocket ) ) | ||||||
|  | 			{ | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			thisfov = getConeDot( player.origin, myeye, myangles ); | ||||||
|  | 			 | ||||||
|  | 			if ( thisfov < 0.75 ) | ||||||
|  | 			{ | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			if ( isdefined( target ) && thisfov < bestfov ) | ||||||
|  | 			{ | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			target = player; | ||||||
|  | 			bestfov = thisfov; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		if ( isdefined( target ) ) | ||||||
|  | 		{ | ||||||
|  | 			if ( !pressedFire && gettime() - sTime > self getRemoteBoostTime() ) | ||||||
|  | 			{ | ||||||
|  | 				pressedFire = true; | ||||||
|  | 				self thread pressFire(); | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			if ( bestfov < 0.999995 && distancesquared( target.origin, myeye ) > 256 * 256 ) | ||||||
|  | 			{ | ||||||
|  | 				angles = vectortoangles( ( target.origin - myeye ) - anglestoforward( myangles ) ); | ||||||
|  | 				angles -= myangles; | ||||||
|  | 				angles = ( angleclamp180( angles[ 0 ] ), angleclamp180( angles[ 1 ] ), 0 ); | ||||||
|  | 				angles = vectornormalize( angles ) * self getRemoteAngleSpeed( length( angles ) ); | ||||||
|  | 				 | ||||||
|  | 				self BotBuiltinBotRemoteAngles( int( angles[ 0 ] ), int( angles[ 1 ] ) ); | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				self BotBuiltinBotRemoteAngles( 0, 0 ); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			self BotBuiltinBotRemoteAngles( 0, 0 ); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		wait 0.05; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
| 	watchUsingTurret | 	watchUsingTurret | ||||||
| */ | */ | ||||||
| @@ -646,6 +843,13 @@ watchPickupGun() | |||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
|  | 		// todo have bots use turrets instead of just kicking them off of it | ||||||
|  | 		if ( isdefined( self.turret ) ) | ||||||
|  | 		{ | ||||||
|  | 			self thread use( 0.5 ); | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
| 		weap = self getcurrentweapon(); | 		weap = self getcurrentweapon(); | ||||||
| 		 | 		 | ||||||
| 		if ( weap != "none" && self getammocount( weap ) ) | 		if ( weap != "none" && self getammocount( weap ) ) | ||||||
| @@ -1177,24 +1381,27 @@ updateBones() | |||||||
| 	self endon( "disconnect" ); | 	self endon( "disconnect" ); | ||||||
| 	self endon( "spawned_player" ); | 	self endon( "spawned_player" ); | ||||||
| 	 | 	 | ||||||
| 	bones = strtok( self.pers[ "bots" ][ "skill" ][ "bones" ], "," ); |  | ||||||
| 	waittime = self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ]; |  | ||||||
| 	 |  | ||||||
| 	for ( ;; ) | 	for ( ;; ) | ||||||
| 	{ | 	{ | ||||||
| 		self waittill_any_timeout( waittime, "new_enemy" ); | 		oldbones = self.pers[ "bots" ][ "skill" ][ "bones" ]; | ||||||
|  | 		bones = strtok( oldbones, "," ); | ||||||
| 		 | 		 | ||||||
| 		if ( !isalive( self ) ) | 		while ( oldbones == self.pers[ "bots" ][ "skill" ][ "bones" ] ) | ||||||
| 		{ | 		{ | ||||||
| 			return; | 			self waittill_any_timeout( self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ], "new_enemy" ); | ||||||
|  | 			 | ||||||
|  | 			if ( !isalive( self ) ) | ||||||
|  | 			{ | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			if ( !isdefined( self.bot.target ) ) | ||||||
|  | 			{ | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			self.bot.target.bone = random( bones ); | ||||||
| 		} | 		} | ||||||
| 		 |  | ||||||
| 		if ( !isdefined( self.bot.target ) ) |  | ||||||
| 		{ |  | ||||||
| 			continue; |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		self.bot.target.bone = random( bones ); |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1303,6 +1510,23 @@ targetObjUpdateNoTrace( obj ) | |||||||
| 	obj.didlook = false; | 	obj.didlook = false; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | 	Returns true if myEye can see the bone of self | ||||||
|  | */ | ||||||
|  | checkTraceForBone( myEye, bone ) | ||||||
|  | { | ||||||
|  | 	boneLoc = self gettagorigin( bone ); | ||||||
|  | 	 | ||||||
|  | 	if ( !isdefined( boneLoc ) ) | ||||||
|  | 	{ | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	trace = bullettrace( myEye, boneLoc, false, undefined ); | ||||||
|  | 	 | ||||||
|  | 	return ( sighttracepassed( myEye, boneLoc, false, undefined ) && ( trace[ "fraction" ] >= 1.0 || trace[ "surfacetype" ] == "glass" ) ); | ||||||
|  | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
| 	The main target thread, will update the bot's main target. Will auto target enemy players and handle script targets. | 	The main target thread, will update the bot's main target. Will auto target enemy players and handle script targets. | ||||||
| */ | */ | ||||||
| @@ -1447,21 +1671,9 @@ target_loop() | |||||||
| 			} | 			} | ||||||
| 			else | 			else | ||||||
| 			{ | 			{ | ||||||
| 				targetHead = player gettagorigin( "j_head" ); | 				canTargetPlayer = ( ( player checkTraceForBone( myEye, "j_head" ) || | ||||||
| 				targetAnkleLeft = player gettagorigin( "j_ankle_le" ); | 							player checkTraceForBone( myEye, "j_ankle_le" ) || | ||||||
| 				targetAnkleRight = player gettagorigin( "j_ankle_ri" ); | 							player checkTraceForBone( myEye, "j_ankle_ri" ) ) | ||||||
| 				 |  | ||||||
| 				traceHead = bullettrace( myEye, targetHead, false, undefined ); |  | ||||||
| 				traceAnkleLeft = bullettrace( myEye, targetAnkleLeft, false, undefined ); |  | ||||||
| 				traceAnkleRight = bullettrace( myEye, targetAnkleRight, false, undefined ); |  | ||||||
| 				 |  | ||||||
| 				canTargetPlayer = ( ( sighttracepassed( myEye, targetHead, false, undefined ) || |  | ||||||
| 							sighttracepassed( myEye, targetAnkleLeft, false, undefined ) || |  | ||||||
| 							sighttracepassed( myEye, targetAnkleRight, false, undefined ) ) |  | ||||||
| 							 |  | ||||||
| 						&& ( ( traceHead[ "fraction" ] >= 1.0 || traceHead[ "surfacetype" ] == "glass" ) || |  | ||||||
| 							( traceAnkleLeft[ "fraction" ] >= 1.0 || traceAnkleLeft[ "surfacetype" ] == "glass" ) || |  | ||||||
| 							( traceAnkleRight[ "fraction" ] >= 1.0 || traceAnkleRight[ "surfacetype" ] == "glass" ) ) |  | ||||||
| 							 | 							 | ||||||
| 						&& ( ignoreSmoke || | 						&& ( ignoreSmoke || | ||||||
| 							SmokeTrace( myEye, player.origin, level.smokeradius ) || | 							SmokeTrace( myEye, player.origin, level.smokeradius ) || | ||||||
| @@ -1937,7 +2149,7 @@ aim_loop() | |||||||
| 					{ | 					{ | ||||||
| 						self thread bot_lookat( target gettagorigin( "j_spine4" ), 0.05 ); | 						self thread bot_lookat( target gettagorigin( "j_spine4" ), 0.05 ); | ||||||
| 					} | 					} | ||||||
| 					else if ( !nadeAimOffset && conedot > 0.999 && lengthsquared( aimoffset ) < 0.05 ) | 					else if ( !nadeAimOffset && conedot > 0.999995 && lengthsquared( aimoffset ) < 0.05 ) | ||||||
| 					{ | 					{ | ||||||
| 						self thread bot_lookat( aimpos, 0.05 ); | 						self thread bot_lookat( aimpos, 0.05 ); | ||||||
| 					} | 					} | ||||||
| @@ -1955,7 +2167,7 @@ aim_loop() | |||||||
| 					 | 					 | ||||||
| 					conedot = getConeDot( aimpos, eyePos, angles ); | 					conedot = getConeDot( aimpos, eyePos, angles ); | ||||||
| 					 | 					 | ||||||
| 					if ( !nadeAimOffset && conedot > 0.999 && lengthsquared( aimoffset ) < 0.05 ) | 					if ( !nadeAimOffset && conedot > 0.999995 && lengthsquared( aimoffset ) < 0.05 ) | ||||||
| 					{ | 					{ | ||||||
| 						self thread bot_lookat( aimpos, 0.05 ); | 						self thread bot_lookat( aimpos, 0.05 ); | ||||||
| 					} | 					} | ||||||
| @@ -2137,6 +2349,7 @@ aim() | |||||||
| 	for ( ;; ) | 	for ( ;; ) | ||||||
| 	{ | 	{ | ||||||
| 		wait 0.05; | 		wait 0.05; | ||||||
|  | 		waittillframeend; | ||||||
| 		 | 		 | ||||||
| 		if ( !isalive( self ) ) | 		if ( !isalive( self ) ) | ||||||
| 		{ | 		{ | ||||||
| @@ -2372,9 +2585,9 @@ walk_loop() | |||||||
| 	 | 	 | ||||||
| 	dist = 16; | 	dist = 16; | ||||||
| 	 | 	 | ||||||
| 	if ( level.waypointcount ) | 	if ( level.waypoints.size ) | ||||||
| 	{ | 	{ | ||||||
| 		goal = level.waypoints[ randomint( level.waypointcount ) ].origin; | 		goal = level.waypoints[ randomint( level.waypoints.size ) ].origin; | ||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| @@ -3350,7 +3563,7 @@ bot_lookat( pos, time, vel, doAimPredict ) | |||||||
| 	for ( i = 0; i < steps; i++ ) | 	for ( i = 0; i < steps; i++ ) | ||||||
| 	{ | 	{ | ||||||
| 		myAngle = ( angleclamp180( myAngle[ 0 ] + X ), angleclamp180( myAngle[ 1 ] + Y ), 0 ); | 		myAngle = ( angleclamp180( myAngle[ 0 ] + X ), angleclamp180( myAngle[ 1 ] + Y ), 0 ); | ||||||
| 		self setplayerangles( myAngle ); | 		self BotBuiltinBotAngles( myAngle ); | ||||||
| 		wait 0.05; | 		wait 0.05; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -5628,27 +5628,6 @@ getKillstreakTargetLocation() | |||||||
| 	return location; | 	return location; | ||||||
| } | } | ||||||
|  |  | ||||||
| /* |  | ||||||
| 	Clears remote usage when bot dies |  | ||||||
| */ |  | ||||||
| clear_remote_on_death( isac130 ) |  | ||||||
| { |  | ||||||
| 	self endon( "bot_clear_remote_on_death" ); |  | ||||||
| 	level endon( "game_ended" ); |  | ||||||
| 	 |  | ||||||
| 	self waittill_either( "death", "disconnect" ); |  | ||||||
| 	 |  | ||||||
| 	if ( isdefined( isac130 ) && isac130 ) |  | ||||||
| 	{ |  | ||||||
| 		level.ac130inuse = false; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	if ( isdefined( self ) ) |  | ||||||
| 	{ |  | ||||||
| 		self clearusingremote(); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* | /* | ||||||
| 	Bots think to use killstreaks | 	Bots think to use killstreaks | ||||||
| */ | */ | ||||||
| @@ -5706,6 +5685,11 @@ bot_killstreak_think_loop( data ) | |||||||
| 		self thread BotPressAttack( 0.05 ); | 		self thread BotPressAttack( 0.05 ); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
|  | 	if ( iskillstreakweapon( curWeap ) ) | ||||||
|  | 	{ | ||||||
|  | 		self thread changeToWeapon( self getlastweapon() ); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
| 	 | 	 | ||||||
| 	useableStreaks = []; | 	useableStreaks = []; | ||||||
| 	 | 	 | ||||||
| @@ -5898,49 +5882,11 @@ bot_killstreak_think_loop( data ) | |||||||
| 			self BotNotifyBotEvent( "killstreak", "call", streakName, location ); | 			self BotNotifyBotEvent( "killstreak", "call", streakName, location ); | ||||||
| 			 | 			 | ||||||
| 			self BotRandomStance(); | 			self BotRandomStance(); | ||||||
| 			self setusingremote( "remotemissile" ); |  | ||||||
| 			self thread clear_remote_on_death(); |  | ||||||
| 			self BotStopMoving( true ); | 			self BotStopMoving( true ); | ||||||
|  | 			self changeToWeapon( ksWeap ); | ||||||
| 			 | 			 | ||||||
| 			if ( !self changeToWeapon( ksWeap ) ) | 			wait 3; | ||||||
| 			{ |  | ||||||
| 				self clearusingremote(); |  | ||||||
| 				self notify( "bot_clear_remote_on_death" ); |  | ||||||
| 				self BotStopMoving( false ); |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			wait 0.05; |  | ||||||
| 			self thread changeToWeapon( ksWeap ); // prevent script from changing back |  | ||||||
| 			 |  | ||||||
| 			wait 1; |  | ||||||
| 			self notify( "bot_clear_remote_on_death" ); |  | ||||||
| 			self BotStopMoving( false ); | 			self BotStopMoving( false ); | ||||||
| 			 |  | ||||||
| 			if ( self isemped() || self isnuked() ) |  | ||||||
| 			{ |  | ||||||
| 				self clearusingremote(); |  | ||||||
| 				self thread changeToWeapon( curWeap ); |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			self BotFreezeControls( true ); |  | ||||||
| 			 |  | ||||||
| 			self thread maps\mp\killstreaks\_killstreaks::updatekillstreaks(); |  | ||||||
| 			self maps\mp\killstreaks\_killstreaks::usedkillstreak( streakName, true ); |  | ||||||
| 			 |  | ||||||
| 			rocket = magicbullet( "remotemissile_projectile_mp", self.origin + ( 0.0, 0.0, 7000.0 - ( self.pers[ "bots" ][ "skill" ][ "base" ] * 400 ) ), location, self ); |  | ||||||
| 			rocket.lifeid = lifeId; |  | ||||||
| 			rocket.type = "remote"; |  | ||||||
| 			 |  | ||||||
| 			rocket thread maps\mp\gametypes\_weapons::addmissiletosighttraces( self.pers[ "team" ] ); |  | ||||||
| 			rocket thread maps\mp\killstreaks\_remotemissile::handledamage(); |  | ||||||
| 			thread maps\mp\killstreaks\_remotemissile::missileeyes( self, rocket ); |  | ||||||
| 			 |  | ||||||
| 			self waittill( "stopped_using_remote" ); |  | ||||||
| 			 |  | ||||||
| 			wait 1; |  | ||||||
| 			self BotFreezeControls( false ); |  | ||||||
| 		} | 		} | ||||||
| 		else if ( streakName == "ac130" || streakName == "remote_mortar" || streakName == "osprey_gunner" ) | 		else if ( streakName == "ac130" || streakName == "remote_mortar" || streakName == "osprey_gunner" ) | ||||||
| 		{ | 		{ | ||||||
|   | |||||||
| @@ -129,6 +129,28 @@ BotBuiltinBotMeleeParams( entNum, dist ) | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | 	Sets remote angles | ||||||
|  | */ | ||||||
|  | BotBuiltinBotRemoteAngles( pitch, yaw ) | ||||||
|  | { | ||||||
|  | 	if ( isdefined( level.bot_builtins ) && isdefined( level.bot_builtins[ "botremoteangles" ] ) ) | ||||||
|  | 	{ | ||||||
|  | 		self [[ level.bot_builtins[ "botremoteangles" ] ]]( pitch, yaw ); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | 	Sets angles | ||||||
|  | */ | ||||||
|  | BotBuiltinBotAngles( angles ) | ||||||
|  | { | ||||||
|  | 	if ( isdefined( level.bot_builtins ) && isdefined( level.bot_builtins[ "botangles" ] ) ) | ||||||
|  | 	{ | ||||||
|  | 		self [[ level.bot_builtins[ "botangles" ] ]]( angles ); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
| 	Returns if player is the host | 	Returns if player is the host | ||||||
| */ | */ | ||||||
| @@ -356,12 +378,22 @@ BotStopMoving( what ) | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | 	Waits till frame end so that if two notifies happen in the same frame, the other will not be missed. | ||||||
|  | */ | ||||||
|  | BotNotifyBotEvent_( msg, a, b, c, d, e, f, g ) | ||||||
|  | { | ||||||
|  | 	self endon( "disconnect" ); | ||||||
|  | 	waittillframeend; // wait for the waittills to setup again | ||||||
|  | 	self notify( "bot_event", msg, a, b, c, d, e, f, g ); | ||||||
|  | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
| 	Notify the bot chat message | 	Notify the bot chat message | ||||||
| */ | */ | ||||||
| BotNotifyBotEvent( msg, a, b, c, d, e, f, g ) | BotNotifyBotEvent( msg, a, b, c, d, e, f, g ) | ||||||
| { | { | ||||||
| 	self notify( "bot_event", msg, a, b, c, d, e, f, g ); | 	self thread BotNotifyBotEvent_( msg, a, b, c, d, e, f, g ); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
| @@ -1252,7 +1284,6 @@ readWpsFromFile( mapname ) | |||||||
| */ | */ | ||||||
| load_waypoints() | load_waypoints() | ||||||
| { | { | ||||||
| 	level.waypointcount = 0; |  | ||||||
| 	level.waypointusage = []; | 	level.waypointusage = []; | ||||||
| 	level.waypointusage[ "allies" ] = []; | 	level.waypointusage[ "allies" ] = []; | ||||||
| 	level.waypointusage[ "axis" ] = []; | 	level.waypointusage[ "axis" ] = []; | ||||||
| @@ -1291,9 +1322,7 @@ load_waypoints() | |||||||
| 		BotBuiltinPrintConsole( "No waypoints loaded!" ); | 		BotBuiltinPrintConsole( "No waypoints loaded!" ); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	level.waypointcount = level.waypoints.size; | 	for ( i = level.waypoints.size - 1; i >= 0; i-- ) | ||||||
| 	 |  | ||||||
| 	for ( i = 0; i < level.waypointcount; i++ ) |  | ||||||
| 	{ | 	{ | ||||||
| 		if ( !isdefined( level.waypoints[ i ].children ) || !isdefined( level.waypoints[ i ].children.size ) ) | 		if ( !isdefined( level.waypoints[ i ].children ) || !isdefined( level.waypoints[ i ].children.size ) ) | ||||||
| 		{ | 		{ | ||||||
| @@ -1390,7 +1419,7 @@ getWaypointsOfType( type ) | |||||||
| { | { | ||||||
| 	answer = []; | 	answer = []; | ||||||
| 	 | 	 | ||||||
| 	for ( i = 0; i < level.waypointcount; i++ ) | 	for ( i = level.waypoints.size - 1; i >= 0; i-- ) | ||||||
| 	{ | 	{ | ||||||
| 		wp = level.waypoints[ i ]; | 		wp = level.waypoints[ i ]; | ||||||
| 		 | 		 | ||||||
| @@ -2107,16 +2136,18 @@ RemoveWaypointUsage( wp, team ) | |||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	if ( !isdefined( level.waypointusage[ team ][ wp + "" ] ) ) | 	wpstr = wp + ""; | ||||||
|  | 	 | ||||||
|  | 	if ( !isdefined( level.waypointusage[ team ][ wpstr ] ) ) | ||||||
| 	{ | 	{ | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	level.waypointusage[ team ][ wp + "" ]--; | 	level.waypointusage[ team ][ wpstr ]--; | ||||||
| 	 | 	 | ||||||
| 	if ( level.waypointusage[ team ][ wp + "" ] <= 0 ) | 	if ( level.waypointusage[ team ][ wpstr ] <= 0 ) | ||||||
| 	{ | 	{ | ||||||
| 		level.waypointusage[ team ][ wp + "" ] = undefined; | 		level.waypointusage[ team ][ wpstr ] = undefined; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -2128,7 +2159,7 @@ GetNearestWaypointWithSight( pos ) | |||||||
| 	candidate = undefined; | 	candidate = undefined; | ||||||
| 	dist = 2147483647; | 	dist = 2147483647; | ||||||
| 	 | 	 | ||||||
| 	for ( i = 0; i < level.waypointcount; i++ ) | 	for ( i = level.waypoints.size - 1; i >= 0; i-- ) | ||||||
| 	{ | 	{ | ||||||
| 		if ( !bullettracepassed( pos + ( 0, 0, 15 ), level.waypoints[ i ].origin + ( 0, 0, 15 ), false, undefined ) ) | 		if ( !bullettracepassed( pos + ( 0, 0, 15 ), level.waypoints[ i ].origin + ( 0, 0, 15 ), false, undefined ) ) | ||||||
| 		{ | 		{ | ||||||
| @@ -2157,7 +2188,7 @@ getNearestWaypoint( pos ) | |||||||
| 	candidate = undefined; | 	candidate = undefined; | ||||||
| 	dist = 2147483647; | 	dist = 2147483647; | ||||||
| 	 | 	 | ||||||
| 	for ( i = 0; i < level.waypointcount; i++ ) | 	for ( i = level.waypoints.size - 1; i >= 0; i-- ) | ||||||
| 	{ | 	{ | ||||||
| 		curdis = distancesquared( level.waypoints[ i ].origin, pos ); | 		curdis = distancesquared( level.waypoints[ i ].origin, pos ); | ||||||
| 		 | 		 | ||||||
| @@ -2242,7 +2273,8 @@ AStarSearch( start, goal, team, greedy_path ) | |||||||
| 		// pop bestnode from queue | 		// pop bestnode from queue | ||||||
| 		bestNode = open.data[ 0 ]; | 		bestNode = open.data[ 0 ]; | ||||||
| 		open HeapRemove(); | 		open HeapRemove(); | ||||||
| 		openset[ bestNode.index + "" ] = undefined; | 		bestNodeStr = bestNode.index + ""; | ||||||
|  | 		openset[ bestNodeStr ] = undefined; | ||||||
| 		wp = level.waypoints[ bestNode.index ]; | 		wp = level.waypoints[ bestNode.index ]; | ||||||
| 		 | 		 | ||||||
| 		// check if we made it to the goal | 		// check if we made it to the goal | ||||||
| @@ -2252,14 +2284,16 @@ AStarSearch( start, goal, team, greedy_path ) | |||||||
| 			 | 			 | ||||||
| 			while ( isdefined( bestNode ) ) | 			while ( isdefined( bestNode ) ) | ||||||
| 			{ | 			{ | ||||||
|  | 				bestNodeStr = bestNode.index + ""; | ||||||
|  | 				 | ||||||
| 				if ( isdefined( team ) && isdefined( level.waypointusage ) ) | 				if ( isdefined( team ) && isdefined( level.waypointusage ) ) | ||||||
| 				{ | 				{ | ||||||
| 					if ( !isdefined( level.waypointusage[ team ][ bestNode.index + "" ] ) ) | 					if ( !isdefined( level.waypointusage[ team ][ bestNodeStr ] ) ) | ||||||
| 					{ | 					{ | ||||||
| 						level.waypointusage[ team ][ bestNode.index + "" ] = 0; | 						level.waypointusage[ team ][ bestNodeStr ] = 0; | ||||||
| 					} | 					} | ||||||
| 					 | 					 | ||||||
| 					level.waypointusage[ team ][ bestNode.index + "" ]++; | 					level.waypointusage[ team ][ bestNodeStr ]++; | ||||||
| 				} | 				} | ||||||
| 				 | 				 | ||||||
| 				// construct path | 				// construct path | ||||||
| @@ -2275,6 +2309,7 @@ AStarSearch( start, goal, team, greedy_path ) | |||||||
| 		for ( i = wp.children.size - 1; i >= 0; i-- ) | 		for ( i = wp.children.size - 1; i >= 0; i-- ) | ||||||
| 		{ | 		{ | ||||||
| 			child = wp.children[ i ]; | 			child = wp.children[ i ]; | ||||||
|  | 			childStr = child + ""; | ||||||
| 			childWp = level.waypoints[ child ]; | 			childWp = level.waypoints[ child ]; | ||||||
| 			 | 			 | ||||||
| 			penalty = 1; | 			penalty = 1; | ||||||
| @@ -2283,9 +2318,9 @@ AStarSearch( start, goal, team, greedy_path ) | |||||||
| 			{ | 			{ | ||||||
| 				temppen = 1; | 				temppen = 1; | ||||||
| 				 | 				 | ||||||
| 				if ( isdefined( level.waypointusage[ team ][ child + "" ] ) ) | 				if ( isdefined( level.waypointusage[ team ][ childStr ] ) ) | ||||||
| 				{ | 				{ | ||||||
| 					temppen = level.waypointusage[ team ][ child + "" ]; // consider how many bots are taking this path | 					temppen = level.waypointusage[ team ][ childStr ]; // consider how many bots are taking this path | ||||||
| 				} | 				} | ||||||
| 				 | 				 | ||||||
| 				if ( temppen > 1 ) | 				if ( temppen > 1 ) | ||||||
| @@ -2304,16 +2339,16 @@ AStarSearch( start, goal, team, greedy_path ) | |||||||
| 			newg = bestNode.g + distancesquared( wp.origin, childWp.origin ) * penalty; // bots on same team's path are more expensive | 			newg = bestNode.g + distancesquared( wp.origin, childWp.origin ) * penalty; // bots on same team's path are more expensive | ||||||
| 			 | 			 | ||||||
| 			// check if this child is in open or close with a g value less than newg | 			// check if this child is in open or close with a g value less than newg | ||||||
| 			inopen = isdefined( openset[ child + "" ] ); | 			inopen = isdefined( openset[ childStr ] ); | ||||||
| 			 | 			 | ||||||
| 			if ( inopen && openset[ child + "" ].g <= newg ) | 			if ( inopen && openset[ childStr ].g <= newg ) | ||||||
| 			{ | 			{ | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
| 			 | 			 | ||||||
| 			inclosed = isdefined( closed[ child + "" ] ); | 			inclosed = isdefined( closed[ childStr ] ); | ||||||
| 			 | 			 | ||||||
| 			if ( inclosed && closed[ child + "" ].g <= newg ) | 			if ( inclosed && closed[ childStr ].g <= newg ) | ||||||
| 			{ | 			{ | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
| @@ -2322,11 +2357,11 @@ AStarSearch( start, goal, team, greedy_path ) | |||||||
| 			 | 			 | ||||||
| 			if ( inopen ) | 			if ( inopen ) | ||||||
| 			{ | 			{ | ||||||
| 				node = openset[ child + "" ]; | 				node = openset[ childStr ]; | ||||||
| 			} | 			} | ||||||
| 			else if ( inclosed ) | 			else if ( inclosed ) | ||||||
| 			{ | 			{ | ||||||
| 				node = closed[ child + "" ]; | 				node = closed[ childStr ]; | ||||||
| 			} | 			} | ||||||
| 			else | 			else | ||||||
| 			{ | 			{ | ||||||
| @@ -2342,19 +2377,19 @@ AStarSearch( start, goal, team, greedy_path ) | |||||||
| 			// check if in closed, remove it | 			// check if in closed, remove it | ||||||
| 			if ( inclosed ) | 			if ( inclosed ) | ||||||
| 			{ | 			{ | ||||||
| 				closed[ child + "" ] = undefined; | 				closed[ childStr ] = undefined; | ||||||
| 			} | 			} | ||||||
| 			 | 			 | ||||||
| 			// check if not in open, add it | 			// check if not in open, add it | ||||||
| 			if ( !inopen ) | 			if ( !inopen ) | ||||||
| 			{ | 			{ | ||||||
| 				open HeapInsert( node ); | 				open HeapInsert( node ); | ||||||
| 				openset[ child + "" ] = node; | 				openset[ childStr ] = node; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		// done with children, push onto closed | 		// done with children, push onto closed | ||||||
| 		closed[ bestNode.index + "" ] = bestNode; | 		closed[ bestNodeStr ] = bestNode; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	return []; | 	return []; | ||||||
| @@ -3697,3 +3732,169 @@ playerModelForWeapon( weapon, secondary ) | |||||||
| 		[[ game[ team + "_model" ][ "JUGGERNAUT" ] ]](); | 		[[ game[ team + "_model" ][ "JUGGERNAUT" ] ]](); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | 	Make player ref attach to rocket ent | ||||||
|  | */ | ||||||
|  | tryUsePredatorMissileFix( lifeId ) | ||||||
|  | { | ||||||
|  | 	if ( isdefined( level.civilianjetflyby ) ) | ||||||
|  | 	{ | ||||||
|  | 		self iprintlnbold( &"MP_CIVILIAN_AIR_TRAFFIC" ); | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	self setusingremote( "remotemissile" ); | ||||||
|  | 	result = self maps\mp\killstreaks\_killstreaks::initridekillstreak(); | ||||||
|  | 	 | ||||||
|  | 	if ( result != "success" ) | ||||||
|  | 	{ | ||||||
|  | 		if ( result != "disconnect" ) | ||||||
|  | 		{ | ||||||
|  | 			self clearusingremote(); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	level thread _fireFix( lifeId, self ); | ||||||
|  | 	 | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | 	Make player ref attach to rocket ent | ||||||
|  | */ | ||||||
|  | _fireFix( lifeId, player ) | ||||||
|  | { | ||||||
|  | 	remoteMissileSpawnArray = getentarray( "remoteMissileSpawn", "targetname" ); | ||||||
|  | 	//assertEX( remoteMissileSpawnArray.size > 0 && getMapCustom( "map" ) != "", "No remote missile spawn points found.  Contact friendly neighborhood designer" ); | ||||||
|  | 	 | ||||||
|  | 	foreach ( spawn in remoteMissileSpawnArray ) | ||||||
|  | 	{ | ||||||
|  | 		if ( isdefined( spawn.target ) ) | ||||||
|  | 		{ | ||||||
|  | 			spawn.targetent = getent( spawn.target, "targetname" ); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	if ( remoteMissileSpawnArray.size > 0 ) | ||||||
|  | 	{ | ||||||
|  | 		remoteMissileSpawn = player maps\mp\killstreaks\_remotemissile::getbestspawnpoint( remoteMissileSpawnArray ); | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		remoteMissileSpawn = undefined; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	if ( isdefined( remoteMissileSpawn ) ) | ||||||
|  | 	{ | ||||||
|  | 		startPos = remoteMissileSpawn.origin; | ||||||
|  | 		targetPos = remoteMissileSpawn.targetent.origin; | ||||||
|  | 		 | ||||||
|  | 		//thread drawLine( startPos, targetPos, 30, (0,1,0) ); | ||||||
|  | 		 | ||||||
|  | 		vector = vectornormalize( startPos - targetPos ); | ||||||
|  | 		startPos = vector * 14000 + targetPos; | ||||||
|  | 		 | ||||||
|  | 		//thread drawLine( startPos, targetPos, 15, (1,0,0) ); | ||||||
|  | 		 | ||||||
|  | 		rocket = magicbullet( "remotemissile_projectile_mp", startpos, targetPos, player ); | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		upVector = ( 0, 0, level.missileremotelaunchvert ); | ||||||
|  | 		backDist = level.missileremotelaunchhorz; | ||||||
|  | 		targetDist = level.missileremotelaunchtargetdist; | ||||||
|  | 		 | ||||||
|  | 		forward = anglestoforward( player.angles ); | ||||||
|  | 		startpos = player.origin + upVector + forward * backDist * -1; | ||||||
|  | 		targetPos = player.origin + forward * targetDist; | ||||||
|  | 		 | ||||||
|  | 		rocket = magicbullet( "remotemissile_projectile_mp", startpos, targetPos, player ); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	if ( !isdefined( rocket ) ) | ||||||
|  | 	{ | ||||||
|  | 		player clearusingremote(); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	rocket thread maps\mp\gametypes\_weapons::addmissiletosighttraces( player.team ); | ||||||
|  | 	 | ||||||
|  | 	// rocket thread maps\mp\killstreaks\_remotemissile::handledamage(); // gsc-tool wrong token, its okay, this func is useless anyway | ||||||
|  | 	 | ||||||
|  | 	rocket.lifeid = lifeId; | ||||||
|  | 	rocket.type = "remote"; | ||||||
|  | 	MissileEyesFix( player, rocket ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | 	Make player ref attach to rocket ent | ||||||
|  | */ | ||||||
|  | MissileEyesFix( player, rocket ) | ||||||
|  | { | ||||||
|  | 	//level endon ( "game_ended" ); | ||||||
|  | 	player endon( "joined_team" ); | ||||||
|  | 	player endon( "joined_spectators" ); | ||||||
|  | 	 | ||||||
|  | 	rocket thread maps\mp\killstreaks\_remotemissile::rocket_cleanupondeath(); | ||||||
|  | 	player thread maps\mp\killstreaks\_remotemissile::player_cleanupongameended( rocket ); | ||||||
|  | 	player thread maps\mp\killstreaks\_remotemissile::player_cleanuponteamchange( rocket ); | ||||||
|  | 	 | ||||||
|  | 	player visionsetmissilecamforplayer( "black_bw", 0 ); | ||||||
|  | 	 | ||||||
|  | 	player endon ( "disconnect" ); | ||||||
|  | 	 | ||||||
|  | 	if ( isdefined( rocket ) ) | ||||||
|  | 	{ | ||||||
|  | 		player visionsetmissilecamforplayer( game["thermal_vision"], 1.0 ); | ||||||
|  | 		player thermalvisionon(); | ||||||
|  | 		player thread maps\mp\killstreaks\_remotemissile::delayedfofoverlay(); | ||||||
|  | 		player cameralinkto( rocket, "tag_origin" ); | ||||||
|  | 		player controlslinkto( rocket ); | ||||||
|  | 		 | ||||||
|  | 		// our additions | ||||||
|  | 		player.rocket = rocket; | ||||||
|  | 		rocket.owner = player; | ||||||
|  | 		 | ||||||
|  | 		if ( getdvarint( "camera_thirdPerson" ) ) | ||||||
|  | 		{ | ||||||
|  | 			player setthirdpersondof( false ); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		rocket waittill( "death" ); | ||||||
|  | 		player thermalvisionoff(); | ||||||
|  | 		 | ||||||
|  | 		// is defined check required because remote missile doesnt handle lifetime explosion gracefully | ||||||
|  | 		// instantly deletes its self after an explode and death notify | ||||||
|  | 		if ( isdefined( rocket ) ) | ||||||
|  | 		{ | ||||||
|  | 			player maps\mp\_matchdata::logkillstreakevent( "predator_missile", rocket.origin ); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		player controlsunlink(); | ||||||
|  | 		player freezecontrolswrapper( true ); | ||||||
|  | 		player.rocket = undefined; // our addition | ||||||
|  | 		 | ||||||
|  | 		// If a player gets the final kill with a hellfire, level.gameEnded will already be true at this point | ||||||
|  | 		if ( !level.gameended || isdefined( player.finalkill ) ) | ||||||
|  | 		{ | ||||||
|  | 			player thread maps\mp\killstreaks\_remotemissile::staticeffect( 0.5 ); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		wait ( 0.5 ); | ||||||
|  | 		 | ||||||
|  | 		player thermalvisionfofoverlayoff(); | ||||||
|  | 		 | ||||||
|  | 		player cameraunlink(); | ||||||
|  | 		 | ||||||
|  | 		if ( getdvarint( "camera_thirdPerson" ) ) | ||||||
|  | 		{ | ||||||
|  | 			player setthirdpersondof( true ); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	player clearusingremote(); | ||||||
|  | } | ||||||
|   | |||||||
| @@ -55,6 +55,50 @@ watchPlayers() | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | destroyFixed() | ||||||
|  | { | ||||||
|  | 	if ( !isdefined( self ) ) | ||||||
|  | 	{ | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	self destroy(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | removeChildFixed( element ) | ||||||
|  | { | ||||||
|  | 	temp = []; | ||||||
|  | 	 | ||||||
|  | 	for ( i = 0; i < self.children.size ; i++ ) | ||||||
|  | 	{ | ||||||
|  | 		if ( isdefined( self.children[ i ] ) && self.children[ i ] != element ) | ||||||
|  | 		{ | ||||||
|  | 			self.children[ i ].index = temp.size; | ||||||
|  | 			temp[ temp.size ] = self.children[ i ]; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	self.children = temp; | ||||||
|  | 	 | ||||||
|  | 	element.index = undefined; | ||||||
|  | 	element.parent = undefined; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | destroyElemFixed() | ||||||
|  | { | ||||||
|  | 	if ( !isdefined( self ) ) | ||||||
|  | 	{ | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	if ( isdefined( self.parent ) ) | ||||||
|  | 	{ | ||||||
|  | 		self.parent removeChildFixed( self ); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	self destroyelem(); | ||||||
|  | } | ||||||
|  |  | ||||||
| kill_menu() | kill_menu() | ||||||
| { | { | ||||||
| 	self notify( "bots_kill_menu" ); | 	self notify( "bots_kill_menu" ); | ||||||
| @@ -66,7 +110,6 @@ init_menu() | |||||||
| 	self.menuinit = true; | 	self.menuinit = true; | ||||||
| 	 | 	 | ||||||
| 	self.menuopen = false; | 	self.menuopen = false; | ||||||
| 	self.menu_player = undefined; |  | ||||||
| 	self.submenu = "Main"; | 	self.submenu = "Main"; | ||||||
| 	self.curs[ "Main" ][ "X" ] = 0; | 	self.curs[ "Main" ][ "X" ] = 0; | ||||||
| 	self addOptions(); | 	self addOptions(); | ||||||
| @@ -95,7 +138,7 @@ watchDisconnect() | |||||||
| 			{ | 			{ | ||||||
| 				if ( isdefined( self.menutexty[ i ] ) ) | 				if ( isdefined( self.menutexty[ i ] ) ) | ||||||
| 				{ | 				{ | ||||||
| 					self.menutexty[ i ] destroy(); | 					self.menutexty[ i ] destroyElemFixed(); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -106,7 +149,7 @@ watchDisconnect() | |||||||
| 			{ | 			{ | ||||||
| 				if ( isdefined( self.menutext[ i ] ) ) | 				if ( isdefined( self.menutext[ i ] ) ) | ||||||
| 				{ | 				{ | ||||||
| 					self.menutext[ i ] destroy(); | 					self.menutext[ i ] destroyElemFixed(); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -115,18 +158,18 @@ watchDisconnect() | |||||||
| 		{ | 		{ | ||||||
| 			if ( isdefined( self.menu[ "X" ][ "Shader" ] ) ) | 			if ( isdefined( self.menu[ "X" ][ "Shader" ] ) ) | ||||||
| 			{ | 			{ | ||||||
| 				self.menu[ "X" ][ "Shader" ] destroy(); | 				self.menu[ "X" ][ "Shader" ] destroyElemFixed(); | ||||||
| 			} | 			} | ||||||
| 			 | 			 | ||||||
| 			if ( isdefined( self.menu[ "X" ][ "Scroller" ] ) ) | 			if ( isdefined( self.menu[ "X" ][ "Scroller" ] ) ) | ||||||
| 			{ | 			{ | ||||||
| 				self.menu[ "X" ][ "Scroller" ] destroy(); | 				self.menu[ "X" ][ "Scroller" ] destroyElemFixed(); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		if ( isdefined( self.menuversionhud ) ) | 		if ( isdefined( self.menuversionhud ) ) | ||||||
| 		{ | 		{ | ||||||
| 			self.menuversionhud destroy(); | 			self.menuversionhud destroyFixed(); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @@ -332,7 +375,7 @@ OpenSub( menu, menu2 ) | |||||||
| 			{ | 			{ | ||||||
| 				if ( isdefined( self.menutext[ i ] ) ) | 				if ( isdefined( self.menutext[ i ] ) ) | ||||||
| 				{ | 				{ | ||||||
| 					self.menutext[ i ] destroy(); | 					self.menutext[ i ] destroyElemFixed(); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -341,18 +384,18 @@ OpenSub( menu, menu2 ) | |||||||
| 		{ | 		{ | ||||||
| 			if ( isdefined( self.menu[ "X" ][ "Shader" ] ) ) | 			if ( isdefined( self.menu[ "X" ][ "Shader" ] ) ) | ||||||
| 			{ | 			{ | ||||||
| 				self.menu[ "X" ][ "Shader" ] destroy(); | 				self.menu[ "X" ][ "Shader" ] destroyElemFixed(); | ||||||
| 			} | 			} | ||||||
| 			 | 			 | ||||||
| 			if ( isdefined( self.menu[ "X" ][ "Scroller" ] ) ) | 			if ( isdefined( self.menu[ "X" ][ "Scroller" ] ) ) | ||||||
| 			{ | 			{ | ||||||
| 				self.menu[ "X" ][ "Scroller" ] destroy(); | 				self.menu[ "X" ][ "Scroller" ] destroyElemFixed(); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		if ( isdefined( self.menuversionhud ) ) | 		if ( isdefined( self.menuversionhud ) ) | ||||||
| 		{ | 		{ | ||||||
| 			self.menuversionhud destroy(); | 			self.menuversionhud destroyFixed(); | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		for ( i = 0 ; i < self.option[ "Name" ][ self.submenu ].size ; i++ ) | 		for ( i = 0 ; i < self.option[ "Name" ][ self.submenu ].size ; i++ ) | ||||||
| @@ -402,7 +445,7 @@ OpenSub( menu, menu2 ) | |||||||
| 			{ | 			{ | ||||||
| 				if ( isdefined( self.menutexty[ i ] ) ) | 				if ( isdefined( self.menutexty[ i ] ) ) | ||||||
| 				{ | 				{ | ||||||
| 					self.menutexty[ i ] destroy(); | 					self.menutexty[ i ] destroyElemFixed(); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -426,11 +469,11 @@ CursMove( direction ) | |||||||
| 	 | 	 | ||||||
| 	if ( self.submenu == "Main" ) | 	if ( self.submenu == "Main" ) | ||||||
| 	{ | 	{ | ||||||
| 		self.menu[ "X" ][ "Scroller" ].x = self.menutext[ self.curs[ "Main" ][ "X" ] ].x; |  | ||||||
| 		self.menu[ "X" ][ "Scroller" ].y = self.menutext[ self.curs[ "Main" ][ "X" ] ].y; |  | ||||||
| 		 |  | ||||||
| 		if ( isdefined( self.menutext ) ) | 		if ( isdefined( self.menutext ) ) | ||||||
| 		{ | 		{ | ||||||
|  | 			self.menu[ "X" ][ "Scroller" ].x = self.menutext[ self.curs[ "Main" ][ "X" ] ].x; | ||||||
|  | 			self.menu[ "X" ][ "Scroller" ].y = self.menutext[ self.curs[ "Main" ][ "X" ] ].y; | ||||||
|  | 			 | ||||||
| 			for ( i = 0; i < self.menutext.size; i++ ) | 			for ( i = 0; i < self.menutext.size; i++ ) | ||||||
| 			{ | 			{ | ||||||
| 				if ( isdefined( self.menutext[ i ] ) ) | 				if ( isdefined( self.menutext[ i ] ) ) | ||||||
| @@ -578,7 +621,7 @@ ExitSub() | |||||||
| 		{ | 		{ | ||||||
| 			if ( isdefined( self.menutexty[ i ] ) ) | 			if ( isdefined( self.menutexty[ i ] ) ) | ||||||
| 			{ | 			{ | ||||||
| 				self.menutexty[ i ] destroy(); | 				self.menutexty[ i ] destroyElemFixed(); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -603,7 +646,7 @@ ExitMenu() | |||||||
| 		{ | 		{ | ||||||
| 			if ( isdefined( self.menutext[ i ] ) ) | 			if ( isdefined( self.menutext[ i ] ) ) | ||||||
| 			{ | 			{ | ||||||
| 				self.menutext[ i ] destroy(); | 				self.menutext[ i ] destroyElemFixed(); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -612,18 +655,18 @@ ExitMenu() | |||||||
| 	{ | 	{ | ||||||
| 		if ( isdefined( self.menu[ "X" ][ "Shader" ] ) ) | 		if ( isdefined( self.menu[ "X" ][ "Shader" ] ) ) | ||||||
| 		{ | 		{ | ||||||
| 			self.menu[ "X" ][ "Shader" ] destroy(); | 			self.menu[ "X" ][ "Shader" ] destroyElemFixed(); | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		if ( isdefined( self.menu[ "X" ][ "Scroller" ] ) ) | 		if ( isdefined( self.menu[ "X" ][ "Scroller" ] ) ) | ||||||
| 		{ | 		{ | ||||||
| 			self.menu[ "X" ][ "Scroller" ] destroy(); | 			self.menu[ "X" ][ "Scroller" ] destroyElemFixed(); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	if ( isdefined( self.menuversionhud ) ) | 	if ( isdefined( self.menuversionhud ) ) | ||||||
| 	{ | 	{ | ||||||
| 		self.menuversionhud destroy(); | 		self.menuversionhud destroyFixed(); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	self.menuopen = false; | 	self.menuopen = false; | ||||||
|   | |||||||
| @@ -77,7 +77,7 @@ init() | |||||||
| 		level.waypoints = []; | 		level.waypoints = []; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	level.waypointcount = 0; | 	level.waypointcount = level.waypoints.size; | ||||||
| 	 | 	 | ||||||
| 	level waittill( "connected", player ); | 	level waittill( "connected", player ); | ||||||
| 	player thread onPlayerSpawned(); | 	player thread onPlayerSpawned(); | ||||||
| @@ -153,29 +153,29 @@ watchAstarCommand() | |||||||
| 	self endon( "death" ); | 	self endon( "death" ); | ||||||
| 	 | 	 | ||||||
| 	self notifyonplayercommand( "astar", "+gostand" ); | 	self notifyonplayercommand( "astar", "+gostand" ); | ||||||
|  | 	self.astar = undefined; | ||||||
| 	 | 	 | ||||||
| 	for ( ;; ) | 	for ( ;; ) | ||||||
| 	{ | 	{ | ||||||
| 		self waittill( "astar" ); | 		self waittill( "astar" ); | ||||||
| 		 | 		 | ||||||
| 		if ( 1 ) | 		if ( isdefined( self.astar ) ) | ||||||
| 		{ | 		{ | ||||||
| 			continue; | 			self iprintln( "Clear AStar" ); | ||||||
|  | 			self.astar = undefined; | ||||||
|  | 			self waittill( "astar" ); | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		self iprintln( "Start AStar" ); | 		self iprintln( "Start AStar" ); | ||||||
| 		self.astar = undefined; | 		self.astar = spawnstruct(); | ||||||
| 		astar = spawnstruct(); | 		self.astar.start = self.origin; | ||||||
| 		astar.start = self.origin; |  | ||||||
| 		 | 		 | ||||||
| 		self waittill( "astar" ); | 		self waittill( "astar" ); | ||||||
| 		self iprintln( "End AStar" ); | 		self iprintln( "End AStar" ); | ||||||
| 		astar.goal = self.origin; | 		self.astar.goal = self.origin; | ||||||
| 		 | 		 | ||||||
| 		astar.nodes = AStarSearch( astar.start, astar.goal, undefined, true ); | 		self.astar.nodes = AStarSearch( self.astar.start, self.astar.goal, undefined, true ); | ||||||
| 		self iprintln( "AStar size: " + astar.nodes.size ); | 		self iprintln( "AStar size: " + self.astar.nodes.size ); | ||||||
| 		 |  | ||||||
| 		self.astar = astar; |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -405,30 +405,45 @@ updateWaypointsStats() | |||||||
| 		 | 		 | ||||||
| 		if ( isdefined( self.astar ) ) | 		if ( isdefined( self.astar ) ) | ||||||
| 		{ | 		{ | ||||||
| 			// print3d(self.astar.start + (0, 0, 35), "start", (0,0,1), 2); | 			if ( isdefined( self.astar.start ) ) | ||||||
| 			// print3d(self.astar.goal + (0, 0, 35), "goal", (0,0,1), 2); |  | ||||||
| 			if ( timeToUpdate ) |  | ||||||
| 			{ | 			{ | ||||||
| 				drawPath( self.astar.start ); | 				// print3d( self.astar.start + ( 0, 0, 35 ), "start", ( 0, 0, 1 ), 2 ); | ||||||
| 				drawPath( self.astar.goal ); |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			prev = self.astar.start + ( 0, 0, 35 ); |  | ||||||
| 			 |  | ||||||
| 			for ( i = self.astar.nodes.size - 1; i >= 0; i-- ) |  | ||||||
| 			{ |  | ||||||
| 				node = self.astar.nodes[ i ]; |  | ||||||
| 				 | 				 | ||||||
| 				// line(prev, level.waypoints[ node ].origin + (0, 0, 35), (0,1,1)); |  | ||||||
| 				if ( timeToUpdate ) | 				if ( timeToUpdate ) | ||||||
| 				{ | 				{ | ||||||
| 					drawPath( level.waypoints[ node ].origin ); | 					drawPath( self.astar.start ); | ||||||
| 				} | 				} | ||||||
| 				 |  | ||||||
| 				prev = level.waypoints[ node ].origin + ( 0, 0, 35 ); |  | ||||||
| 			} | 			} | ||||||
| 			 | 			 | ||||||
| 			// line(prev, self.astar.goal + (0, 0, 35), (0,1,1)); | 			if ( isdefined( self.astar.goal ) ) | ||||||
|  | 			{ | ||||||
|  | 				// print3d( self.astar.goal + ( 0, 0, 35 ), "goal", ( 0, 0, 1 ), 2 ); | ||||||
|  | 				 | ||||||
|  | 				if ( timeToUpdate ) | ||||||
|  | 				{ | ||||||
|  | 					drawPath( self.astar.goal ); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			if ( isdefined( self.astar.start ) && isdefined( self.astar.goal ) && isdefined( self.astar.nodes ) ) | ||||||
|  | 			{ | ||||||
|  | 				prev = self.astar.start + ( 0, 0, 35 ); | ||||||
|  | 				 | ||||||
|  | 				for ( i = self.astar.nodes.size - 1; i >= 0; i-- ) | ||||||
|  | 				{ | ||||||
|  | 					node = self.astar.nodes[ i ]; | ||||||
|  | 					 | ||||||
|  | 					// line(prev, level.waypoints[ node ].origin + (0, 0, 35), (0,1,1)); | ||||||
|  | 					if ( timeToUpdate ) | ||||||
|  | 					{ | ||||||
|  | 						drawPath( level.waypoints[ node ].origin ); | ||||||
|  | 					} | ||||||
|  | 					 | ||||||
|  | 					prev = level.waypoints[ node ].origin + ( 0, 0, 35 ); | ||||||
|  | 				} | ||||||
|  | 				 | ||||||
|  | 				// line(prev, self.astar.goal + (0, 0, 35), (0,1,1)); | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @@ -646,6 +661,7 @@ LoadWaypoints() | |||||||
| 	// self DeleteAllWaypoints(); | 	// self DeleteAllWaypoints(); | ||||||
| 	self iprintlnbold( "Loading WPS..." ); | 	self iprintlnbold( "Loading WPS..." ); | ||||||
| 	load_waypoints(); | 	load_waypoints(); | ||||||
|  | 	level.waypointcount = level.waypoints.size; | ||||||
| 	 | 	 | ||||||
| 	wait 1; | 	wait 1; | ||||||
| 	 | 	 | ||||||
| @@ -934,7 +950,7 @@ DeleteAllWaypoints() | |||||||
| 	self iprintln( "DelAllWps" ); | 	self iprintln( "DelAllWps" ); | ||||||
| } | } | ||||||
|  |  | ||||||
| buildChildCountString ( wp ) | buildChildCountString( wp ) | ||||||
| { | { | ||||||
| 	if ( wp == -1 ) | 	if ( wp == -1 ) | ||||||
| 	{ | 	{ | ||||||
|   | |||||||
| @@ -8,6 +8,8 @@ init() | |||||||
| 	level.bot_builtins["botstop"] = ::do_botstop; | 	level.bot_builtins["botstop"] = ::do_botstop; | ||||||
| 	level.bot_builtins["botmovement"] = ::do_botmovement; | 	level.bot_builtins["botmovement"] = ::do_botmovement; | ||||||
| 	level.bot_builtins["botmeleeparams"] = ::do_botmeleeparams; | 	level.bot_builtins["botmeleeparams"] = ::do_botmeleeparams; | ||||||
|  | 	level.bot_builtins[ "botremoteangles" ] = ::do_botremoteangles; | ||||||
|  | 	level.bot_builtins[ "botangles" ] = ::do_botangles; | ||||||
| } | } | ||||||
|  |  | ||||||
| do_printconsole( s ) | do_printconsole( s ) | ||||||
| @@ -51,3 +53,13 @@ do_botmeleeparams( entNum, dist ) | |||||||
| { | { | ||||||
| 	self botmeleeparams( entNum, dist ); | 	self botmeleeparams( entNum, dist ); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | do_botremoteangles( pitch, yaw ) | ||||||
|  | { | ||||||
|  | 	self botremoteangles( pitch, yaw ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | do_botangles( angles ) | ||||||
|  | { | ||||||
|  | 	self botangles( angles[ 0 ], angles[ 1 ], angles[ 2 ] ); | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user