59 Commits

Author SHA1 Message Date
14b161b3ed version 2.1.0 2022-05-08 22:59:08 -06:00
edd674fdbe bot chatter 2022-05-08 20:23:59 -06:00
4258aa872b Chat events 2022-05-08 19:41:25 -06:00
45e13c60ad use pluto 2022-05-08 18:33:36 -06:00
58fdabc2cf fixed bombs 2022-05-02 15:24:02 -06:00
fa835e7ff1 fix bridge waypoints 2022-04-25 15:38:03 -06:00
11f170073c door hack 2022-04-25 14:15:39 -06:00
257ffd6d61 kneedeep 2022-04-25 11:27:56 -06:00
38eba8089f fixed kneedeep 2022-04-25 11:26:08 -06:00
1e055b5bf5 small fix 2022-04-25 11:21:52 -06:00
4db478c8f1 fix none scr errors 2022-04-25 10:40:14 -06:00
86477e579f pickup 2022-04-24 23:48:26 -06:00
dd635903c6 Prep work for bot chatter 2022-04-20 12:58:29 -06:00
cda591313e Better stuct 2022-04-08 23:48:01 -06:00
d0e67be25a Bot do random actions at objectives 2022-04-08 20:34:14 -06:00
a66e849dfe github supports gsc 2022-03-23 11:50:42 -06:00
07bbe8aade better 2021-12-21 21:51:33 -06:00
e032ecd4c8 fix 2021-11-27 00:06:41 -06:00
5dbfb2f2ad fix 2021-11-16 14:31:13 -06:00
d5cdb98ffb improve 2021-11-16 14:28:21 -06:00
7f9f9d0eb6 Table 2021-09-09 13:01:26 -06:00
4d56d1e77f gitattr and editorconfig 2021-09-09 11:26:20 -06:00
a0d443c295 Add maxclients 2021-09-05 14:59:46 -06:00
d641264cca add name 2021-09-04 23:28:38 -06:00
9b1158341b last 2021-09-04 22:16:01 -06:00
cf034fce87 new config 2021-09-04 21:40:56 -06:00
f438568a70 deploy configs 2021-09-04 21:28:05 -06:00
bcf607e2f3 cleanup 2021-09-04 21:27:26 -06:00
6619087af1 cleanup 2021-09-04 21:26:55 -06:00
5892e46daa Add vscode settings 2021-09-03 11:01:15 -06:00
b6991b3754 Added bot_aim dvar 2021-08-26 10:31:45 -06:00
b877ecffda fix script link error 2021-08-25 13:02:32 -06:00
4cdde8e7a5 Fix bots class selecting 2021-08-25 12:48:07 -06:00
0884902695 improved cap capflag 2021-08-25 11:01:58 -06:00
bdea53b670 sprint improvements 2021-07-29 13:45:54 -06:00
8f5f1e0572 small fix 2021-07-25 21:56:52 -06:00
d90a1a29b8 needs 4 params 2021-07-13 19:23:51 -06:00
cf377c976e target glass 2021-07-13 19:01:29 -06:00
a4819bacf4 Format scripts 2021-06-18 15:12:00 -06:00
ed8fd1db01 Add deploy and astylerc 2021-06-18 15:02:14 -06:00
a11119abe3 abstract class choice 2021-06-14 13:20:39 -06:00
26e0344a56 More sprint 2021-06-13 19:12:22 -06:00
10576118ee Improved bot sight 2021-06-13 14:16:39 -06:00
2e10706c4c fun 2021-06-04 19:08:19 -06:00
7d8ed25cdc Reduce var usage 2021-06-04 14:13:52 -06:00
831a63032b weap changes 2021-06-02 10:32:05 -06:00
95755e1749 prevent stuck 2021-05-27 14:18:27 -06:00
30eae3d3d9 greatly reduce var usage 2021-05-26 22:25:05 -06:00
bb74baec06 update wps 2021-05-26 22:24:58 -06:00
cc9c873ce7 Reduce var usage by removing kdtree 2021-05-26 18:54:57 -06:00
fb6daae114 Some fix ups 2021-05-26 12:56:06 -06:00
d435111091 Fix runtime error 2021-05-23 13:34:09 -06:00
417faa0353 Added low mem mode 2021-05-19 20:12:53 -06:00
65eaedd9d4 Oops 2021-05-19 15:47:24 -06:00
8d108b0fc5 Improved bot aimming 2021-05-19 15:44:50 -06:00
e3253d291a Improved bots mantling 2021-05-19 15:40:19 -06:00
ea26141601 Fix possible runtime error 2021-05-18 15:01:02 -06:00
84768fce13 no image 2021-05-16 09:54:01 -06:00
2e145d7093 Add wpedit md 2021-05-16 09:49:57 -06:00
38 changed files with 18659 additions and 6759 deletions

21
.astylerc Normal file
View File

@ -0,0 +1,21 @@
# try to mimic the original gsc provided
mode=c
style=allman
indent=tab
lineend=windows
pad-oper
pad-paren-in
pad-header
# delete-empty-lines
break-blocks
# remove-braces
indent-switches
indent-cases
indent-after-parens
remove-comment-prefix

11
.editorconfig Normal file
View File

@ -0,0 +1,11 @@
root = true
[*]
indent_style = tab
indent_size = 2
charset = latin1
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

13
.gitignore vendored
View File

@ -3,18 +3,21 @@
# Files to not ignore # Files to not ignore
!/.gitignore !/.gitignore
!/.vscode
!/.editorconfig
!/.gitattributes
!/z_client.bat
!/z_dev.bat
!/z_devserver.bat
!/z_server.bat !/z_server.bat
!/z_serverdev.bat
!/z_bots.bat
!/README.md !/README.md
!/out !/out
*.zip *.zip
!/.astylerc
!/z_deploy.bat
!/deploy.bat
!/deploy.js
!/main/ !/main/
!/main_shared/ !/main_shared/
/main/* /main/*

15
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,15 @@
{
"astyle.astylerc": "${workspaceRoot}/.astylerc",
"astyle.additional_languages": [
"gsc"
],
"[gsc]": {
"editor.defaultFormatter": "chiehyu.vscode-astyle",
},
"editor.quickSuggestions": {
"other": true,
"comments": true,
"strings": true
},
"vscode-codscript.use_builtin_completionItems": false
}

149
README.md
View File

@ -1,7 +1,7 @@
![GitHub Logo](/main_shared/bw-assets/bw-logo.png) ![GitHub Logo](/main_shared/bw-assets/bw-logo.png)
# T4M Bot Warfare # T4M Bot Warfare
Bot Warfare is a GSC mod for the [T4M project](https://github.com/ineedbots/T4M). Bot Warfare is a GSC mod for the [T4M project](https://github.com/ineedbots/T4M) and [PlutoniumT4 project](https://plutonium.pw/).
It aims to add playable AI to the multiplayer games of World at War. It aims to add playable AI to the multiplayer games of World at War.
@ -22,7 +22,7 @@ Make sure to disable this DVAR by adding ```set bots_main_firstIsHost 0``` in yo
- [Credits](#Credits) - [Credits](#Credits)
## Features ## Features
- A Waypoint Editor for creating and modifying bot's waypoints of traversing the map. Have a look at [Using the Waypoint editor](). - A Waypoint Editor for creating and modifying bot's waypoints of traversing the map. Have a look at [Using the Waypoint editor](/main_shared/bw-assets/wpedit.md).
- A clean and nice menu, you can edit every bot DVAR within in-game. - A clean and nice menu, you can edit every bot DVAR within in-game.
@ -57,14 +57,7 @@ Make sure to disable this DVAR by adding ```set bots_main_firstIsHost 0``` in yo
- ... And pretty much everything you expect a Combat Training bot to have - ... And pretty much everything you expect a Combat Training bot to have
## Installation ## Installation
T4M requires an unpacked steamless version of the multiplayer World at War executable (otherwise known as LanFixed). You can use a [Steam Unpacker](https://github.com/atom0s/Steamless) on your multiplayer World at War Steam executable to acquire the required executable. 0. Make sure that [Plutonium T4](https://plutonium.pw/docs/install/) is installed, updated and working properly.
Also make sure that PunkBuster is disabled!
![Disabling PunkBuster](/main_shared/bw-assets/disable_pb.png)
0. Make sure that [T4M](https://github.com/ineedbots/T4M) is installed, updated and working properly.
- Download the [d3d9.dll](https://github.com/ineedbots/T4M/releases) and place it into the root of your World at War install
- Download the [WaW MP LanFixed](https://bit.ly/3803IUC) and place it into the root of your World at War install, you will use this executable to run the game.
- Download the [latest release](https://github.com/ineedbots/t4m_bot_warfare/releases) of Bot Warfare. - Download the [latest release](https://github.com/ineedbots/t4m_bot_warfare/releases) of Bot Warfare.
1. Extract all the files from the Bot Warfare release archive you downloaded to anywhere on your computer. 1. Extract all the files from the Bot Warfare release archive you downloaded to anywhere on your computer.
2. Run the 'install.bat'. This copies the mod to your WaW mods folder. 2. Run the 'install.bat'. This copies the mod to your WaW mods folder.
@ -83,90 +76,60 @@ Also make sure that PunkBuster is disabled!
- Pressing the menu buttons again closes menus. - Pressing the menu buttons again closes menus.
### DVARs ### DVARs
- bots_manage_add - an integer amount of bots to add to the game, resets to 0 once the bots have been added. | Dvar | Description | Default Value |
- for example: 'bots_manage_add 10' will add 10 bots to the game. |----------------------------------|---------------------------------------------------------------------------------------------|--------------:|
| bots_main | Enable this mod. | true |
- bots_manage_fill - an integer amount of players/bots (depends on bots_manage_fill_mode) to retain on the server, it will automatically add bots to fill player space. | bots_main_firstIsHost | The first player to connect will be given host. | true |
- for example: 'bots_manage_fill 10' will have the server retain 10 players in the server, if there are less than 10, it will add bots until that value is reached. | 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_manage_fill_mode - a value to indicate if the server should consider only bots or players and bots when filling player space. | bots_main_menu | Enable the in-game menu for hosts. | true |
- 0 will consider both players and bots. | bots_main_debug | Enable the in-game waypoint editor. | false |
- 1 will only consider bots. | bots_main_kickBotsAtEnd | Kick the bots at the end of a match. | false |
| bots_main_chat | The rate bots will chat at, set to 0 to disable. | 1.0 |
- bots_manage_fill_kick - a boolean value (0 or 1), whether or not if the server should kick bots if the amount of players/bots (depends on bots_manage_fill_mode) exceeds the value of bots_manage_fill. | 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_spec - a boolean value (0 or 1), whether or not if the server should consider players who are on the spectator team when filling player space. | 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_kick | If the amount of players/bots in the match exceeds `bots_manage_fill`, kick bots until no longer exceeds. | false |
--- | bots_manage_fill_spec | If when counting players for `bots_manage_fill` should include spectators. | true |
| bots_team | One of `autoassign`, `allies`, `axis`, `spectator`, or `custom`. What team the bots should be on. | autoassign |
- bots_team - a string, the value indicates what team the bots should join: | 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 |
- 'autoassign' will have bots balance the teams | 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`. | false |
- 'allies' will have the bots join the allies team | 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 |
- 'axis' will have the bots join the axis team | 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 |
- 'custom' will have bots_team_amount bots on the axis team, the rest will be on the allies team | 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_team_amount - an integer amount of bots to have on the axis team if bots_team is set to 'custom', the rest of the bots will be placed on the allies team. | bots_skill_allies_hard | When `bots_skill` is set to `8`, the amount of hard difficulty bots to set on the allies team. | 0 |
- for example: there are 5 bots on the server and 'bots_team_amount 3', then 3 bots will be placed on the axis team, the other 2 will be placed on the allies team. | bots_skill_allies_med | When `bots_skill` is set to `8`, the amount of medium difficulty bots to set on the allies team. The remaining bots on the team will be set to easy difficulty. | 0 |
| bots_skill_min | The minimum difficulty level for the bots. | 1 |
- bots_team_force - a boolean value (0 or 1), whether or not if the server should enforce periodically the bot's team instead of just a single team when the bot is added to the game. | bots_skill_max | The maximum difficulty level for the bots. | 7 |
- for example: 'bots_team_force 1' and 'bots_team autoassign' and the teams become to far unbalanced, then the server will change a bot's team to make it balanced again. | bots_loadout_reasonable | If the bots should filter bad performing create-a-class selections. | false |
| bots_loadout_allow_op | If the bots should be able to use overpowered and annoying create-a-class selections. | true |
- bots_team_mode - a value to indicate if the server should consider only bots or players and bots when counting players on the teams. | bots_loadout_rank | What rank to set the bots.<ul><li>`-1` - Average of all players in the match.</li><li>`0` - All random.</li><li>`1` or higher - Sets the bots' rank to this.</li></ul> | -1 |
- 0 will consider both players and bots. | bots_loadout_prestige | What prestige to set the bots.<ul><li>`-1` - Same as host player in the match.</li><li>`-2` - All random.</li><li>`0` or higher - Sets the bots' prestige to this.</li></ul> | -1 |
- 1 will only consider bots. | bots_play_move | If the bots can move. | true |
| bots_play_knife | If the bots can knife. | true |
--- | bots_play_fire | If the bots can fire. | true |
| bots_play_nade | If the bots can grenade. | true |
- bots_skill - value to indicate how difficult the bots should be. | bots_play_obj | If the bots can play the objective. | true |
- 0 will be mixed difficultly | bots_play_camp | If the bots can camp. | true |
- 1 will be the most easy | bots_play_jumpdrop | If the bots can jump/drop shot. | true |
- 2-6 will be in between most easy and most hard | bots_play_target_other | If the bots can target other entities other than players. | true |
- 7 will be the most hard. | bots_play_killstreak | If the bots can call in killstreaks. | true |
- 8 will be custom. | bots_play_ads | If the bots can aim down sights. | true |
| bots_play_aim | If the bots can aim. | true |
- bots_skill_axis_hard - an integer amount of hard bots on the axis team.
- bots_skill_axis_med - an integer amount of medium bots on the axis team.
- bots_skill_allies_hard - an integer amount of hard bots on the allies team.
- bots_skill_allies_med - an integer amount of medium bots on the allies team
- if bots_skill is 8 (custom). The remaining bots on the team will become easy bots
- for example: having 5 bots on the allies team, 'bots_skill_allies_hard 2' and 'bots_skill_allies_med 2' will have 2 hard bots, 2 medium bots, and 1 easy bot on the allies team.
---
- bots_loadout_reasonable - a boolean value (0 or 1), whether or not if the bots should filter out bad create a class selections
- bots_loadout_allow_op - a boolean value (0 or 1), whether or not if the bots are allowed to use jug, marty, etc.
- bots_loadout_rank - an integer number, bots will be around this rank, -1 is average of all players in game, 0 is all random
- bots_loadout_prestige - an integer number, bots will be this prestige, -1 is the same as player, -2 is all random
- bots_play_move - a boolean value (0 or 1), whether or not if the bots will move
- bots_play_knife - a boolean value (0 or 1), whether or not if the bots will use the knife
- bots_play_fire - a boolean value (0 or 1), whether or not if the bots will fire their weapons
- bots_play_nade - a boolean value (0 or 1), whether or not if the bots will grenade
- bots_play_obj - a boolean value (0 or 1), whether or not if the bots will play the objective
- bots_play_camp - a boolean value (0 or 1), whether or not if the bots will camp
- bots_play_jumpdrop - a boolean value (0 or 1), whether or not if the bots will jump shot or drop shot
- bots_play_target_other - a boolean value (0 or 1), whether or not if the bots will target claymores, killstreaks, etc.
- bots_play_killstreak - a boolean value (0 or 1), whether or not if the bots will use killstreaks
- bots_play_ads - a boolean value (0 or 1), whether or not if the bots will ads
---
- bots_main - a boolean value (0 or 1), enables or disables the mod
- bots_main_firstIsHost - a boolean value (0 or 1), the first player to connect is considered a host
- bots_main_GUIDs - a list of GUIDs (comma seperated) of players who will be considered a host
- bots_main_waitForHostTime - a float value, how long in seconds to wait for the host player to connect before adding in bots
- bots_main_menu - a boolean value (0 or 1), enables or disables the menu
- bots_main_debug - a boolean value (0 or 1), enables or disables the waypoint editor
## Changelog ## Changelog
- v2.1.0
- Bot chatter system, bots_main_chat
- Greatly reduce script variable usage
- Improved bots mantling and stuck
- Fix some runtime errors
- Bots sprint more
- Improved bots sight on enemies
- Bots do random actions while waiting at an objective
- Improved bots from getting stuck
- Better bot difficulty management, bots_skill_min and bots_skill_max
- v2.0.1 - v2.0.1
- Reduced bots crouching - Reduced bots crouching
- Increased bots sprinting - Increased bots sprinting
@ -188,7 +151,7 @@ Also make sure that PunkBuster is disabled!
## Credits ## Credits
- iAmThatMichael - https://github.com/iAmThatMichael/T4M - iAmThatMichael - https://github.com/iAmThatMichael/T4M
- INeedGames(me) - http://www.moddb.com/mods/bot-warfare - INeedGames - http://www.moddb.com/mods/bot-warfare
- PeZBot team - http://www.moddb.com/mods/pezbot - PeZBot team - http://www.moddb.com/mods/pezbot
- Ability - Ability
- Salvation - Salvation

4
deploy.bat Normal file
View File

@ -0,0 +1,4 @@
xcopy t4m_bot_warfare\main_shared\maps main_shared\maps\ /Y /I /E /H /C
xcopy t4m_bot_warfare\main_shared\waypoints main_shared\waypoints\ /Y /I /E /H /C
xcopy t4m_bot_warfare\main main\ /Y /I /E /H /C
xcopy t4m_bot_warfare\main_shared\bots.txt main_shared\ /Y /I /H /C

54
deploy.js Normal file
View File

@ -0,0 +1,54 @@
// nodejs 14+
const exec = require('util').promisify(require('child_process').exec)
const repo_name = 't4m_bot_warfare'
const repo_url = `https://github.com/ineedbots/${repo_name}`
const deploy_check_rate = 60000
const title = 'T4M Bot Warfare Git Deployer'
function printToConsole(what, error = false)
{
log = error ? console.error : console.log
log(`[${new Date().toISOString()}]:`, what)
}
async function doDeploy() {
try {
const { stdout, stderr } = await exec(`cd ${repo_name} && git fetch`)
if (stderr.length <= 0)
return
if (stderr.startsWith('From '))
{
printToConsole('git fetched! Pulling...')
await exec(`cd ${repo_name} && git pull && git submodule update --init --recursive`)
printToConsole('Deploying...')
await exec('deploy.bat')
printToConsole('Deployed!')
}
} catch (e) {
printToConsole(e, true)
if (!e.stderr.startsWith('The system cannot find the path specified'))
return
printToConsole('Cloning repo...')
try {
await exec(`git clone ${repo_url} && cd ${repo_name} && git submodule update --init --recursive`)
printToConsole('Cloned!')
printToConsole('Deploying...')
await exec('deploy.bat')
printToConsole('Deployed!')
} catch (f) {
printToConsole(f, true)
}
}
}
process.stdout.write(`${String.fromCharCode(27)}]0;${title}${String.fromCharCode(7)}`)
doDeploy()
setInterval(doDeploy, deploy_check_rate)

View File

@ -2,7 +2,7 @@
// Color Codes // Color Codes
//****************************************************************************** //******************************************************************************
// Colors for text. Do not clear the comment in front of the color codes. // Colors for text. Do not clear the comment in front of the color codes.
// Useful for your server name, motd msg's - Information and ref use only // Useful for your server name, motd msgs - Information and ref use only
// //
// ^1 = Red // ^1 = Red
// ^2 = Green // ^2 = Green
@ -26,11 +26,12 @@ sets _modver ""
sets _modupdate "" sets _modupdate ""
set scr_motd "^1Bot ^3War^5fare" set scr_motd "^1Bot ^3War^5fare"
set sv_maxclients "64"
//****************************************************************************** //******************************************************************************
// Common Server Settings // Common Server Settings
//****************************************************************************** //******************************************************************************
// Password Settings // Password Settings
set rcon_password "qazqaz"
set sv_privatepassword "" set sv_privatepassword ""
set g_password "" set g_password ""
set scr_xpscale_ "10" set scr_xpscale_ "10"
@ -250,7 +251,7 @@ set sv_maprotation "gametype dom map mp_dome"
// Additional DVAR's // Additional DVAR's
//****************************************************************************** //******************************************************************************
// There are simply too many DVAR's for AGrcon to explicitly list and index // There are simply too many DVAR's for AGrcon to explicitly list and index
// for you. All additional DVAR's (such as weapon configs and player configs) are // for you. All additional DVARs (such as weapon configs and player configs) are
// listed below. // listed below.
// WEAPONS / ATTACHMENTS // WEAPONS / ATTACHMENTS

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@ -0,0 +1,96 @@
# T4M Bot Warfare Waypoint Editor
First things first, Bot Warfare uses the [AStar search algorithm](https://en.wikipedia.org/wiki/A*_search_algorithm) for creating paths for the bots to find their way through a map.
The AStar search algorithm requires a [set of waypoints](https://en.wikipedia.org/wiki/Graph_(discrete_mathematics)) defining where all the paths are in the map.
Now if you want to modify existing or create new waypoints for World at War maps, this is the read for you.
## Contents
- [Setting up the Waypoint Editor](#Setting-up-the-Waypoint-Editor)
- [The Editor](#The-Editor)
## Setting up the Waypoint Editor
The Bot Warfare mod comes with the Waypoint Editor out of the box, so its just a matter of telling the mod you want to use it. Its a matter of setting the `bots_main_debug` DVAR to `1`.
Start your game, and load up the Bot Warfare mod. Now open your console with tilde(~).
In the console, type in ```set bots_main_debug 1```.<br>
![Setting the dvar](/main_shared/bw-assets/console.png)
Now start a match with the map you want to edit.
It should be noted that waypoints load in this following order;
1. checks the 'waypoints' folder (FS_Game\waypoints) for a csv file
2. loads the waypoints from GSC (maps\mp\bots\waypoints)
3. checks online at [this repo](https://github.com/ineedbots/t4m_waypoints) for the waypoints
If all fail to load waypoints, there will be no waypoints and the bots will not know how to navigate the map.
## The Editor
![The editor](/main_shared/bw-assets/editor.png)<br>
This is the Waypoint Editor. You can view, edit and create the waypoint graph.
- Each red number you see in the world is a waypoint.
- The green string you see is the type of that waypoint.
- The green list of numbers are the waypoints linked to that waypoint.
- The pink lines show the links between the waypoints, a link defines that a bot can walk from A to B.
- The white lines show the 'angles' that a waypoint has, these are used for grenade, betty and tube waypoints. It's used to tell the bot where to look at when grenading/betty, etc.
---
Pressing any of these buttons will initiate a command to the Waypoint Editor.
Each button has a secondary modifier button, and can be pressed shortly after pressing the primary button.
- SecondaryOffhand (stun) - Add Waypoint
- Press nothing - Make a waypoint of your stance
- ADS - Make a climb waypoint
- Attack + Use - Make a tube waypoint
- Attack - Make a grenade waypoint
- Use - Make a claymore waypoint
- Melee - Link Waypoint
- Press nothing - Link
- ADS - Unlink
- FragButton (grenade) - Delete Waypoint
- Press nothing - Delete Waypoint
- Attack - Delete all waypoints
- ADS - (Re)Load Waypoints
- UseButton + Attack - Save Waypoints
- Press nothing - Save waypoints
- ADS - Toggle autolink waypoints (links waypoints as you create them)
---
Okay, now that you know how to control the Editor, lets now go ahead and create some waypoints.
Here I added a waypoint.<br>
![Adding a waypoint](/main_shared/bw-assets/editor-addwp.png)
And I added a second waypoint.<br>
![Adding another waypoint](/main_shared/bw-assets/editor-addwp2.png)
There are several types of waypoints, holding a modifier button before pressing the add waypoint button will create a special type of waypoint.
- Types of waypoints:
- any stance ('stand', 'crouch', 'prone') - bots will have this stance upon reaching this waypoint
- grenade - bots will look at the angles you were looking at when you made the waypoint and throw a grenade from the waypoint
- tube - bots will look at the angles you were looking at when you made the waypoint and switch to a launcher and fire
- claymore - bots will look at the angles you were looking at when you made the waypoint and place a betty or a charge
- camp ('crouch' waypoint with only one linked waypoint) - bots will look at the angles you were looking at when you made the waypoint and camp
- climb - bots will look at the angles you were looking at when you made the waypoint and climb (use this for ladders and mantles)
Here I linked the two waypoints together.<br>
![Linking waypoints](/main_shared/bw-assets/editor-link.png)
Linking waypoints are very important, it tells the bots that they can reach waypoint 1 from waypoint 0, and vice versa.
Now go and waypoint the whole map out. This may take awhile and can be pretty tedious.
Once you feel like you are done, press the Save buttons. This will generate a [CSV](https://en.wikipedia.org/wiki/Comma-separated_values) output to your waypoints folder!
That is it! The waypoints should load next time you start your game!
Your waypoints CSV file will be located at ```<fs_game>/waypoints/<mapname>_wp.csv```. (main folder if fs_game is blank)<br>
![Location](/main_shared/bw-assets/saved.png)
You can share your waypoints publicly (and can be loaded by other users of Bot Warfare remotely) by making a Pull Request to the [T4M_Waypoints repo](https://github.com/ineedbots/t4m_waypoints).

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -10,35 +10,35 @@
/* /*
Will attempt to retreive waypoints from the internet Will attempt to retreive waypoints from the internet
*/ */
getRemoteWaypoints(mapname) getRemoteWaypoints( mapname )
{ {
url = "https://raw.githubusercontent.com/ineedbots/t4m_waypoints/master/" + mapname + "_wp.csv"; url = "https://raw.githubusercontent.com/ineedbots/t4m_waypoints/master/" + mapname + "_wp.csv";
filename = "waypoints/" + mapname + "_wp.csv"; filename = "waypoints/" + mapname + "_wp.csv";
PrintConsole("Attempting to get remote waypoints from " + url + "\n"); PrintConsole( "Attempting to get remote waypoints from " + url + "\n" );
res = getLinesFromUrl(url, filename); res = getLinesFromUrl( url, filename );
if (!res.lines.size) if ( !res.lines.size )
return; return;
waypointCount = int(res.lines[0]); waypointCount = int( res.lines[0] );
waypoints = []; waypoints = [];
PrintConsole("Loading remote waypoints...\n"); PrintConsole( "Loading remote waypoints...\n" );
for (i = 1; i <= waypointCount; i++) for ( i = 1; i <= waypointCount; i++ )
{ {
tokens = tokenizeLine(res.lines[i], ","); tokens = tokenizeLine( res.lines[i], "," );
waypoint = parseTokensIntoWaypoint(tokens); waypoint = parseTokensIntoWaypoint( tokens );
waypoints[i-1] = waypoint; waypoints[i - 1] = waypoint;
} }
if (waypoints.size) if ( waypoints.size )
{ {
level.waypoints = waypoints; level.waypoints = waypoints;
PrintConsole("Loaded " + waypoints.size + " waypoints from remote.\n"); PrintConsole( "Loaded " + waypoints.size + " waypoints from remote.\n" );
} }
} }
@ -49,20 +49,20 @@ doVersionCheck()
{ {
remoteVersion = getRemoteVersion(); remoteVersion = getRemoteVersion();
if (!isDefined(remoteVersion)) if ( !isDefined( remoteVersion ) )
{ {
PrintConsole("Error getting remote version of Bot Warfare.\n"); PrintConsole( "Error getting remote version of Bot Warfare.\n" );
return false; return false;
} }
if (level.bw_VERSION != remoteVersion) if ( level.bw_VERSION != remoteVersion )
{ {
PrintConsole("There is a new version of Bot Warfare!\n"); PrintConsole( "There is a new version of Bot Warfare!\n" );
PrintConsole("You are on version " + level.bw_VERSION + " but " + remoteVersion + " is available!\n"); PrintConsole( "You are on version " + level.bw_VERSION + " but " + remoteVersion + " is available!\n" );
return false; return false;
} }
PrintConsole("You are on the latest version of Bot Warfare!\n"); PrintConsole( "You are on the latest version of Bot Warfare!\n" );
return true; return true;
} }
@ -73,33 +73,34 @@ getRemoteVersion()
{ {
data = httpGet( "https://raw.githubusercontent.com/ineedbots/t4m_waypoints/master/version.txt" ); data = httpGet( "https://raw.githubusercontent.com/ineedbots/t4m_waypoints/master/version.txt" );
if (!isDefined(data)) if ( !isDefined( data ) )
return undefined; return undefined;
return strtok(data, "\n")[0]; return strtok( data, "\n" )[0];
} }
/* /*
Returns an array of each line from the response of the http url request Returns an array of each line from the response of the http url request
*/ */
getLinesFromUrl(url, filename) getLinesFromUrl( url, filename )
{ {
result = spawnStruct(); result = spawnStruct();
result.lines = []; result.lines = [];
data = HTTPGet(url); data = HTTPGet( url );
if (!isDefined(data)) if ( !isDefined( data ) )
return result; return result;
fileWrite(filename, data, "write"); fileWrite( filename, data, "write" );
line = ""; line = "";
for (i=0;i<data.size;i++)
for ( i = 0; i < data.size; i++ )
{ {
c = data[i]; c = data[i];
if (c == "\n") if ( c == "\n" )
{ {
result.lines[result.lines.size] = line; result.lines[result.lines.size] = line;
@ -109,6 +110,7 @@ getLinesFromUrl(url, filename)
line += c; line += c;
} }
result.lines[result.lines.size] = line; result.lines[result.lines.size] = line;
return result; return result;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -12,68 +12,69 @@
init() init()
{ {
if(getDvar("bots_main_debug") == "") if ( getDvar( "bots_main_debug" ) == "" )
setDvar("bots_main_debug", 0); setDvar( "bots_main_debug", 0 );
if(!getDVarint("bots_main_debug")) if ( !getDVarint( "bots_main_debug" ) )
return; return;
if(!getDVarint("developer")) if ( !getDVarint( "developer" ) )
{ {
setdvar("developer_script", 1); setdvar( "developer_script", 1 );
setdvar("developer", 1); setdvar( "developer", 1 );
setdvar("sv_mapRotation", "map "+getDvar("mapname")); setdvar( "sv_mapRotation", "map " + getDvar( "mapname" ) );
exitLevel(false); exitLevel( false );
} }
setDvar("bots_main", 0); setDvar( "bots_main", 0 );
setdvar("bots_main_menu", 0); setdvar( "bots_main_menu", 0 );
setdvar("bots_manage_fill_mode", 0); setdvar( "bots_manage_fill_mode", 0 );
setdvar("bots_manage_fill", 0); setdvar( "bots_manage_fill", 0 );
setdvar("bots_manage_add", 0); setdvar( "bots_manage_add", 0 );
setdvar("bots_manage_fill_kick", 1); setdvar( "bots_manage_fill_kick", 1 );
setDvar("bots_manage_fill_spec", 1); setDvar( "bots_manage_fill_spec", 1 );
if (getDvar("bots_main_debug_distance") == "") if ( getDvar( "bots_main_debug_distance" ) == "" )
setDvar("bots_main_debug_distance", 512.0); setDvar( "bots_main_debug_distance", 512.0 );
if (getDvar("bots_main_debug_cone") == "") if ( getDvar( "bots_main_debug_cone" ) == "" )
setDvar("bots_main_debug_cone", 0.65); setDvar( "bots_main_debug_cone", 0.65 );
if (getDvar("bots_main_debug_minDist") == "") if ( getDvar( "bots_main_debug_minDist" ) == "" )
setDvar("bots_main_debug_minDist", 32.0); setDvar( "bots_main_debug_minDist", 32.0 );
if (getDvar("bots_main_debug_drawThrough") == "") if ( getDvar( "bots_main_debug_drawThrough" ) == "" )
setDvar("bots_main_debug_drawThrough", false); setDvar( "bots_main_debug_drawThrough", false );
if(getDvar("bots_main_debug_commandWait") == "") if ( getDvar( "bots_main_debug_commandWait" ) == "" )
setDvar("bots_main_debug_commandWait", 0.5); setDvar( "bots_main_debug_commandWait", 0.5 );
setDvar("player_sustainAmmo", 1); setDvar( "player_sustainAmmo", 1 );
level.waypoints = []; level.waypoints = [];
level.waypointCount = 0; level.waypointCount = 0;
level waittill( "connected", player); level waittill( "connected", player );
player thread onPlayerSpawned(); player thread onPlayerSpawned();
} }
onPlayerSpawned() onPlayerSpawned()
{ {
self endon("disconnect"); self endon( "disconnect" );
for(;;)
for ( ;; )
{ {
self waittill("spawned_player"); self waittill( "spawned_player" );
self thread beginDebug(); self thread beginDebug();
} }
} }
beginDebug() beginDebug()
{ {
self endon("disconnect"); self endon( "disconnect" );
self endon("death"); self endon( "death" );
level.wpToLink = -1; level.wpToLink = -1;
level.autoLink = false; level.autoLink = false;
@ -83,10 +84,10 @@ beginDebug()
self clearPerks(); self clearPerks();
self takeAllWeapons(); self takeAllWeapons();
self.specialty = []; self.specialty = [];
self giveWeapon("m1garand_gl_mp"); self giveWeapon( "m1garand_gl_mp" );
self SetActionSlot( 3, "altMode" ); self SetActionSlot( 3, "altMode" );
self giveWeapon("frag_grenade_mp"); self giveWeapon( "frag_grenade_mp" );
self freezecontrols(false); self freezecontrols( false );
self thread debug(); self thread debug();
self thread addWaypoints(); self thread addWaypoints();
@ -95,245 +96,256 @@ beginDebug()
self thread watchSaveWaypointsCommand(); self thread watchSaveWaypointsCommand();
self thread sayExtras(); self thread sayExtras();
self thread textScroll("^1SecondaryOffhand - ^2Add Waypoint; ^3MeleeButton - ^4Link Waypoint; ^5FragButton - ^6Delete Waypoint; ^7UseButton + AttackButton - ^8Save"); self thread textScroll( "^1SecondaryOffhand - ^2Add Waypoint; ^3MeleeButton - ^4Link Waypoint; ^5FragButton - ^6Delete Waypoint; ^7UseButton + AttackButton - ^8Save" );
} }
sayExtras() sayExtras()
{ {
self endon("disconnect"); self endon( "disconnect" );
self endon("death"); self endon( "death" );
self iprintln("Making a crouch waypoint with only one link..."); self iprintln( "Making a crouch waypoint with only one link..." );
self iprintln("Makes a camping waypoint."); self iprintln( "Makes a camping waypoint." );
} }
debug() debug()
{ {
self endon("disconnect"); self endon( "disconnect" );
self endon("death"); self endon( "death" );
for(;;) for ( ;; )
{ {
wait 0.05; wait 0.05;
if(isDefined(self.command)) if ( isDefined( self.command ) )
continue; continue;
closest = -1; closest = -1;
myEye = self getTagOrigin( "j_head" ); myEye = self getTagOrigin( "j_head" );
myAngles = self GetPlayerAngles(); myAngles = self GetPlayerAngles();
for(i = 0; i < level.waypointCount; i++) for ( i = 0; i < level.waypointCount; i++ )
{ {
if(closest == -1 || closer(self.origin, level.waypoints[i].origin, level.waypoints[closest].origin)) if ( closest == -1 || closer( self.origin, level.waypoints[i].origin, level.waypoints[closest].origin ) )
closest = i; closest = i;
wpOrg = level.waypoints[i].origin + (0, 0, 25); wpOrg = level.waypoints[i].origin + ( 0, 0, 25 );
if(distance(level.waypoints[i].origin, self.origin) < getDvarFloat("bots_main_debug_distance") && (bulletTracePassed(myEye, wpOrg, false, self) || getDVarint("bots_main_debug_drawThrough"))) if ( distance( level.waypoints[i].origin, self.origin ) < getDvarFloat( "bots_main_debug_distance" ) && ( bulletTracePassed( myEye, wpOrg, false, self ) || getDVarint( "bots_main_debug_drawThrough" ) ) )
{ {
for(h = 0; h < level.waypoints[i].childCount; h++) for ( h = level.waypoints[i].children.size - 1; h >= 0; h-- )
line(wpOrg, level.waypoints[level.waypoints[i].children[h]].origin + (0, 0, 25), (1,0,1)); line( wpOrg, level.waypoints[level.waypoints[i].children[h]].origin + ( 0, 0, 25 ), ( 1, 0, 1 ) );
if(getConeDot(wpOrg, myEye, myAngles) > getDvarFloat("bots_main_debug_cone")) if ( getConeDot( wpOrg, myEye, myAngles ) > getDvarFloat( "bots_main_debug_cone" ) )
print3d(wpOrg, i, (1,0,0), 2); print3d( wpOrg, i, ( 1, 0, 0 ), 2 );
if (isDefined(level.waypoints[i].angles) && level.waypoints[i].type != "stand") if ( isDefined( level.waypoints[i].angles ) && level.waypoints[i].type != "stand" )
line(wpOrg, wpOrg + AnglesToForward(level.waypoints[i].angles) * 64, (1,1,1)); line( wpOrg, wpOrg + AnglesToForward( level.waypoints[i].angles ) * 64, ( 1, 1, 1 ) );
} }
} }
self.closest = closest; self.closest = closest;
if(closest != -1) if ( closest != -1 )
{ {
stringChildren = ""; stringChildren = "";
for(i = 0; i < level.waypoints[closest].childCount; i++)
for ( i = 0; i < level.waypoints[closest].children.size; i++ )
{ {
if(i != 0) if ( i != 0 )
stringChildren = stringChildren + "," + level.waypoints[closest].children[i]; stringChildren = stringChildren + "," + level.waypoints[closest].children[i];
else else
stringChildren = stringChildren + level.waypoints[closest].children[i]; stringChildren = stringChildren + level.waypoints[closest].children[i];
} }
print3d(level.waypoints[closest].origin + (0, 0, 35), stringChildren, (0,1,0), 2);
print3d(level.waypoints[closest].origin + (0, 0, 15), level.waypoints[closest].type, (0,1,0), 2); print3d( level.waypoints[closest].origin + ( 0, 0, 35 ), stringChildren, ( 0, 1, 0 ), 2 );
print3d( level.waypoints[closest].origin + ( 0, 0, 15 ), level.waypoints[closest].type, ( 0, 1, 0 ), 2 );
} }
} }
} }
AddWaypoints() AddWaypoints()
{ {
self endon("disconnect"); self endon( "disconnect" );
self endon("death"); self endon( "death" );
for(;;)
for ( ;; )
{ {
while(!self SecondaryOffhandButtonPressed() || isDefined(self.command)) while ( !self SecondaryOffhandButtonPressed() || isDefined( self.command ) )
wait 0.05; wait 0.05;
pos = self getOrigin(); pos = self getOrigin();
self.command = true; self.command = true;
self iprintln("Adding a waypoint..."); self iprintln( "Adding a waypoint..." );
self iprintln("ADS - climb; Attack + Use - tube"); self iprintln( "ADS - climb; Attack + Use - tube" );
self iprintln("Attack - grenade; Use - claymore"); self iprintln( "Attack - grenade; Use - claymore" );
self iprintln("Else(wait) - your stance"); self iprintln( "Else(wait) - your stance" );
wait getDvarFloat("bots_main_debug_commandWait"); wait getDvarFloat( "bots_main_debug_commandWait" );
self addWaypoint(pos); self addWaypoint( pos );
self.command = undefined; self.command = undefined;
while(self SecondaryOffhandButtonPressed()) while ( self SecondaryOffhandButtonPressed() )
wait 0.05; wait 0.05;
} }
} }
linkWaypoints() linkWaypoints()
{ {
self endon("disconnect"); self endon( "disconnect" );
self endon("death"); self endon( "death" );
for(;;)
for ( ;; )
{ {
while(!self MeleeButtonPressed() || isDefined(self.command)) while ( !self MeleeButtonPressed() || isDefined( self.command ) )
wait 0.05; wait 0.05;
self.command = true; self.command = true;
self iprintln("ADS - Unlink; Else(wait) - Link"); self iprintln( "ADS - Unlink; Else(wait) - Link" );
wait getDvarFloat("bots_main_debug_commandWait"); wait getDvarFloat( "bots_main_debug_commandWait" );
if(!self adsButtonPressed()) if ( !self adsButtonPressed() )
self LinkWaypoint(self.closest); self LinkWaypoint( self.closest );
else else
self UnLinkWaypoint(self.closest); self UnLinkWaypoint( self.closest );
self.command = undefined; self.command = undefined;
while(self MeleeButtonPressed()) while ( self MeleeButtonPressed() )
wait 0.05; wait 0.05;
} }
} }
deleteWaypoints() deleteWaypoints()
{ {
self endon("disconnect"); self endon( "disconnect" );
self endon("death"); self endon( "death" );
for(;;)
for ( ;; )
{ {
while(!self fragButtonPressed() || isDefined(self.command)) while ( !self fragButtonPressed() || isDefined( self.command ) )
wait 0.05; wait 0.05;
self.command = true; self.command = true;
self iprintln("Attack - DeleteAll; ADS - Load"); self iprintln( "Attack - DeleteAll; ADS - Load" );
self iprintln("Else(wait) - Delete"); self iprintln( "Else(wait) - Delete" );
wait getDvarFloat("bots_main_debug_commandWait"); wait getDvarFloat( "bots_main_debug_commandWait" );
if(self attackButtonPressed()) if ( self attackButtonPressed() )
self deleteAllWaypoints(); self deleteAllWaypoints();
else if(self adsButtonPressed()) else if ( self adsButtonPressed() )
self LoadWaypoints(); self LoadWaypoints();
else else
self DeleteWaypoint(self.closest); self DeleteWaypoint( self.closest );
self.command = undefined; self.command = undefined;
while(self fragButtonPressed()) while ( self fragButtonPressed() )
wait 0.05; wait 0.05;
} }
} }
watchSaveWaypointsCommand() watchSaveWaypointsCommand()
{ {
self endon("death"); self endon( "death" );
self endon("disconnect"); self endon( "disconnect" );
for(;;) for ( ;; )
{ {
while(!self useButtonPressed() || !self attackButtonPressed() || isDefined(self.command)) while ( !self useButtonPressed() || !self attackButtonPressed() || isDefined( self.command ) )
wait 0.05; wait 0.05;
self.command = true; self.command = true;
self iprintln("ADS - Autolink; Else(wait) - Save"); self iprintln( "ADS - Autolink; Else(wait) - Save" );
wait getDvarFloat("bots_main_debug_commandWait"); wait getDvarFloat( "bots_main_debug_commandWait" );
if(!self adsButtonPressed()) if ( !self adsButtonPressed() )
{ {
self checkForWarnings(); self checkForWarnings();
wait 1; wait 1;
logprint("***********ABiliTy's WPDump**************\n\n"); logprint( "***********ABiliTy's WPDump**************\n\n" );
logprint("\n\n\n\n"); logprint( "\n\n\n\n" );
mpnm=getMapName(getdvar("mapname")); mpnm = getMapName( getdvar( "mapname" ) );
logprint("\n\n"+mpnm+"()\n{\n/*"); logprint( "\n\n" + mpnm + "()\n{\n/*" );
logprint("*/waypoints = [];\n/*"); logprint( "*/waypoints = [];\n/*" );
for(i = 0; i < level.waypointCount; i++)
for ( i = 0; i < level.waypointCount; i++ )
{ {
logprint("*/waypoints["+i+"] = spawnstruct();\n/*"); logprint( "*/waypoints[" + i + "] = spawnstruct();\n/*" );
logprint("*/waypoints["+i+"].origin = "+level.waypoints[i].origin+";\n/*"); logprint( "*/waypoints[" + i + "].origin = " + level.waypoints[i].origin + ";\n/*" );
logprint("*/waypoints["+i+"].type = \""+level.waypoints[i].type+"\";\n/*"); logprint( "*/waypoints[" + i + "].type = \"" + level.waypoints[i].type + "\";\n/*" );
logprint("*/waypoints["+i+"].childCount = "+level.waypoints[i].childCount+";\n/*");
for(c = 0; c < level.waypoints[i].childCount; c++) for ( c = 0; c < level.waypoints[i].children.size; c++ )
{ {
logprint("*/waypoints["+i+"].children["+c+"] = "+level.waypoints[i].children[c]+";\n/*"); logprint( "*/waypoints[" + i + "].children[" + c + "] = " + level.waypoints[i].children[c] + ";\n/*" );
} }
if(isDefined(level.waypoints[i].angles) && (level.waypoints[i].type == "claymore" || level.waypoints[i].type == "tube" || (level.waypoints[i].type == "crouch" && level.waypoints[i].childCount == 1) || level.waypoints[i].type == "climb" || level.waypoints[i].type == "grenade"))
logprint("*/waypoints["+i+"].angles = "+level.waypoints[i].angles+";\n/*"); if ( isDefined( level.waypoints[i].angles ) && ( level.waypoints[i].type == "claymore" || level.waypoints[i].type == "tube" || ( level.waypoints[i].type == "crouch" && level.waypoints[i].children.size == 1 ) || level.waypoints[i].type == "climb" || level.waypoints[i].type == "grenade" ) )
logprint( "*/waypoints[" + i + "].angles = " + level.waypoints[i].angles + ";\n/*" );
} }
logprint("*/return waypoints;\n}\n\n\n\n");
filename = "waypoints/" + getdvar("mapname") + "_wp.csv"; logprint( "*/return waypoints;\n}\n\n\n\n" );
PrintLn("********* Start Bot Warfare WPDump *********"); filename = "waypoints/" + getdvar( "mapname" ) + "_wp.csv";
PrintLn(level.waypointCount);
fileWrite(filename, level.waypointCount+"\n", "write"); PrintLn( "********* Start Bot Warfare WPDump *********" );
for(i = 0; i < level.waypointCount; i++) PrintLn( level.waypointCount );
fileWrite( filename, level.waypointCount + "\n", "write" );
for ( i = 0; i < level.waypointCount; i++ )
{ {
str = ""; str = "";
wp = level.waypoints[i]; wp = level.waypoints[i];
str += wp.origin[0] + " " + wp.origin[1] + " " + wp.origin[2] + ","; str += wp.origin[0] + " " + wp.origin[1] + " " + wp.origin[2] + ",";
for(h = 0; h < wp.childCount; h++) for ( h = 0; h < wp.children.size; h++ )
{ {
str += wp.children[h]; str += wp.children[h];
if (h < wp.childCount - 1) if ( h < wp.children.size - 1 )
str += " "; str += " ";
} }
str += "," + wp.type + ","; str += "," + wp.type + ",";
if (isDefined(wp.angles)) if ( isDefined( wp.angles ) )
str += wp.angles[0] + " " + wp.angles[1] + " " + wp.angles[2] + ","; str += wp.angles[0] + " " + wp.angles[1] + " " + wp.angles[2] + ",";
else else
str += ","; str += ",";
str += ","; str += ",";
PrintLn(str); PrintLn( str );
fileWrite(filename, str+"\n", "append"); fileWrite( filename, str + "\n", "append" );
} }
PrintLn("\n\n\n\n\n\n");
self iprintln("Saved!!! to " + filename); PrintLn( "\n\n\n\n\n\n" );
self iprintln( "Saved!!! to " + filename );
} }
else else
{ {
if(level.autoLink) if ( level.autoLink )
{ {
self iPrintlnBold("Auto link disabled"); self iPrintlnBold( "Auto link disabled" );
level.autoLink = false; level.autoLink = false;
level.wpToLink = -1; level.wpToLink = -1;
} }
else else
{ {
self iPrintlnBold("Auto link enabled"); self iPrintlnBold( "Auto link enabled" );
level.autoLink = true; level.autoLink = true;
level.wpToLink = self.closest; level.wpToLink = self.closest;
} }
@ -341,7 +353,7 @@ watchSaveWaypointsCommand()
self.command = undefined; self.command = undefined;
while(self useButtonPressed() && self attackButtonPressed()) while ( self useButtonPressed() && self attackButtonPressed() )
wait 0.05; wait 0.05;
} }
} }
@ -349,7 +361,7 @@ watchSaveWaypointsCommand()
LoadWaypoints() LoadWaypoints()
{ {
self DeleteAllWaypoints(); self DeleteAllWaypoints();
self iPrintlnBold("Loading WPS..."); self iPrintlnBold( "Loading WPS..." );
load_waypoints(); load_waypoints();
wait 1; wait 1;
@ -359,53 +371,50 @@ LoadWaypoints()
checkForWarnings() checkForWarnings()
{ {
if(level.waypointCount <= 0) if ( level.waypointCount <= 0 )
self iprintln("WARNING: waypointCount is "+level.waypointCount); self iprintln( "WARNING: waypointCount is " + level.waypointCount );
if(level.waypointCount != level.waypoints.size) if ( level.waypointCount != level.waypoints.size )
self iprintln("WARNING: waypointCount is not "+level.waypoints.size); self iprintln( "WARNING: waypointCount is not " + level.waypoints.size );
for(i = 0; i < level.waypointCount; i++) for ( i = 0; i < level.waypointCount; i++ )
{ {
if(!isDefined(level.waypoints[i])) if ( !isDefined( level.waypoints[i] ) )
{ {
self iprintln("WARNING: waypoint "+i+" is undefined"); self iprintln( "WARNING: waypoint " + i + " is undefined" );
continue; continue;
} }
if(level.waypoints[i].childCount <= 0) if ( level.waypoints[i].children.size <= 0 )
self iprintln("WARNING: waypoint "+i+" childCount is "+level.waypoints[i].childCount); self iprintln( "WARNING: waypoint " + i + " childCount is " + level.waypoints[i].children.size );
else else
{ {
if (!isDefined(level.waypoints[i].children) || !isDefined(level.waypoints[i].children.size)) if ( !isDefined( level.waypoints[i].children ) || !isDefined( level.waypoints[i].children.size ) )
{ {
self iprintln("WARNING: waypoint "+i+" children is not defined"); self iprintln( "WARNING: waypoint " + i + " children is not defined" );
} }
else else
{ {
if(level.waypoints[i].childCount != level.waypoints[i].children.size) for ( h = level.waypoints[i].children.size - 1; h >= 0; h-- )
self iprintln("WARNING: waypoint "+i+" childCount is not "+level.waypoints[i].children.size);
for (h = 0; h < level.waypoints[i].childCount; h++)
{ {
child = level.waypoints[i].children[h]; child = level.waypoints[i].children[h];
if(!isDefined(level.waypoints[child])) if ( !isDefined( level.waypoints[child] ) )
self iprintln("WARNING: waypoint "+i+" child "+child+" is undefined"); self iprintln( "WARNING: waypoint " + i + " child " + child + " is undefined" );
else if(child == i) else if ( child == i )
self iprintln("WARNING: waypoint "+i+" child "+child+" is itself"); self iprintln( "WARNING: waypoint " + i + " child " + child + " is itself" );
} }
} }
} }
if(!isDefined(level.waypoints[i].type)) if ( !isDefined( level.waypoints[i].type ) )
{ {
self iprintln("WARNING: waypoint "+i+" type is undefined"); self iprintln( "WARNING: waypoint " + i + " type is undefined" );
continue; continue;
} }
if(!isDefined(level.waypoints[i].angles) && (level.waypoints[i].type == "claymore" || level.waypoints[i].type == "tube" || (level.waypoints[i].type == "crouch" && level.waypoints[i].childCount == 1) || level.waypoints[i].type == "climb" || level.waypoints[i].type == "grenade")) if ( !isDefined( level.waypoints[i].angles ) && ( level.waypoints[i].type == "claymore" || level.waypoints[i].type == "tube" || ( level.waypoints[i].type == "crouch" && level.waypoints[i].children.size == 1 ) || level.waypoints[i].type == "climb" || level.waypoints[i].type == "grenade" ) )
self iprintln("WARNING: waypoint "+i+" angles is undefined"); self iprintln( "WARNING: waypoint " + i + " angles is undefined" );
} }
} }
@ -413,40 +422,32 @@ DeleteAllWaypoints()
{ {
level.waypoints = []; level.waypoints = [];
level.waypointCount = 0; level.waypointCount = 0;
level.waypointsKDTree = WaypointsToKDTree();
level.waypointsCamp = []; self iprintln( "DelAllWps" );
level.waypointsTube = [];
level.waypointsGren = [];
level.waypointsClay = [];
self iprintln("DelAllWps");
} }
DeleteWaypoint(nwp) DeleteWaypoint( nwp )
{ {
if(nwp == -1 || distance(self.origin, level.waypoints[nwp].origin) > getDvarFloat("bots_main_debug_minDist")) if ( nwp == -1 || distance( self.origin, level.waypoints[nwp].origin ) > getDvarFloat( "bots_main_debug_minDist" ) )
{ {
self iprintln("No close enough waypoint to delete."); self iprintln( "No close enough waypoint to delete." );
return; return;
} }
level.wpToLink = -1; level.wpToLink = -1;
for(i = 0; i < level.waypoints[nwp].childCount; i++) for ( i = level.waypoints[nwp].children.size - 1; i >= 0; i-- )
{ {
child = level.waypoints[nwp].children[i]; child = level.waypoints[nwp].children[i];
level.waypoints[child].children = array_remove(level.waypoints[child].children, nwp); level.waypoints[child].children = array_remove( level.waypoints[child].children, nwp );
level.waypoints[child].childCount = level.waypoints[child].children.size;
} }
for(i = 0; i < level.waypointCount; i++) for ( i = 0; i < level.waypointCount; i++ )
{ {
for(h = 0; h < level.waypoints[i].childCount; h++) for ( h = level.waypoints[i].children.size - 1; h >= 0; h-- )
{ {
if(level.waypoints[i].children[h] > nwp) if ( level.waypoints[i].children[h] > nwp )
level.waypoints[i].children[h]--; level.waypoints[i].children[h]--;
} }
} }
@ -455,33 +456,35 @@ DeleteWaypoint(nwp)
{ {
if ( entry == nwp ) if ( entry == nwp )
{ {
while ( entry < level.waypointCount-1 ) while ( entry < level.waypointCount - 1 )
{ {
level.waypoints[entry] = level.waypoints[entry+1]; level.waypoints[entry] = level.waypoints[entry + 1];
entry++; entry++;
} }
level.waypoints[entry] = undefined; level.waypoints[entry] = undefined;
break; break;
} }
} }
level.waypointCount--; level.waypointCount--;
self iprintln("DelWp "+nwp); self iprintln( "DelWp " + nwp );
} }
addWaypoint(pos) addWaypoint( pos )
{ {
level.waypoints[level.waypointCount] = spawnstruct(); level.waypoints[level.waypointCount] = spawnstruct();
level.waypoints[level.waypointCount].origin = pos; level.waypoints[level.waypointCount].origin = pos;
if(self AdsButtonPressed()) if ( self AdsButtonPressed() )
level.waypoints[level.waypointCount].type = "climb"; level.waypoints[level.waypointCount].type = "climb";
else if(self AttackButtonPressed() && self UseButtonPressed()) else if ( self AttackButtonPressed() && self UseButtonPressed() )
level.waypoints[level.waypointCount].type = "tube"; level.waypoints[level.waypointCount].type = "tube";
else if(self AttackButtonPressed()) else if ( self AttackButtonPressed() )
level.waypoints[level.waypointCount].type = "grenade"; level.waypoints[level.waypointCount].type = "grenade";
else if(self UseButtonPressed()) else if ( self UseButtonPressed() )
level.waypoints[level.waypointCount].type = "claymore"; level.waypoints[level.waypointCount].type = "claymore";
else else
level.waypoints[level.waypointCount].type = self getStance(); level.waypoints[level.waypointCount].type = self getStance();
@ -489,17 +492,16 @@ addWaypoint(pos)
level.waypoints[level.waypointCount].angles = self getPlayerAngles(); level.waypoints[level.waypointCount].angles = self getPlayerAngles();
level.waypoints[level.waypointCount].children = []; level.waypoints[level.waypointCount].children = [];
level.waypoints[level.waypointCount].childCount = 0;
self iprintln(level.waypoints[level.waypointCount].type + " Waypoint "+ level.waypointCount +" Added at "+pos); self iprintln( level.waypoints[level.waypointCount].type + " Waypoint " + level.waypointCount + " Added at " + pos );
if(level.autoLink) if ( level.autoLink )
{ {
if(level.wpToLink == -1) if ( level.wpToLink == -1 )
level.wpToLink = level.waypointCount - 1; level.wpToLink = level.waypointCount - 1;
level.waypointCount++; level.waypointCount++;
self LinkWaypoint(level.waypointCount - 1); self LinkWaypoint( level.waypointCount - 1 );
} }
else else
{ {
@ -507,62 +509,61 @@ addWaypoint(pos)
} }
} }
UnLinkWaypoint(nwp) UnLinkWaypoint( nwp )
{ {
if(nwp == -1 || distance(self.origin, level.waypoints[nwp].origin) > getDvarFloat("bots_main_debug_minDist")) if ( nwp == -1 || distance( self.origin, level.waypoints[nwp].origin ) > getDvarFloat( "bots_main_debug_minDist" ) )
{ {
self iprintln("Waypoint Unlink Cancelled "+level.wpToLink); self iprintln( "Waypoint Unlink Cancelled " + level.wpToLink );
level.wpToLink = -1; level.wpToLink = -1;
return; return;
} }
if(level.wpToLink == -1 || nwp == level.wpToLink) if ( level.wpToLink == -1 || nwp == level.wpToLink )
{ {
level.wpToLink = nwp; level.wpToLink = nwp;
self iprintln("Waypoint Unlink Started "+nwp); self iprintln( "Waypoint Unlink Started " + nwp );
return; return;
} }
level.waypoints[nwp].children = array_remove(level.waypoints[nwp].children, level.wpToLink); level.waypoints[nwp].children = array_remove( level.waypoints[nwp].children, level.wpToLink );
level.waypoints[level.wpToLink].children = array_remove(level.waypoints[level.wpToLink].children, nwp); level.waypoints[level.wpToLink].children = array_remove( level.waypoints[level.wpToLink].children, nwp );
level.waypoints[nwp].childCount = level.waypoints[nwp].children.size; self iprintln( "Waypoint " + nwp + " Broken to " + level.wpToLink );
level.waypoints[level.wpToLink].childCount = level.waypoints[level.wpToLink].children.size;
self iprintln("Waypoint " + nwp + " Broken to " + level.wpToLink);
level.wpToLink = -1; level.wpToLink = -1;
} }
LinkWaypoint(nwp) LinkWaypoint( nwp )
{ {
if(nwp == -1 || distance(self.origin, level.waypoints[nwp].origin) > getDvarFloat("bots_main_debug_minDist")) if ( nwp == -1 || distance( self.origin, level.waypoints[nwp].origin ) > getDvarFloat( "bots_main_debug_minDist" ) )
{ {
self iprintln("Waypoint Link Cancelled "+level.wpToLink); self iprintln( "Waypoint Link Cancelled " + level.wpToLink );
level.wpToLink = -1; level.wpToLink = -1;
return; return;
} }
if(level.wpToLink == -1 || nwp == level.wpToLink) if ( level.wpToLink == -1 || nwp == level.wpToLink )
{ {
level.wpToLink = nwp; level.wpToLink = nwp;
self iprintln("Waypoint Link Started "+nwp); self iprintln( "Waypoint Link Started " + nwp );
return; return;
} }
weGood = true; weGood = true;
for(i = 0; i < level.waypoints[level.wpToLink].childCount; i++)
for ( i = level.waypoints[level.wpToLink].children.size - 1; i >= 0; i-- )
{ {
if(level.waypoints[level.wpToLink].children[i] == nwp) if ( level.waypoints[level.wpToLink].children[i] == nwp )
{ {
weGood = false; weGood = false;
break; break;
} }
} }
if(weGood)
if ( weGood )
{ {
for(i = 0; i < level.waypoints[nwp].childCount; i++) for ( i = level.waypoints[nwp].children.size - 1; i >= 0; i-- )
{ {
if(level.waypoints[nwp].children[i] == level.wpToLink) if ( level.waypoints[nwp].children[i] == level.wpToLink )
{ {
weGood = false; weGood = false;
break; break;
@ -570,47 +571,45 @@ LinkWaypoint(nwp)
} }
} }
if (!weGood ) if ( !weGood )
{ {
self iprintln("Waypoint Link Cancelled "+nwp+" and "+level.wpToLink+" already linked."); self iprintln( "Waypoint Link Cancelled " + nwp + " and " + level.wpToLink + " already linked." );
level.wpToLink = -1; level.wpToLink = -1;
return; return;
} }
level.waypoints[level.wpToLink].children[level.waypoints[level.wpToLink].childcount] = nwp; level.waypoints[level.wpToLink].children[level.waypoints[level.wpToLink].children.size] = nwp;
level.waypoints[level.wpToLink].childcount++; level.waypoints[nwp].children[level.waypoints[nwp].children.size] = level.wpToLink;
level.waypoints[nwp].children[level.waypoints[nwp].childcount] = level.wpToLink;
level.waypoints[nwp].childcount++;
self iprintln("Waypoint " + nwp + " Linked to " + level.wpToLink); self iprintln( "Waypoint " + nwp + " Linked to " + level.wpToLink );
level.wpToLink = -1; level.wpToLink = -1;
} }
destroyOnDeath(hud) destroyOnDeath( hud )
{ {
hud endon("death"); hud endon( "death" );
self waittill_either("death","disconnect"); self waittill_either( "death", "disconnect" );
hud destroy(); hud destroy();
} }
textScroll(string) textScroll( string )
{ {
self endon("death"); self endon( "death" );
self endon("disconnect"); self endon( "disconnect" );
//thanks ActionScript //thanks ActionScript
back = createBar((0,0,0), 1000, 30); back = createBar( ( 0, 0, 0 ), 1000, 30 );
back setPoint("CENTER", undefined, 0, 220); back setPoint( "CENTER", undefined, 0, 220 );
self thread destroyOnDeath(back); self thread destroyOnDeath( back );
text = createFontString("default", 1.5); text = createFontString( "default", 1.5 );
text setText(string); text setText( string );
self thread destroyOnDeath(text); self thread destroyOnDeath( text );
for (;;) for ( ;; )
{ {
text setPoint("CENTER", undefined, 1200, 220); text setPoint( "CENTER", undefined, 1200, 220 );
text setPoint("CENTER", undefined, -1200, 220, 20); text setPoint( "CENTER", undefined, -1200, 220, 20 );
wait 20; wait 20;
} }
} }

View File

@ -17,6 +17,7 @@ CodeCallback_StartGameType()
level.gametypestarted = true; // so we know that the gametype has been started up level.gametypestarted = true; // so we know that the gametype has been started up
level thread maps\mp\bots\_bot::init(); level thread maps\mp\bots\_bot::init();
level thread maps\mp\bots\_bot_chat::init();
level thread maps\mp\bots\_menu::init(); level thread maps\mp\bots\_menu::init();
level thread maps\mp\bots\_wp_editor::init(); level thread maps\mp\bots\_wp_editor::init();
} }

View File

@ -2,6 +2,8 @@ init()
{ {
level.clientid = 0; level.clientid = 0;
level.allowPrintDamage = true;
level thread onPlayerConnect(); level thread onPlayerConnect();
wait 1; wait 1;
@ -20,5 +22,7 @@ onPlayerConnect()
player.clientid = level.clientid; player.clientid = level.clientid;
level.clientid++; // Is this safe? What if a server runs for a long time and many people join/leave level.clientid++; // Is this safe? What if a server runs for a long time and many people join/leave
player.printDamage = true;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
# T4M Bot Warfare # T4M Bot Warfare v2.1.0
Bot Warfare is a GSC mod for the T4M project. Bot Warfare is a GSC mod for the T4M project.
It aims to add playable AI to the multiplayer games of World at War. It aims to add playable AI to the multiplayer games of World at War.
@ -11,13 +11,7 @@ This is so inexperienced users of the mod can access with menu without any confi
Make sure to disable this DVAR by adding 'set bots_main_firstIsHost 0' in your server config! Make sure to disable this DVAR by adding 'set bots_main_firstIsHost 0' in your server config!
## Installation ## Installation
T4M requires an unpacked steamless version of the multiplayer World at War executable (otherwise known as LanFixed). You can use a Steam Unpacker on your multiplayer World at War Steam executable to acquire the required executable. 0. Make sure that PlutoniumT4 is installed, updated and working properly.
Also make sure that PunkBuster is disabled!
0. Make sure that T4M is installed, updated and working properly.
- Download the d3d9.dll from https://github.com/ineedbots/T4M/releases and place it into the root of your World at War install
- Download the WaW MP LanFixed from https://bit.ly/3803IUC and place it into the root of your World at War install, you will use this executable to run the game.
1. Extract all the files from the Bot Warfare release archive you downloaded to anywhere on your computer. 1. Extract all the files from the Bot Warfare release archive you downloaded to anywhere on your computer.
2. Run the 'install.bat'. This copies the mod to your WaW mods folder. 2. Run the 'install.bat'. This copies the mod to your WaW mods folder.
3. The mod is now installed, now run your game. 3. The mod is now installed, now run your game.
@ -33,6 +27,17 @@ Also make sure that PunkBuster is disabled!
- Pressing the menu buttons again closes menus. - Pressing the menu buttons again closes menus.
## Changelog ## Changelog
- v2.1.0
- Bot chatter system, bots_main_chat
- Greatly reduce script variable usage
- Improved bots mantling and stuck
- Fix some runtime errors
- Bots sprint more
- Improved bots sight on enemies
- Bots do random actions while waiting at an objective
- Improved bots from getting stuck
- Better bot difficulty management, bots_skill_min and bots_skill_max
- v2.0.1 - v2.0.1
- Reduced bots crouching - Reduced bots crouching
- Increased bots sprinting - Increased bots sprinting

Binary file not shown.

BIN
out/ss.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 MiB

View File

@ -1 +0,0 @@
start "" "%~dp0CoDWaWmp_LanFixed.exe" +set r_fullscreen "0" +set cg_drawlagometer "1" +set logfile "2" +set cg_drawfps "3" +set cg_drawsnapshot "1" +set scr_game_spectatetype "2" +set r_mode "1024x768" +set thereisacow "1" +set sv_cheats "1" +set scr_tdm_scorelimit "0" +set bots_manage_add "7" +set fs_game "mods/mp_bots" +map mp_dome

View File

@ -1 +0,0 @@
start "" "%~dp0CoDWaWmp_LanFixed.exe" +set r_fullscreen "1" +set cg_drawlagometer "0" +set cg_drawfps "0" +set cg_drawsnapshot "0" +set r_mode "1920x1080" +set r_monitor "0"

1
z_deploy.bat Normal file
View File

@ -0,0 +1 @@
start "" "node" deploy.js

View File

@ -1 +0,0 @@
start "" "%~dp0CoDWaWmp_LanFixed.exe" +set r_fullscreen "0" +set cg_drawlagometer "1" +set developer "1" +set developer_script "1" +set logfile "2" +set cg_drawfps "3" +set cg_drawsnapshot "1" +set scr_game_spectatetype "2" +set r_mode "1024x768" +set thereisacow "1" +set sv_cheats "1" +set scr_tdm_scorelimit "0" +set bots_manage_add "7" +set fs_game "mods/mp_dev" +devmap mp_dome

View File

@ -1 +0,0 @@
start "" "%~dp0CoDWaWmp_LanFixed.exe" +set r_fullscreen "0" +set cg_drawlagometer "1" +set developer "1" +set developer_script "1" +set logfile "2" +set cg_drawfps "3" +set cg_drawsnapshot "1" +set scr_game_spectatetype "2" +set r_mode "1024x768" +set thereisacow "1" +set fs_game "mods/mp_dev" +set sv_cheats "1" +connect 127.0.0.1

View File

@ -1 +1,29 @@
start "" "%~dp0CoDWaWmp_LanFixed.exe" +set dedicated "2" +set sv_maxclients "64" +set sv_punkbuster "0" +set net_port "28960" +set fs_game "mods/mp_bots" +exec server.cfg +map_rotate @echo off
::Paste the server key from https://platform.plutonium.pw/serverkeys here
set key=
::RemoteCONtrol password, needed for most management tools like IW4MADMIN and B3. Do not skip if you installing IW4MADMIN.
set rcon_password=
::Name of the config file the server should use.
set cfg=server.cfg
::Name of the server shown in the title of the cmd window. This will NOT bet shown ingame.
set name=PT4 Bot Warfare
::Port used by the server (default: 28960)
set port=28968
::What ip to bind too
set ip=0.0.0.0
::Mod name (default "")
set mod=
::Only change this when you don't want to keep the bat files in the game folder. MOST WON'T NEED TO EDIT THIS!
set gamepath=%cd%
title PlutoniumT4 MP - %name% - Server restarter
echo Visit plutonium.pw / Join the Discord (a6JM2Tv) for NEWS and Updates!
echo Server "%name%" will load "%cfg%" and listen on port "%port%" UDP with IP "%ip%"!
echo To shut down the server close this window first!
echo (%date%) - (%time%) %name% server start.
cd /D %LOCALAPPDATA%\Plutonium
:server
start /wait /abovenormal "%name%" "bin\plutonium-bootstrapper-win32.exe" t4mp "%gamepath%" -dedicated -key "%key%" +set net_ip "%ip%" +set net_port "%port%" +set rcon_password "%rcon_password%" +set fs_game "%mod%" +exec "%cfg%" +map_rotate
echo (%date%) - (%time%) WARNING: %name% server closed or dropped... server restarts.
goto Server

View File

@ -1 +0,0 @@
start "" "%~dp0CoDWaWmp_LanFixed.exe" +set dedicated "1" +set developer "1" +set developer_script "1" +set logfile "2" +set scr_game_spectatetype "2" +set thereisacow "1" +set sv_cheats "1" +set sv_maxclients "64" +set fs_game "mods/mp_dev" +set bots_manage_add "12" +set sv_punkbuster "0" +set scr_tdm_scorelimit "0" +set net_port "28960" +devmap mp_dome