Compare commits

...

32 Commits

Author SHA1 Message Date
ineed bots
1ca1cab3de fix this logic error 2025-01-23 23:44:24 -06:00
ineed bots
78435888b8 wait for notifies 2024-10-22 10:04:52 -06:00
ineed bots
d76bff04a6 Merge branch 'master' of https://github.com/ineedbots/piw5_bot_warfare 2024-09-21 20:25:50 -06:00
ineed bots
02ffc62730 import old camp changes 2024-09-21 20:25:47 -06:00
INeedGames
ab7979f9d1
Update README.md
rip rsebots.blogspot
2024-08-13 11:31:14 -06:00
ineed bots
3325405f08 missing tag 2024-05-17 07:52:49 -06:00
ineed bots
b005f90e99 add menu option 2024-05-16 10:44:45 -06:00
ineed bots
41fb775e97 simplify 2024-05-16 10:35:01 -06:00
ineed bots
3a68ef5ffc add bots_manage_fill_watchplayers 2024-05-16 10:32:16 -06:00
INeedGames
7a8041f065
Update README.md 2024-05-12 22:02:38 -06:00
ineed bots
d92d2c03c4 fix script errors 2024-05-10 00:06:49 -06:00
ineed bots
12ca117bdc fixed menu var leak 2024-05-09 20:54:03 -06:00
ineed bots
0300692cdd turret 2024-05-09 14:18:13 -06:00
ineed bots
d2ddce2169 update 2024-04-30 13:09:03 -06:00
ineed bots
7028290495 comment out 2024-04-30 10:56:15 -06:00
ineed bots
39c6f5054f the angle update 2024-04-30 01:33:08 -06:00
ineed bots
b47088538e chat event 2024-04-26 13:37:00 -06:00
ineed bots
1e0daca087 playername 2024-04-25 14:50:04 -06:00
ineed bots
dfe2ba0c47 connection events 2024-04-25 14:20:01 -06:00
ineed bots
c8df9ef311 cleanup 2024-04-05 14:11:28 -06:00
ineed bots
0b22a6b8a6 small fix 2024-04-04 17:02:46 -06:00
ineed bots
60a8f65180 update bones 2024-04-04 14:51:37 -06:00
ineed bots
5719080f45 update bones 2024-04-04 14:38:55 -06:00
ineed bots
1bf8314acd Cleanup trace for bones
Cleanup waypointcount
cleanup str concat
2024-04-04 13:19:51 -06:00
ineed bots
f31a306b0a missing 2024-03-20 15:24:20 -06:00
ineed bots
c4a222089c use options 2024-03-20 15:14:00 -06:00
ineed bots
a1651baa5a fix 2024-03-20 13:13:08 -06:00
ineed bots
748d261c02 add 2024-03-20 13:04:31 -06:00
ineed bots
06dfea7790 update 2024-03-20 13:04:27 -06:00
ineed bots
a9ea7acec3 pregsc 2024-03-20 12:57:08 -06:00
ineed bots
26a5adae13 waittillframeend bot events 2024-03-12 15:06:30 -06:00
INeedGames
a37aadfc2b
Update README.md 2024-03-11 13:17:13 -06:00
15 changed files with 869 additions and 251 deletions

View File

@ -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
View 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
View File

@ -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

View File

@ -75,19 +75,20 @@ You can find the ModDB release post [here](https://www.moddb.com/mods/bot-warfar
| bots_main_GUIDs | A comma separated list of GUIDs of players who will be given host. | | | bots_main_GUIDs | A comma separated list of GUIDs of players who will be given host. | |
| bots_main_waitForHostTime | How many seconds to wait for the host player to connect before adding bots to the match. | 10 | | bots_main_waitForHostTime | How many seconds to wait for the host player to connect before adding bots to the match. | 10 |
| bots_main_menu | Enable the in-game menu for hosts. | 1 | | bots_main_menu | Enable the in-game menu for hosts. | 1 |
| bots_main_debug | Enable the in-game waypoint editor. | 0 | | bots_main_debug | Enable the in-game waypoint editor at start of the game, or enable bot event prints. <ul><li>`0` - disable</li><li>`1` - for just debug events</li><li>`2` - for every event</li><ul> | 0 |
| bots_main_kickBotsAtEnd | Kick the bots at the end of a match. | 0 | | bots_main_kickBotsAtEnd | Kick the bots at the end of a match. | 0 |
| bots_main_chat | The rate bots will chat at, set to 0 to disable. | 1.0 | | bots_main_chat | The rate bots will chat at, set to 0 to disable. | 1.0 |
| bots_manage_add | Amount of bots to add to the game, once bots are added, resets back to `0`. | 0 | | bots_manage_add | Amount of bots to add to the game, once bots are added, resets back to `0`. | 0 |
| bots_manage_fill | Amount of players/bots (look at `bots_manage_fill_mode`) to maintain in the match. | 0 | | bots_manage_fill | Amount of players/bots (look at `bots_manage_fill_mode`) to maintain in the match. | 0 |
| bots_manage_fill_mode | `bots_manage_fill` players/bots counting method.<ul><li>`0` - counts both players and bots.</li><li>`1` - only counts bots.</li></ul> | 0 | | bots_manage_fill_mode | `bots_manage_fill` players/bots counting method.<ul><li>`0` - counts both players and bots.</li><li>`1` - only counts bots.</li><li>`2` - exactly `0` but auto adjusts `bots_manage_fill` to map.</li><li>`3` - exactly `1` but auto adjusts `bots_manage_fill` to map.</li><li>`4` - bots are used for balancing teams.</li><li>`5` - exactly `4` but auto adjusts `bots_manage_fill` to map.</li></ul> | 0 |
| bots_manage_fill_kick | If the amount of players/bots in the match exceeds `bots_manage_fill`, kick bots until no longer exceeds. | 0 | | bots_manage_fill_watchplayers | Bots will not be added until one player is in the game | 0 |
| bots_manage_fill_kick | If the amount of players/bots in the match exceeds `bots_manage_fill`, kick bots until no longer exceeds. | 0 |
| bots_manage_fill_spec | If when counting players for `bots_manage_fill` should include spectators. | 1 | | bots_manage_fill_spec | If when counting players for `bots_manage_fill` should include spectators. | 1 |
| bots_team | One of `autoassign`, `allies`, `axis`, `spectator`, or `custom`. What team the bots should be on. | autoassign | | bots_team | One of `autoassign`, `allies`, `axis`, `spectator`, or `custom`. What team the bots should be on. | autoassign |
| 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 `1` 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><li>`9` - Every difficulty parameter is randomized</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 +113,18 @@ 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)
- Added bots_manage_fill_watchplayers dvar
- Bots hop off turrets if they get stuck on one
- Fixed script variable leak with opening and closing the in-game menu
- 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
@ -128,9 +137,10 @@ You can find the ModDB release post [here](https://www.moddb.com/mods/bot-warfar
- INeedGames - http://www.moddb.com/mods/bot-warfare - INeedGames - http://www.moddb.com/mods/bot-warfare
- tinkie101 - https://web.archive.org/web/20120326060712/http://alteriw.net/viewtopic.php?f=72&t=4869 - tinkie101 - https://web.archive.org/web/20120326060712/http://alteriw.net/viewtopic.php?f=72&t=4869
- PeZBot team - http://www.moddb.com/mods/pezbot - PeZBot team - http://www.moddb.com/mods/pezbot
- apdonato - http://rsebots.blogspot.ca/ - apdonato - https://web.archive.org/web/20240516065610/http://rsebots.blogspot.com/
- 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
View 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 .\

View File

@ -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
View 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\

View File

@ -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" ) == "" )
{ {
@ -80,6 +80,11 @@ init()
setdvar( "bots_manage_fill_kick", false ); // kick bots if too many setdvar( "bots_manage_fill_kick", false ); // kick bots if too many
} }
if ( getdvar( "bots_manage_fill_watchplayers" ) == "" )
{
setdvar( "bots_manage_fill_watchplayers", false ); // add bots when player exists, kick if not
}
if ( getdvar( "bots_team" ) == "" ) if ( getdvar( "bots_team" ) == "" )
{ {
setdvar( "bots_team", "autoassign" ); // which team for bots to join setdvar( "bots_team", "autoassign" ); // which team for bots to join
@ -218,8 +223,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 +285,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 +294,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 +876,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 +910,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();
@ -891,10 +945,10 @@ connected()
level.bots[ level.bots.size ] = self; level.bots[ level.bots.size ] = self;
self thread onDisconnect(); self thread onDisconnect();
level notify( "bot_connected", self );
self thread watchBotDebugEvent(); self thread watchBotDebugEvent();
waittillframeend; // wait for waittills to process
level notify( "bot_connected", self );
} }
/* /*
@ -1294,7 +1348,7 @@ addBots_loop()
fillMode = getdvarint( "bots_manage_fill_mode" ); fillMode = getdvarint( "bots_manage_fill_mode" );
if ( fillMode == 2 || fillMode == 3 ) if ( fillMode == 2 || fillMode == 3 || fillMode == 5 )
{ {
setdvar( "bots_manage_fill", getGoodMapAmount() ); setdvar( "bots_manage_fill", getGoodMapAmount() );
} }
@ -1304,6 +1358,8 @@ addBots_loop()
players = 0; players = 0;
bots = 0; bots = 0;
spec = 0; spec = 0;
axisplayers = 0;
alliesplayers = 0;
playercount = level.players.size; playercount = level.players.size;
@ -1322,37 +1378,6 @@ addBots_loop()
else else
{ {
players++; players++;
}
}
if ( !randomint( 999 ) )
{
setdvar( "testclients_doreload", true );
wait 0.1;
setdvar( "testclients_doreload", false );
doExtraCheck();
}
if ( fillMode == 4 )
{
axisplayers = 0;
alliesplayers = 0;
playercount = level.players.size;
for ( i = 0; i < playercount; i++ )
{
player = level.players[ i ];
if ( player is_bot() )
{
continue;
}
if ( !isdefined( player.pers[ "team" ] ) )
{
continue;
}
if ( player.pers[ "team" ] == "axis" ) if ( player.pers[ "team" ] == "axis" )
{ {
@ -1363,26 +1388,19 @@ addBots_loop()
alliesplayers++; alliesplayers++;
} }
} }
}
result = fillAmount - abs( axisplayers - alliesplayers ) + bots;
if ( getdvarint( "bots_manage_fill_spec" ) )
if ( players == 0 ) {
{ players += spec;
if ( bots < fillAmount ) }
{
result = fillAmount - 1; if ( !randomint( 999 ) )
} {
else if ( bots > fillAmount ) setdvar( "testclients_doreload", true );
{ wait 0.1;
result = fillAmount + 1; setdvar( "testclients_doreload", false );
} doExtraCheck();
else
{
result = fillAmount;
}
}
bots = result;
} }
amount = bots; amount = bots;
@ -1392,22 +1410,46 @@ addBots_loop()
amount += players; amount += players;
} }
if ( getdvarint( "bots_manage_fill_spec" ) ) // use bots as balance
if ( fillMode == 4 || fillMode == 5 )
{ {
amount += spec; diffPlayers = abs( alliesplayers - axisplayers );
amount = fillAmount - ( diffPlayers - bots );
if ( players + diffPlayers < fillAmount )
{
amount = players + bots;
}
}
if ( players <= 0 && getdvarint( "bots_manage_fill_watchplayers" ) )
{
amount = fillAmount + bots;
} }
if ( amount < fillAmount ) if ( amount < fillAmount )
{ {
setdvar( "bots_manage_add", 1 ); setdvar( "bots_manage_add", fillAmount - amount );
} }
else if ( amount > fillAmount && getdvarint( "bots_manage_fill_kick" ) ) else if ( amount > fillAmount && getdvarint( "bots_manage_fill_kick" ) )
{ {
tempBot = getBotToKick(); botsToKick = amount - fillAmount;
if ( isdefined( tempBot ) ) if ( botsToKick > 64 )
{ {
kick( tempBot getentitynumber() ); botsToKick = 64;
}
for ( i = 0; i < botsToKick; i++ )
{
tempBot = getBotToKick();
if ( isdefined( tempBot ) )
{
kick( tempBot getentitynumber(), "EXE_PLAYERKICKED" );
wait 0.25;
}
} }
} }
} }
@ -1552,3 +1594,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" );
}

View File

@ -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
*/ */

View File

@ -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;
} }
} }

View File

@ -2455,7 +2455,7 @@ bot_think_camp_loop()
self SetScriptGoal( campSpot.origin, 16 ); self SetScriptGoal( campSpot.origin, 16 );
time = randomintrange( 10, 20 ); time = randomintrange( 30, 90 );
self BotNotifyBotEvent( "camp", "go", campSpot, time ); self BotNotifyBotEvent( "camp", "go", campSpot, time );
@ -2514,7 +2514,17 @@ killCampAfterTime( time )
self endon( "disconnect" ); self endon( "disconnect" );
self endon( "kill_camp_bot" ); self endon( "kill_camp_bot" );
wait time + 0.05; timeleft = maps\mp\gametypes\_gamelogic::gettimeremaining() / 1000;
while ( time > 0 && timeleft >= 60 )
{
wait 1;
timeleft = maps\mp\gametypes\_gamelogic::gettimeremaining() / 1000;
time--;
}
wait 0.05;
self ClearScriptGoal(); self ClearScriptGoal();
self ClearScriptAimPos(); self ClearScriptAimPos();
@ -5628,27 +5638,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 +5695,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 +5892,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" )
{ {

View File

@ -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();
}

View File

@ -55,6 +55,47 @@ 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;
}
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 +107,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 +135,7 @@ watchDisconnect()
{ {
if ( isdefined( self.menutexty[ i ] ) ) if ( isdefined( self.menutexty[ i ] ) )
{ {
self.menutexty[ i ] destroy(); self.menutexty[ i ] destroyElemFixed();
} }
} }
} }
@ -106,7 +146,7 @@ watchDisconnect()
{ {
if ( isdefined( self.menutext[ i ] ) ) if ( isdefined( self.menutext[ i ] ) )
{ {
self.menutext[ i ] destroy(); self.menutext[ i ] destroyElemFixed();
} }
} }
} }
@ -115,18 +155,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 +372,7 @@ OpenSub( menu, menu2 )
{ {
if ( isdefined( self.menutext[ i ] ) ) if ( isdefined( self.menutext[ i ] ) )
{ {
self.menutext[ i ] destroy(); self.menutext[ i ] destroyElemFixed();
} }
} }
} }
@ -341,18 +381,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 +442,7 @@ OpenSub( menu, menu2 )
{ {
if ( isdefined( self.menutexty[ i ] ) ) if ( isdefined( self.menutexty[ i ] ) )
{ {
self.menutexty[ i ] destroy(); self.menutexty[ i ] destroyElemFixed();
} }
} }
} }
@ -426,11 +466,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 +618,7 @@ ExitSub()
{ {
if ( isdefined( self.menutexty[ i ] ) ) if ( isdefined( self.menutexty[ i ] ) )
{ {
self.menutexty[ i ] destroy(); self.menutexty[ i ] destroyElemFixed();
} }
} }
} }
@ -603,7 +643,7 @@ ExitMenu()
{ {
if ( isdefined( self.menutext[ i ] ) ) if ( isdefined( self.menutext[ i ] ) )
{ {
self.menutext[ i ] destroy(); self.menutext[ i ] destroyElemFixed();
} }
} }
} }
@ -612,18 +652,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;
@ -728,6 +768,10 @@ addOptions()
_temp = "bots used as team balance"; _temp = "bots used as team balance";
break; break;
case 5:
_temp = "bots used as team balance, adjust to map";
break;
default: default:
_temp = "out of range"; _temp = "out of range";
break; break;
@ -1320,6 +1364,11 @@ man_bots( a, b )
self iprintln( "bot_fill will now use bots as team balance." ); self iprintln( "bot_fill will now use bots as team balance." );
break; break;
case 4:
setdvar( "bots_manage_fill_mode", 5 );
self iprintln( "bot_fill will now use bots as team balance, adjusting to map." );
break;
default: default:
setdvar( "bots_manage_fill_mode", 0 ); setdvar( "bots_manage_fill_mode", 0 );
self iprintln( "bot_fill will now count everyone." ); self iprintln( "bot_fill will now count everyone." );

View File

@ -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 )
{ {

View File

@ -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 ] );
}