shi
This commit is contained in:
+64
-11
@@ -19,7 +19,7 @@
|
||||
# BOT AIM VARIABLE NOTES:
|
||||
#
|
||||
# The offset and the aim speed are more base values. When a bot has to turn little the aimspeed
|
||||
# and the aim offset will be lower(so he will aim more precise) and when a bot has to turn much
|
||||
# and the aim offset will be lower(so he will aim more precise) and when the bot has to turn much
|
||||
# the aimspeed and aim offset will be higher(so he will aim fast but inaccurate).
|
||||
#
|
||||
#
|
||||
@@ -62,10 +62,6 @@
|
||||
# Description = Sets if the bot will search for items when he has an enemy.
|
||||
# Unit of Measure = Bool(1 = on, 0 = off)
|
||||
#
|
||||
# can_predict_position <value> :
|
||||
# Description = Sets if the bot will predict their enemy's position.
|
||||
# Unit of Measure = Bool(1 = on, 0 = off)
|
||||
#
|
||||
# max_hear_volume <value>
|
||||
# Description = Sets 'how much' the bot can hear, how lower the value, how lower the max distance a
|
||||
# bot can still hear a sound.
|
||||
@@ -79,15 +75,72 @@
|
||||
# Description = Sets the maximum distance at which the bot will always spot the enemy
|
||||
# Unit of Measure = Float (distance in cubes)
|
||||
#
|
||||
# BOT SMART VARIABLES (only used by the best+ skill, keep them at 0 for the others):
|
||||
#
|
||||
# smart_movement <value> :
|
||||
# Description = Steers around walls instead of walking into them, and uses diagonal movement
|
||||
# (two keys at once is faster) whenever that is quicker.
|
||||
#
|
||||
# smart_weapons <value> :
|
||||
# Description = Weighs every weapon on the damage it can land at the current distance
|
||||
# (range window, accuracy, ammo and reload state) instead of using fixed bonuses.
|
||||
#
|
||||
# smart_grenades <value> :
|
||||
# Description = Only throws grenades when they are useful: out of our own blast radius,
|
||||
# close enough to land, not into a wall and never onto a team mate.
|
||||
# Also runs out of the way of live grenades.
|
||||
#
|
||||
# smart_targeting <value> :
|
||||
# Description = Picks enemies on threat (distance, who is aiming at us, who is nearly dead,
|
||||
# who we are already looking at) instead of distance only.
|
||||
#
|
||||
# dodge_fire <value> :
|
||||
# Description = Reacts to taking damage by strafing and sometimes jumping instead of
|
||||
# continuing to walk in a straight line.
|
||||
#
|
||||
# Unit of Measure = Bool(1 = on, 0 = off)
|
||||
#
|
||||
# SKILL LEVELS:
|
||||
#
|
||||
# There are five skill levels to edit (and choose from ingame). SKILL1 is the highest skill level
|
||||
# while SKILL5 is the lowest skill level.
|
||||
# There are six skill levels to edit (and choose from ingame). SKILL1 is the highest skill level
|
||||
# (best+) while SKILL6 is the lowest skill level (bad).
|
||||
#
|
||||
#-----------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
[SKILL1]
|
||||
min_x_aim_speed 450
|
||||
max_x_aim_speed 520
|
||||
min_y_aim_speed 500
|
||||
max_y_aim_speed 560
|
||||
|
||||
min_x_aim_offset 0
|
||||
max_x_aim_offset 2
|
||||
min_y_aim_offset 0
|
||||
max_y_aim_offset 2
|
||||
|
||||
min_attack_delay 0.02
|
||||
max_attack_delay 0.08
|
||||
|
||||
min_enemy_search_delay 0.04
|
||||
max_enemy_search_delay 0.07
|
||||
|
||||
max_always_detect_distance 20
|
||||
|
||||
can_predict_position 1
|
||||
can_circle_strafe 1
|
||||
can_search_items_in_combat 1
|
||||
|
||||
smart_movement 1
|
||||
smart_weapons 1
|
||||
smart_grenades 1
|
||||
smart_targeting 1
|
||||
dodge_fire 1
|
||||
|
||||
max_hear_volume 100
|
||||
field_of_view 240
|
||||
|
||||
[SKILL2]
|
||||
min_x_aim_speed 330
|
||||
max_x_aim_speed 355
|
||||
min_y_aim_speed 350
|
||||
@@ -113,7 +166,7 @@ can_search_items_in_combat 1
|
||||
max_hear_volume 75
|
||||
field_of_view 200
|
||||
|
||||
[SKILL2]
|
||||
[SKILL3]
|
||||
min_general_delay 0.035
|
||||
max_general_delay 0.045
|
||||
|
||||
@@ -142,7 +195,7 @@ can_search_items_in_combat 1
|
||||
max_hear_volume 60
|
||||
field_of_view 160
|
||||
|
||||
[SKILL3]
|
||||
[SKILL4]
|
||||
min_x_aim_speed 190
|
||||
max_x_aim_speed 225
|
||||
min_y_aim_speed 210
|
||||
@@ -168,7 +221,7 @@ can_search_items_in_combat 0
|
||||
max_hear_volume 40
|
||||
field_of_view 140
|
||||
|
||||
[SKILL4]
|
||||
[SKILL5]
|
||||
min_x_aim_speed 155
|
||||
max_x_aim_speed 170
|
||||
min_y_aim_speed 175
|
||||
@@ -194,7 +247,7 @@ can_search_items_in_combat 0
|
||||
max_hear_volume 30
|
||||
field_of_view 120
|
||||
|
||||
[SKILL5]
|
||||
[SKILL6]
|
||||
min_x_aim_speed 60
|
||||
max_x_aim_speed 90
|
||||
min_y_aim_speed 80
|
||||
|
||||
+4
-4
@@ -4223,14 +4223,14 @@ docref [waterlevel];
|
||||
docsection [Bot mode]
|
||||
docident [addbot] [Adds a bot for a given team with a given skill calling him a given name.];
|
||||
docargument [T] [team] [RVSF or CLA] [0];
|
||||
docargument [S] [skill] [best, good, medium, worse, bad] [0];
|
||||
docargument [S] [skill] [best+, best, good, medium, worse, bad] [0];
|
||||
docargument [N] [name] [name for the bot] [0];
|
||||
docremark [This command only works for single player modes.];
|
||||
docexample [addbot RVSF medium Robbie] [Will add a bot named Robbie with a medium skill level to the RVSF team.];
|
||||
docident [addnbot] [Adds a given count of bots for the given team with the given skill and select random names for them.];
|
||||
docargument [C] [count] [how many bots to add] [0];
|
||||
docargument [T] [team] [RVSF or CLA] [0];
|
||||
docargument [S] [skill] [best, good, medium, worse, bad] [0];
|
||||
docargument [S] [skill] [best+, best, good, medium, worse, bad] [0];
|
||||
docremark [This command only works for single player modes.];
|
||||
docremark [The name of the bots will be selected randomly.];
|
||||
docexample [addnbot 2 CLA bad] [Will add 2 bots with a bad skill level to the CLA team.];
|
||||
@@ -4243,10 +4243,10 @@ docargument [A] [connect automatically] [0 or 1] [0];
|
||||
docident [autowp] [Automatically places waypoints.];
|
||||
docident [botskill] [Changes the skill level for the given bot.];
|
||||
docargument [N] [botname] [the name of the bot] [0];
|
||||
docargument [S] [botskill] [best, good, medium, worse, bad] [0];
|
||||
docargument [S] [botskill] [best+, best, good, medium, worse, bad] [0];
|
||||
docexample [botskill Robbie best] [Changes the previous bot skill level of the bot named Robbie to a 'best' skill level.];
|
||||
docident [botskillall] [Changes the skill level for all bots.];
|
||||
docargument [S] [botskill] [best, good, medium, worse, bad] [0];
|
||||
docargument [S] [botskill] [best+, best, good, medium, worse, bad] [0];
|
||||
docexample [botskillall worse] [Changes the previous bot skill level for all bots to a 'worse' skill level.];
|
||||
docident [botsshoot] [Enables or disables the ability of the bots to fire their weapons.];
|
||||
docargument [T] [shooting bots?] [0 or 1] [0];
|
||||
|
||||
+15
-2
@@ -25,11 +25,14 @@ const __maps_most [ac_africa ac_alcove ac_aqueous ac_arabian ac_arctic ac_arctic
|
||||
const __maps_flags [ac_africa ac_alcove ac_aqueous ac_arabian ac_arctic2 ac_arid ac_avenue ac_coal ac_depot ac_desert3 ac_dusk ac_edifice ac_elevation ac_gothic ac_industrial ac_ingress ac_kazemat ac_keller ac_lainio ac_lotus ac_mines ac_nocturne ac_origin ac_outpost ac_power ac_rampart ac_shine ac_stellar ac_sunset ac_swamp ac_terros ac_urban ac_venison ac_werk]
|
||||
// this list is like maps_flags (but with ac_douze) that support TKTF
|
||||
const __maps_tktf [ac_africa ac_alcove ac_aqueous ac_arabian ac_arctic2 ac_arid ac_avenue ac_coal ac_depot ac_desert3 ac_douze ac_dusk ac_edifice ac_elevation ac_gothic ac_industrial ac_ingress ac_kazemat ac_keller ac_lainio ac_lotus ac_mines ac_nocturne ac_origin ac_outpost ac_power ac_rampart ac_shine ac_stellar ac_sunset ac_swamp ac_terros ac_urban ac_venison ac_werk]
|
||||
// fork maps: silly maps that are not balanced AssaultCube maps (converted maps, experiments, ...)
|
||||
// just add the map name here to get it into the "Maps+" submenu
|
||||
const __maps_plus [dust2css]
|
||||
|
||||
// Start maps.
|
||||
const __genmapitems [
|
||||
looplisti $arg1 m [
|
||||
menuitemmapload $m [map @m; if (= (curmastermode) 2) [ showmenu [Match Settings] ] ]
|
||||
menuitemmapload $m [map @m; if (= (curmastermode) 2) [ __matchsettings_bot = 0; showmenu [Match Settings] ] ]
|
||||
[nextmap_@m] = (at $arg1 (mod (+ $i 1) @(listlen $arg1)))
|
||||
]
|
||||
]
|
||||
@@ -37,30 +40,40 @@ const __genmapitems [
|
||||
newmenu all_custom_maps
|
||||
menutitle "custom maps"
|
||||
menurenderoffset -20 0
|
||||
menudirlist "packages/maps" cgz [map $arg1; if (= (curmastermode) 2) [ showmenu [Match Settings] ] ]
|
||||
menudirlist "packages/maps" cgz [map $arg1; if (= (curmastermode) 2) [ __matchsettings_bot = 0; showmenu [Match Settings] ] ]
|
||||
|
||||
newmenu maps
|
||||
__genmapitems $__maps_all
|
||||
menuitem [] -1
|
||||
menuitem "Show all custom maps\i\3" [showmenu all_custom_maps]
|
||||
menuitem "Maps+\i\3" [showmenu maps_plus]
|
||||
|
||||
newmenu maps_most
|
||||
menutitle "maps"
|
||||
__genmapitems $__maps_most
|
||||
menuitem [] -1
|
||||
menuitem "Show all custom maps\i\3" [showmenu all_custom_maps]
|
||||
menuitem "Maps+\i\3" [showmenu maps_plus]
|
||||
|
||||
newmenu maps_flags
|
||||
menutitle "maps with flags"
|
||||
__genmapitems $__maps_flags
|
||||
menuitem [] -1
|
||||
menuitem "Show all custom maps\i\3" [showmenu all_custom_maps]
|
||||
menuitem "Maps+\i\3" [showmenu maps_plus]
|
||||
|
||||
newmenu maps_tktf
|
||||
menutitle "maps with flags"
|
||||
__genmapitems $__maps_tktf
|
||||
menuitem [] -1
|
||||
menuitem "Show all custom maps\i\3" [showmenu all_custom_maps]
|
||||
menuitem "Maps+\i\3" [showmenu maps_plus]
|
||||
|
||||
newmenu maps_plus
|
||||
menutitle "maps+"
|
||||
__genmapitems $__maps_plus
|
||||
menuitem [] -1
|
||||
menuitem "Show all custom maps\i\3" [showmenu all_custom_maps]
|
||||
|
||||
//// Main > Play demo ////
|
||||
|
||||
|
||||
+11
-1
@@ -4,13 +4,22 @@ newmenu botmaps
|
||||
|
||||
const genbotmaps [
|
||||
looplist $arg1 listmapname [
|
||||
menuitemmapload $listmapname (concat "tmp_botmap =" $listmapname "; showmenu [Match Settings]")
|
||||
menuitemmapload $listmapname (concat "tmp_botmap =" $listmapname "; __matchsettings_bot = 1; showmenu [Match Settings]")
|
||||
]
|
||||
]
|
||||
// problems with quite a number of maps when playing against bots (waypoints simply flooded) have lead to generating lists to avoid these
|
||||
//known issues on: (BTDM) ac_alcove ac_aqueous ac_avenue ac_coal ac_depot ac_kazemat ac_keller ac_outpost ac_power ac_shine ac_terros ac_urban
|
||||
const __bot_maps_all [ac_africa ac_arabian ac_arctic ac_arctic2 ac_arid ac_complex ac_desert ac_desert2 ac_desert3 ac_douze ac_dusk ac_edifice ac_elevation ac_gothic ac_industrial ac_ingress ac_lainio ac_lotus ac_mines ac_nocturne ac_origin ac_rampart ac_rattrap ac_scaffold ac_snow ac_stellar ac_sunset ac_swamp ac_toxic ac_venison ac_wasteland ac_werk]
|
||||
genbotmaps $__bot_maps_all
|
||||
menuitem [] -1
|
||||
menuitem "Maps+\i\3" [showmenu botmaps_plus]
|
||||
|
||||
// the fork maps of menus.cfg ($__maps_plus), with bots
|
||||
newmenu botmaps_plus
|
||||
menutitle "maps+"
|
||||
genbotmaps $__maps_plus
|
||||
menuitem [] -1
|
||||
menuitem "Back to bot maps\i\3" [showmenu botmaps]
|
||||
|
||||
tempalias tmp_botskill good
|
||||
tempalias tmp_numbots 1
|
||||
@@ -107,6 +116,7 @@ const showmenu_enemies [ if ($tmp_isbotteammode) [ showmenu [team enemies] ] [ s
|
||||
|
||||
newmenu botskill
|
||||
|
||||
menuitem "Best+ (brutal)" [ tmp_botskill = best+; showmenu_enemies ]
|
||||
menuitem Best [ tmp_botskill = best; showmenu_enemies ]
|
||||
menuitem "Good (default)" [ tmp_botskill = good; showmenu_enemies ]
|
||||
menuitem Medium [ tmp_botskill = medium; showmenu_enemies ]
|
||||
|
||||
@@ -85,7 +85,7 @@ menuinit [
|
||||
menuitem "Kick/ban player\i\3" [ showmenu kick/ban ]
|
||||
menuitem "Adjust teams\i\3" [ showmenu [Team adjustment] ]
|
||||
menuitem "Change mastermode\i\3" [ showmenu Mastermode ]
|
||||
menuitem "Match Settings\i\3" [ showmenu [Match Settings] ]
|
||||
menuitem "Match Settings\i\3" [ __matchsettings_bot = 0; showmenu [Match Settings] ]
|
||||
menuitem "Change the server description\i\3" [ saycommand "/serverdesc " ]
|
||||
menuitem "Find a players IP address\i\3" [ saycommand "/whois " ]
|
||||
menuitem "Give admin\i\3" [ showmenu [give admin] ]
|
||||
@@ -162,38 +162,51 @@ newmenu Mastermode
|
||||
menuadminonly 2
|
||||
menuitem [Unlock the server (open)] [ mastermode 0 ]
|
||||
menuitem [Lock the server (private)] [ mastermode 1 ]
|
||||
menuitem [Lock the server (match mode)] [ mastermode 2; showmenu [Match Settings] ]
|
||||
menuitem [Lock the server (match mode)] [ mastermode 2; __matchsettings_bot = 0; showmenu [Match Settings] ]
|
||||
|
||||
//// In-Game admin > Match Settings ////
|
||||
|
||||
// 1 while setting up a singleplayer bot match (set by menus_bot.cfg); the "Start Bot
|
||||
// Match" button and the way back to the bot map list are only offered in that case.
|
||||
__matchsettings_bot = 0
|
||||
|
||||
const __matchsettings_items [
|
||||
menuitemslider "Recoil Multiplier: " 50 500 "$matchrecoilmul" 10 [ matchset matchrecoilmul $arg1 ]
|
||||
menuitemslider "Spread Multiplier: " 50 500 "$matchspreadmul" 10 [ matchset matchspreadmul $arg1 ]
|
||||
menuitemslider "Speed Multiplier: " 50 500 "$matchspeedmul" 10 [ matchset matchspeedmul $arg1 ]
|
||||
menuitemslider "Gravity Multiplier: " 50 500 "$matchgravity" 10 [ matchset matchgravity $arg1 ]
|
||||
menuitemslider "Friction Multiplier: " 10 500 "$matchfriction" 10 [ matchset matchfriction $arg1 ]
|
||||
menuitem "" -1
|
||||
menuitemcheckbox "Enable Assists: " "$matchassist" [ matchset matchassist $arg1 ]
|
||||
menuitemcheckbox "Reload cancel on switch: " "$matchreloadcancel" [ matchset matchreloadcancel $arg1 ]
|
||||
menuitemcheckbox "Knife+jump speed boost: " "$matchknifeboost" [ matchset matchknifeboost $arg1 ]
|
||||
menuitemcheckbox "Medkit pickup item: " "$matchmedkit" [ matchset matchmedkit $arg1 ]
|
||||
menuitemcheckbox "Slow backwards walk (70%): " "$matchbackwards" [ matchset matchbackwards $arg1 ]
|
||||
menuitemcheckbox "Ceiling bump speed boost: " "$matchheadboost" [ matchset matchheadboost $arg1 ]
|
||||
menuitemcheckbox "Source-style physics (bhop/air strafe): " "$matchsourcephysics" [ matchset matchsourcephysics $arg1 ]
|
||||
menuitemcheckbox "Explosive Deaths: " "$matchdeathexplosion" [ matchset matchdeathexplosion $arg1 ]
|
||||
menuitemslider " Blast Radius %: " 10 300 "$matchdeathradius" 10 [ matchset matchdeathradius $arg1 ]
|
||||
menuitemslider " Blast Power %: " 10 500 "$matchdeathpower" 10 [ matchset matchdeathpower $arg1 ]
|
||||
menuitem "" -1
|
||||
menuitem "Friendly Fire\i\3" [ showmenu [Match Friendly Fire] ]
|
||||
menuitem "" -1
|
||||
menuitem "Spawn Weapons\i\3" [ showmenu [Match Spawn Weapons] ]
|
||||
if $__matchsettings_bot [
|
||||
menuitem "" -1
|
||||
menuitem "\f2Start Bot Match" [ startbotmap ]
|
||||
]
|
||||
menuitem "" -1
|
||||
menuitem "Reset to defaults" [ matchsetreset; showmenu [Match Settings] ]
|
||||
menuitem "Back" [ showmenu @(at [Mastermode botmaps] $__matchsettings_bot) ]
|
||||
]
|
||||
|
||||
newmenu [Match Settings]
|
||||
menuadminonly 2
|
||||
menuinit [ ]
|
||||
menuitemslider "Recoil Multiplier: " 50 500 "$matchrecoilmul" 10 [ matchset matchrecoilmul $arg1 ]
|
||||
menuitemslider "Spread Multiplier: " 50 500 "$matchspreadmul" 10 [ matchset matchspreadmul $arg1 ]
|
||||
menuitemslider "Speed Multiplier: " 50 500 "$matchspeedmul" 10 [ matchset matchspeedmul $arg1 ]
|
||||
menuitemslider "Gravity Multiplier: " 50 500 "$matchgravity" 10 [ matchset matchgravity $arg1 ]
|
||||
menuitemslider "Friction Multiplier: " 10 500 "$matchfriction" 10 [ matchset matchfriction $arg1 ]
|
||||
menuitem "" -1
|
||||
menuitemcheckbox "Enable Assists: " "$matchassist" [ matchset matchassist $arg1 ]
|
||||
menuitemcheckbox "Reload cancel on switch: " "$matchreloadcancel" [ matchset matchreloadcancel $arg1 ]
|
||||
menuitemcheckbox "Knife+jump speed boost: " "$matchknifeboost" [ matchset matchknifeboost $arg1 ]
|
||||
menuitemcheckbox "Medkit pickup item: " "$matchmedkit" [ matchset matchmedkit $arg1 ]
|
||||
menuitemcheckbox "Slow backwards walk (70%): " "$matchbackwards" [ matchset matchbackwards $arg1 ]
|
||||
menuitemcheckbox "Ceiling bump speed boost: " "$matchheadboost" [ matchset matchheadboost $arg1 ]
|
||||
menuitemcheckbox "Source-style physics (bhop/air strafe): " "$matchsourcephysics" [ matchset matchsourcephysics $arg1 ]
|
||||
menuitemcheckbox "Explosive Deaths: " "$matchdeathexplosion" [ matchset matchdeathexplosion $arg1 ]
|
||||
menuitemslider " Blast Radius %: " 10 300 "$matchdeathradius" 10 [ matchset matchdeathradius $arg1 ]
|
||||
menuitemslider " Blast Power %: " 10 500 "$matchdeathpower" 10 [ matchset matchdeathpower $arg1 ]
|
||||
menuitem "" -1
|
||||
menuitem "Friendly Fire\i\3" [ showmenu [Match Friendly Fire] ]
|
||||
menuitem "" -1
|
||||
menuitem "Spawn Weapons\i\3" [ showmenu [Match Spawn Weapons] ]
|
||||
menuitem "" -1
|
||||
menuitem "\f2Start Bot Match" [ startbotmap ]
|
||||
menuitem "" -1
|
||||
menuitem "Reset to defaults" [ matchsetreset; showmenu [Match Settings] ]
|
||||
menuitem "Back" [ showmenu Mastermode ]
|
||||
menuinit [
|
||||
resetcurmenu
|
||||
menuadminonly 2
|
||||
__matchsettings_items
|
||||
]
|
||||
|
||||
//// In-Game admin > Match Settings > Friendly Fire ////
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
// example MOTD:
|
||||
-o \f3server using example cmdline file (config/servercmdline.txt)\n\f2gassy server 🥶
|
||||
-f 27015
|
||||
// -f 27015
|
||||
|
||||
// commonly used commandline switches:
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ Adds a bot in the current game. Command arguments:
|
||||
<teamname>: Specifies the team for the bot, when you leave it blank or
|
||||
use "random" as team the bot will choose a team from the file
|
||||
'bot/bot_teams.txt'.
|
||||
<skill>: The skill of the bot; can be best, good, medium, worse, bad, default or random.
|
||||
<skill>: The skill of the bot; can be best+, best, good, medium, worse, bad, default or random.
|
||||
When blank or "default" is used as skill, the bot will use skill good. When "random" is used,
|
||||
the bot will use a random skill.
|
||||
<name>: The name for this bot. When blank the bot will pick a name from the
|
||||
@@ -154,7 +154,7 @@ Adds multiple bots to the game. Command arguments:
|
||||
<teamname>: Specifies the team for the bots, when you leave it blank or
|
||||
use "random" as team the bot will choose a team from the file
|
||||
'bot/bot_teams.txt'.
|
||||
<skill>: The skill of the bot; can be best, good, medium, worse, bad, default or random.
|
||||
<skill>: The skill of the bot; can be best+, best, good, medium, worse, bad, default or random.
|
||||
When blank or "default" is used as skill, the bot will use skill good. When "random" is used,
|
||||
the bot will use a random skill.
|
||||
|
||||
@@ -172,7 +172,7 @@ Will kick all bots from the server
|
||||
|
||||
botskill <botname> <skill>
|
||||
Will change the skill of the bot with the name <botname> to <skill>.
|
||||
<skill> can be best, good, medium, worse or bad.
|
||||
<skill> can be best+, best, good, medium, worse or bad.
|
||||
|
||||
Example:
|
||||
To change the skill of the bot Joe to best:
|
||||
@@ -181,7 +181,7 @@ botskill Joe best
|
||||
|
||||
botskillall <skill>
|
||||
Will change the bot skill and the default skill to <skill>.
|
||||
<skill> can be best, good, medium, worse or bad.
|
||||
<skill> can be best+, best, good, medium, worse or bad.
|
||||
|
||||
|
||||
5.3 List of all client side commands(Works if you're a host or joined a server):
|
||||
|
||||
+4
-4
@@ -11677,7 +11677,7 @@ name="AssaultCube Documentation" version="Current" xsi:schemaLocation="xml/cuber
|
||||
<description>Adds a bot for a given team with a given skill calling him a given name.</description>
|
||||
<arguments>
|
||||
<argument token="T" description="team" valueNotes="RVSF or CLA"/>
|
||||
<argument token="S" description="skill" valueNotes="best, good, medium, worse, bad"/>
|
||||
<argument token="S" description="skill" valueNotes="best+, best, good, medium, worse, bad"/>
|
||||
<argument token="N" description="name" valueNotes="name for the bot"/>
|
||||
</arguments>
|
||||
<remarks>
|
||||
@@ -11696,7 +11696,7 @@ name="AssaultCube Documentation" version="Current" xsi:schemaLocation="xml/cuber
|
||||
<arguments>
|
||||
<argument token="C" description="count" valueNotes="how many bots to add"/>
|
||||
<argument token="T" description="team" valueNotes="RVSF or CLA"/>
|
||||
<argument token="S" description="skill" valueNotes="best, good, medium, worse, bad"/>
|
||||
<argument token="S" description="skill" valueNotes="best+, best, good, medium, worse, bad"/>
|
||||
</arguments>
|
||||
<remarks>
|
||||
<remark>This command only works for single player modes.</remark>
|
||||
@@ -11714,7 +11714,7 @@ name="AssaultCube Documentation" version="Current" xsi:schemaLocation="xml/cuber
|
||||
<description>Changes the skill level for the given bot.</description>
|
||||
<arguments>
|
||||
<argument token="N" description="botname" valueNotes="the name of the bot"/>
|
||||
<argument token="S" description="botskill" valueNotes="best, good, medium, worse, bad"/>
|
||||
<argument token="S" description="botskill" valueNotes="best+, best, good, medium, worse, bad"/>
|
||||
</arguments>
|
||||
<examples>
|
||||
<example>
|
||||
@@ -11727,7 +11727,7 @@ name="AssaultCube Documentation" version="Current" xsi:schemaLocation="xml/cuber
|
||||
<command name="botskillall">
|
||||
<description>Changes the skill level for all bots.</description>
|
||||
<arguments>
|
||||
<argument token="S" description="botskill" valueNotes="best, good, medium, worse, bad"/>
|
||||
<argument token="S" description="botskill" valueNotes="best+, best, good, medium, worse, bad"/>
|
||||
</arguments>
|
||||
<examples>
|
||||
<example>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -62,6 +62,33 @@ void CACBot::Spawn()
|
||||
|
||||
m_vGoal = m_vWaterGoal = g_vecZero;
|
||||
|
||||
m_iLastHealth = m_pMyEnt->health;
|
||||
m_iDodgeTime = 0;
|
||||
m_iDodgeDir = DIR_NONE;
|
||||
m_iGrenadeDelay = 0;
|
||||
m_iStrafeSide = DIR_NONE;
|
||||
m_iStrafeSideTime = 0;
|
||||
m_iSteerSide = DIR_NONE;
|
||||
m_iSteerSideTime = 0;
|
||||
m_iSteerDir = DIR_NONE;
|
||||
m_bStrafeRunning = false;
|
||||
m_iLastDeathSeen = 0;
|
||||
m_iSwearTime = 0;
|
||||
if (m_flTemperament <= 0.0f) m_flTemperament = 1.0f;
|
||||
m_flLastAggression = 0.5f;
|
||||
m_vWanderGoal = g_vecZero;
|
||||
m_iWanderTime = 0;
|
||||
m_vTravelSmooth = g_vecZero;
|
||||
m_iTravelSampleTime = 0;
|
||||
m_fTravelTurn = 0.0f;
|
||||
m_iLastBhopJump = 0;
|
||||
m_iMidairCrouchUntil = 0;
|
||||
m_iGrenadeThrowTime = 0;
|
||||
m_iGrenadeCookTime = 0;
|
||||
m_iReachCheckTime = 0;
|
||||
m_bEnemyHardToReach = false;
|
||||
m_pReachEnemy = NULL;
|
||||
|
||||
ResetWaypointVars();
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,9 @@ public:
|
||||
|
||||
// AI Functions
|
||||
virtual bool ChoosePreferredWeapon(void);
|
||||
bool ChooseEliteWeapon(void); // best+ weapon choice
|
||||
float ScoreWeapon(int iGun, float flDist);
|
||||
virtual void GetPreferredRange(float &flMinDist, float &flMaxDist);
|
||||
void Reload(int Gun);
|
||||
virtual entity *SearchForEnts(bool bUseWPs, float flRange=9999.0f,
|
||||
float flMaxHeight=JUMP_HEIGHT);
|
||||
|
||||
@@ -28,10 +28,152 @@ weaponinfo_s WeaponInfoTable[MAX_WEAPONS] =
|
||||
{ TYPE_AUTO, 0.0f, 50.0f, 3.0f, 50.0f, 0 } // AKIMBO
|
||||
};
|
||||
|
||||
// The best+ (elite) bots don't use the bonus-point scheme above: they weigh
|
||||
// every weapon on the damage it can actually land at the current distance.
|
||||
// flCloseRange/flFarRange are where the weapon starts/stop being useful,
|
||||
// flDps is the raw damage per second and flAccuracy is how much of that lands
|
||||
// at the ideal range (spread, recoil, travel time).
|
||||
struct elite_weaponinfo_s
|
||||
{
|
||||
float flCloseRange;
|
||||
float flIdealRange;
|
||||
float flFarRange;
|
||||
float flDps;
|
||||
float flAccuracy;
|
||||
};
|
||||
|
||||
static const elite_weaponinfo_s EliteWeaponInfo[MAX_WEAPONS] =
|
||||
{
|
||||
// ---- close -- ideal -- far ---- dps -- accuracy
|
||||
{ 0.0f, 1.5f, 3.5f, 100.0f, 0.95f }, // KNIFE
|
||||
{ 2.0f, 12.0f, 45.0f, 112.0f, 0.85f }, // PISTOL
|
||||
{ 4.0f, 22.0f, 60.0f, 83.0f, 0.90f }, // CARBINE
|
||||
{ 0.0f, 6.0f, 14.0f, 240.0f, 0.85f }, // SHOTGUN
|
||||
{ 0.0f, 10.0f, 30.0f, 190.0f, 0.80f }, // SUBGUN
|
||||
{ 12.0f, 50.0f, 160.0f, 70.0f, 0.95f }, // SNIPER
|
||||
{ 3.0f, 18.0f, 50.0f, 200.0f, 0.75f }, // ASSAULT
|
||||
{ 8.0f, 15.0f, 25.0f, 200.0f, 0.50f }, // GRENADE
|
||||
{ 0.0f, 8.0f, 25.0f, 200.0f, 0.60f } // AKIMBO
|
||||
};
|
||||
|
||||
// Code of CACBot - Start
|
||||
|
||||
void CACBot::GetPreferredRange(float &flMinDist, float &flMaxDist)
|
||||
{
|
||||
if (!m_pBotSkill->bSmartWeapons)
|
||||
{
|
||||
CBot::GetPreferredRange(flMinDist, flMaxDist);
|
||||
return;
|
||||
}
|
||||
|
||||
const elite_weaponinfo_s &info = EliteWeaponInfo[m_pMyEnt->gunselect];
|
||||
|
||||
// The range the bot actually wants to fight at, based on what the weapon
|
||||
// can do (not on the optimistic table the other skills use)
|
||||
flMinDist = info.flCloseRange;
|
||||
flMaxDist = min(info.flFarRange, info.flIdealRange * 2.0f);
|
||||
|
||||
if (flMaxDist < flMinDist + 1.0f)
|
||||
flMaxDist = flMinDist + 1.0f;
|
||||
}
|
||||
|
||||
float CACBot::ScoreWeapon(int iGun, float flDist)
|
||||
{
|
||||
const elite_weaponinfo_s &info = EliteWeaponInfo[iGun];
|
||||
|
||||
// An empty magazine is no weapon at all (the knife is the exception)
|
||||
if ((iGun != GUN_KNIFE) && !m_pMyEnt->mag[iGun])
|
||||
return -1.0f;
|
||||
|
||||
// A grenade is a tool, not a primary weapon: pull it out when the throw
|
||||
// makes sense, throw it and switch straight back to a gun
|
||||
if (iGun == GUN_GRENADE)
|
||||
{
|
||||
if (!m_pBotSkill->bSmartGrenades || !ShouldThrowGrenade(flDist))
|
||||
return -1.0f;
|
||||
|
||||
return 250.0f;
|
||||
}
|
||||
|
||||
float flRangeFactor;
|
||||
|
||||
// Full damage in the ideal window, a steep drop outside of it
|
||||
if ((flDist < info.flCloseRange) || (flDist > info.flFarRange))
|
||||
flRangeFactor = 0.1f;
|
||||
else if (flDist < info.flIdealRange)
|
||||
flRangeFactor = 0.1f + 0.9f * ((flDist - info.flCloseRange) /
|
||||
(info.flIdealRange - info.flCloseRange));
|
||||
else
|
||||
flRangeFactor = 1.0f - 0.9f * ((flDist - info.flIdealRange) /
|
||||
(info.flFarRange - info.flIdealRange));
|
||||
|
||||
float flScore = info.flDps * info.flAccuracy * flRangeFactor;
|
||||
|
||||
// The weapon we already hold has no switch delay
|
||||
if (iGun == m_pMyEnt->gunselect)
|
||||
flScore *= 1.15f;
|
||||
|
||||
// Reloading in the middle of a fight is a waste of a magazine
|
||||
if (m_pMyEnt->weapons[iGun] && m_pMyEnt->weapons[iGun]->reloading)
|
||||
flScore *= 0.25f;
|
||||
|
||||
// Running dry hurts: save the last rounds for when they matter
|
||||
if ((iGun != GUN_KNIFE) && (iGun != GUN_GRENADE) &&
|
||||
(m_pMyEnt->ammo[iGun] <= 0) && (m_pMyEnt->mag[iGun] <= 2))
|
||||
flScore *= 0.5f;
|
||||
|
||||
// Being able to finish the enemy with a single shot is worth setting up
|
||||
if (m_pMyEnt->enemy && (m_pMyEnt->enemy->health <= guns[iGun].damage))
|
||||
flScore *= 1.3f;
|
||||
|
||||
return flScore;
|
||||
}
|
||||
|
||||
bool CACBot::ChooseEliteWeapon()
|
||||
{
|
||||
if (!m_pMyEnt->enemy)
|
||||
return false;
|
||||
|
||||
// Keep the grenade in hand while a throw is being lined up: switching away
|
||||
// lets go of it in whatever direction the bot happens to be facing
|
||||
if (m_iGrenadeThrowTime > lastmillis)
|
||||
return true;
|
||||
|
||||
float flDist = GetDistance(m_pMyEnt->enemy->o);
|
||||
float flBestScore = ScoreWeapon(m_pMyEnt->gunselect, flDist);
|
||||
int iBestWeapon = m_pMyEnt->gunselect;
|
||||
|
||||
for (int i=0;i<MAX_WEAPONS;i++)
|
||||
{
|
||||
if (i == m_pMyEnt->gunselect) continue;
|
||||
if (!m_pMyEnt->weapons[i] || !m_pMyEnt->weapons[i]->selectable()) continue;
|
||||
|
||||
float flScore = ScoreWeapon(i, flDist);
|
||||
|
||||
// Only switch when the other weapon is clearly better: constantly
|
||||
// swapping guns costs more time than a slightly better range gives
|
||||
if (flScore > flBestScore * 1.15f)
|
||||
{
|
||||
flBestScore = flScore;
|
||||
iBestWeapon = i;
|
||||
}
|
||||
}
|
||||
|
||||
if ((iBestWeapon != m_pMyEnt->gunselect) && (lastmillis > m_iChangeWeaponDelay))
|
||||
SelectGun(iBestWeapon);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CACBot::ChoosePreferredWeapon()
|
||||
{
|
||||
if (m_pBotSkill->bSmartWeapons)
|
||||
return ChooseEliteWeapon();
|
||||
|
||||
// Same hold while the pin is out
|
||||
if (m_iGrenadeThrowTime > lastmillis)
|
||||
return true;
|
||||
|
||||
short bestWeapon = m_pMyEnt->gunselect;
|
||||
short bestWeaponScore = 0;
|
||||
|
||||
@@ -79,7 +221,13 @@ bool CACBot::ChoosePreferredWeapon()
|
||||
|
||||
if(i == GUN_GRENADE)
|
||||
{
|
||||
sWeaponScore += 30; // Nades have high priority
|
||||
// Nades have high priority, but only when the throw is worth it:
|
||||
// a grenade chosen just because it scores well is a grenade the
|
||||
// bot holds while doing nothing else
|
||||
if (!ShouldThrowGrenade(flDist))
|
||||
continue;
|
||||
|
||||
sWeaponScore += 30;
|
||||
}
|
||||
|
||||
// The ideal distance would be between the Min and Max desired distance.
|
||||
@@ -338,6 +486,12 @@ bool CACBot::HeadToTargetEnt()
|
||||
if (!bToHigh)
|
||||
{
|
||||
AimToVec(o);
|
||||
|
||||
// Elite bots strafe-run to the item and walk around the
|
||||
// geometry instead of into it
|
||||
if (m_pBotSkill->bSmartMovement)
|
||||
SteerTo(o, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+121
-2
@@ -84,15 +84,85 @@ void CBot::Spawn()
|
||||
|
||||
m_vGoal = m_vWaterGoal = g_vecZero;
|
||||
|
||||
m_iLastHealth = m_pMyEnt->health;
|
||||
m_iDodgeTime = 0;
|
||||
m_iDodgeDir = DIR_NONE;
|
||||
m_iGrenadeDelay = 0;
|
||||
m_iStrafeSide = DIR_NONE;
|
||||
m_iStrafeSideTime = 0;
|
||||
m_iSteerSide = DIR_NONE;
|
||||
m_iSteerSideTime = 0;
|
||||
m_iSteerDir = DIR_NONE;
|
||||
m_bStrafeRunning = false;
|
||||
m_iLastDeathSeen = 0;
|
||||
m_iSwearTime = 0;
|
||||
if (m_flTemperament <= 0.0f) m_flTemperament = 1.0f;
|
||||
m_flLastAggression = 0.5f;
|
||||
m_vWanderGoal = g_vecZero;
|
||||
m_iWanderTime = 0;
|
||||
m_vTravelSmooth = g_vecZero;
|
||||
m_iTravelSampleTime = 0;
|
||||
m_fTravelTurn = 0.0f;
|
||||
m_iLastBhopJump = 0;
|
||||
m_iMidairCrouchUntil = 0;
|
||||
m_iGrenadeThrowTime = 0;
|
||||
m_iGrenadeCookTime = 0;
|
||||
m_iReachCheckTime = 0;
|
||||
m_bEnemyHardToReach = false;
|
||||
m_pReachEnemy = NULL;
|
||||
|
||||
ResetWaypointVars();
|
||||
}
|
||||
|
||||
static bool PlayerWonMatch(void)
|
||||
{
|
||||
// Did our player just win the game? Same ordering the scoreboard uses:
|
||||
// flags first in flag modes, then frags, then deaths.
|
||||
if (!player1 || (player1->team == TEAM_SPECT))
|
||||
return false;
|
||||
|
||||
if (!m_teammode) // deathmatch: the player has to be top of the board
|
||||
{
|
||||
int iBest = player1->frags;
|
||||
|
||||
loopv(bots) if (bots[i] && (bots[i] != player1) && (bots[i]->frags > iBest)) return false;
|
||||
loopv(players) if (players[i] && (players[i] != player1) && (players[i]->frags > iBest)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int iScores[4];
|
||||
calcteamscores(iScores);
|
||||
|
||||
int iMine = team_base(player1->team), iTheirs = iMine ? 0 : 1;
|
||||
|
||||
if (m_flags_ && (iScores[iMine] != iScores[iTheirs]))
|
||||
return iScores[iMine] > iScores[iTheirs];
|
||||
|
||||
return iScores[iMine + 2] > iScores[iTheirs + 2];
|
||||
}
|
||||
|
||||
void CBot::Think()
|
||||
{
|
||||
if (intermission) return;
|
||||
// Bot is dead?
|
||||
if (m_pMyEnt->state == CS_DEAD)
|
||||
{
|
||||
// Dying is frustrating: once in a while a bot lets it out in chat.
|
||||
// lastdeath (instead of the dead state) so it happens once per death,
|
||||
// not on every frame the corpse is lying there.
|
||||
if (m_pMyEnt->lastdeath != m_iLastDeathSeen)
|
||||
{
|
||||
m_iLastDeathSeen = m_pMyEnt->lastdeath;
|
||||
m_iSwearTime = lastmillis + RandomLong(600, 1600); // a beat, like a real player
|
||||
}
|
||||
|
||||
if (m_iSwearTime && (m_iSwearTime <= lastmillis))
|
||||
{
|
||||
m_iSwearTime = 0;
|
||||
SwearOnDeath();
|
||||
}
|
||||
|
||||
if(lastmillis-m_pMyEnt->lastdeath<1200)
|
||||
{
|
||||
m_pMyEnt->move = 0;
|
||||
@@ -130,6 +200,50 @@ void CBot::Think()
|
||||
SendBotInfo();
|
||||
}
|
||||
|
||||
void CBot::SwearOnDeath(void)
|
||||
{
|
||||
static const char *szCurses[] =
|
||||
{
|
||||
"блядь",
|
||||
"сука",
|
||||
"чёрт",
|
||||
"пиздец",
|
||||
"блин",
|
||||
"ёбаный рот",
|
||||
"твою мать",
|
||||
"заебало",
|
||||
"ну и хуйня",
|
||||
"охренеть",
|
||||
"блять, ну как так",
|
||||
"сука, кемпер",
|
||||
"ну нихуя себе",
|
||||
"да ёб твою мать"
|
||||
};
|
||||
|
||||
// Bots that have spent the whole game in somebody's face take it worst:
|
||||
// roughly 3.5% for a cautious one, 10% for a madman (mean about 5%)
|
||||
float flChance = 2.5f + 7.5f * m_flLastAggression;
|
||||
|
||||
// And handing our player the match deserves a little extra
|
||||
if (intermission && PlayerWonMatch())
|
||||
flChance *= 1.5f;
|
||||
|
||||
if (RandomLong(1, 1000) > int(flChance * 10.0f))
|
||||
return;
|
||||
|
||||
SayText(szCurses[RandomLong(0, sizeof(szCurses)/sizeof(szCurses[0]) - 1)]);
|
||||
}
|
||||
|
||||
void CBot::SayText(const char *text)
|
||||
{
|
||||
// Same formatting the client uses for a chat line from another player, so
|
||||
// it lands in the chat where everybody else's messages do
|
||||
if (!text || !*text)
|
||||
return;
|
||||
|
||||
conoutf("%s:\f0 %s", colorname(m_pMyEnt), highlight(text));
|
||||
}
|
||||
|
||||
void CBot::AimToVec(const vec &o)
|
||||
{
|
||||
m_pMyEnt->targetpitch = atan2(o.z-m_pMyEnt->o.z, GetDistance(o))*180/PI;
|
||||
@@ -283,6 +397,11 @@ float CBot::GetDistance(entity *e)
|
||||
bool CBot::SelectGun(int Gun)
|
||||
{
|
||||
if(!m_pMyEnt->weapons[Gun]->selectable()) return false;
|
||||
// A grenade with the pin out cannot be put away: the switch would leave the
|
||||
// live grenade behind at the world origin. ReleaseCookedGrenade() throws it
|
||||
// as soon as the aim is no longer being kept up.
|
||||
if(m_pMyEnt->weaponsel && (m_pMyEnt->weaponsel->type == GUN_GRENADE) &&
|
||||
(((grenades *)m_pMyEnt->weaponsel)->state == GST_INHAND)) return false;
|
||||
if(m_pMyEnt->weaponsel->reloading || m_pMyEnt->weaponchanging) return false;
|
||||
m_pMyEnt->gunselect = Gun;
|
||||
if(m_pMyEnt->weaponsel->type != Gun)
|
||||
@@ -359,14 +478,14 @@ void CBot::SetMoveDir(int iMoveDir, bool add)
|
||||
{
|
||||
if (iMoveDir & FORWARD)
|
||||
m_pMyEnt->move = 1;
|
||||
else if (m_iMoveDir & BACKWARD)
|
||||
else if (iMoveDir & BACKWARD)
|
||||
m_pMyEnt->move = -1;
|
||||
else if (!add)
|
||||
m_pMyEnt->move = 0;
|
||||
|
||||
if (iMoveDir & LEFT)
|
||||
m_pMyEnt->strafe = 1;
|
||||
else if (m_iMoveDir & RIGHT)
|
||||
else if (iMoveDir & RIGHT)
|
||||
m_pMyEnt->strafe = -1;
|
||||
else if (!add)
|
||||
m_pMyEnt->strafe = 0;
|
||||
|
||||
+63
-3
@@ -103,6 +103,12 @@ struct bot_skill_s
|
||||
bool bCanPredict; // Can this bot predict his enemy position?
|
||||
bool bCircleStrafe; // Can this bot circle strafe?
|
||||
bool bCanSearchItemsInCombat;
|
||||
// The following are only enabled for the elite ("best+") skill
|
||||
bool bSmartMovement; // Steer around walls and use diagonal movement for speed
|
||||
bool bSmartWeapons; // Weigh weapons on what they can actually do at this range
|
||||
bool bSmartGrenades; // Only throw grenades when they are useful (and won't hurt us)
|
||||
bool bSmartTargeting; // Pick targets on threat instead of distance only
|
||||
bool bDodgeFire; // React to being shot at
|
||||
};
|
||||
|
||||
enum EBotWeaponTypes
|
||||
@@ -148,6 +154,10 @@ public:
|
||||
botent *m_pMyEnt;
|
||||
int m_iLastBotUpdate;
|
||||
|
||||
// Rolled once when the bot is created, so it keeps its own streak for the
|
||||
// whole game instead of drawing a new character every respawn
|
||||
void RollTemperament(void) { m_flTemperament = RandomFloat(0.6f, 1.4f); }
|
||||
|
||||
// Combat variabels
|
||||
playerent *m_pPrevEnemy;
|
||||
int m_iShootDelay;
|
||||
@@ -212,7 +222,35 @@ public:
|
||||
int m_iAimDelay;
|
||||
float m_fYawToTurn, m_fPitchToTurn;
|
||||
bot_skill_s *m_pBotSkill; // Pointer to current bot skill
|
||||
short m_sSkillNr; // Skill number, 0 == best 4 == worst
|
||||
short m_sSkillNr; // Skill number, 0 == best+ 5 == worst
|
||||
|
||||
// Elite (best+) behaviour
|
||||
int m_iLastHealth; // Health at the last think, used to notice getting shot
|
||||
int m_iDodgeTime; // Dodge until this time
|
||||
int m_iDodgeDir; // Direction to dodge in
|
||||
int m_iGrenadeDelay; // Don't spam grenades
|
||||
int m_iStrafeSide; // Side the bot is currently circling to (LEFT or RIGHT)
|
||||
int m_iStrafeSideTime; // Time to reconsider the circling side
|
||||
int m_iSteerSide; // Side the bot strafe-runs on (LEFT or RIGHT)
|
||||
int m_iSteerSideTime; // Time to reconsider the strafe-run side
|
||||
int m_iSteerDir; // Movement keys the steering picked last frame
|
||||
bool m_bStrafeRunning; // Sprinting with two keys at the moment
|
||||
vec m_vWanderGoal; // Where to head when there is no waypoint to follow
|
||||
int m_iWanderTime; // When to pick a new wander goal
|
||||
vec m_vTravelSmooth; // Travel direction a moment ago (how straight are we going)
|
||||
int m_iTravelSampleTime; // When to take the next straightness sample
|
||||
float m_fTravelTurn; // Degrees turned in the last sample window
|
||||
int m_iLastBhopJump; // Last hop, so the mid-air crouch knows how long we are up
|
||||
int m_iMidairCrouchUntil; // Hold the show-off tuck until this (never past the landing)
|
||||
int m_iGrenadeThrowTime; // Lining up a throw: stand still until this
|
||||
int m_iGrenadeCookTime; // When the pin came out (0 = nothing in hand)
|
||||
int m_iReachCheckTime; // When to look again at whether the enemy is reachable
|
||||
bool m_bEnemyHardToReach; // Result of that check
|
||||
playerent *m_pReachEnemy; // Which enemy the check was about
|
||||
int m_iLastDeathSeen; // lastdeath of the last death we reacted to
|
||||
int m_iSwearTime; // When the bot lets out its death curse (0 = nothing pending)
|
||||
float m_flTemperament; // Personal streak: some bots push, some play it safe
|
||||
float m_flLastAggression; // Aggression on the last living frame
|
||||
|
||||
void AimToVec(const vec &o);
|
||||
void AimToIdeal(void);
|
||||
@@ -267,6 +305,28 @@ public:
|
||||
bool InUnreachableList(entity *e);
|
||||
virtual bool DoSPStuff(void) = 0;
|
||||
vec GetEnemyPos(playerent *d);
|
||||
// Elite (best+) behaviour
|
||||
void MoveDirToVec(int iDir, vec &vDir);
|
||||
float GetMoveClearance(const vec &vDir, float flDist);
|
||||
int SteerTo(const vec &vGoal, bool bStrafeRun = false, bool bAllowBackward = true);
|
||||
vec GetNadeRepulsion(void);
|
||||
void BhopAlongLine(bool bStraight, float flGoalDist);
|
||||
vec GetClearDirection(const vec &vWant, float flDist);
|
||||
playerent *GetGrenadeThrower(void);
|
||||
bool EnemyIsHardToReach(playerent *pEnemy);
|
||||
bool IsCookingGrenadeAtMe(playerent *d);
|
||||
float GetAggression(void);
|
||||
void SwearOnDeath(void);
|
||||
int CountEnemiesNear(float flRadius);
|
||||
void SayText(const char *text);
|
||||
void DoSmartCombatNav(void);
|
||||
bool ShouldThrowGrenade(float flDist, playerent *pAimAt = NULL);
|
||||
bool ThrowGrenade(playerent *pTarget);
|
||||
void ReleaseCookedGrenade(void);
|
||||
float GetGrenadeLobPitch(float flDist, float flHeight, float &flFlight);
|
||||
void AvoidGrenades(void);
|
||||
int GetEnemyScore(playerent *d, float flDist);
|
||||
virtual void GetPreferredRange(float &flMinDist, float &flMaxDist);
|
||||
bool AStar(void);
|
||||
float AStarCost(waypoint_s *pWP1, waypoint_s *pWP2);
|
||||
void CleanAStarLists(bool bPathFailed);
|
||||
@@ -330,10 +390,10 @@ class CBotManager
|
||||
bool m_bInit;
|
||||
bool m_bBotsShoot;
|
||||
bool m_bIdleBots;
|
||||
bot_skill_s m_BotSkills[5]; // 5 different bot skills, 0 = best 4 = worst
|
||||
bot_skill_s m_BotSkills[6]; // 6 different bot skills, 0 = best+ 5 = worst
|
||||
int m_iFrameTime;
|
||||
int m_iPrevTime;
|
||||
short m_sBotSkill; // Bad - Worse - Medium - Good - Best
|
||||
short m_sBotSkill; // Bad - Worse - Medium - Good - Best - Best+
|
||||
short m_sMaxAStarBots; // Max bots that can use a* at the same time
|
||||
short m_sUsingAStarBotsCount; // Number of bots that are using a*
|
||||
short m_sCurrentTriggerNr; // Current waypoint trigger bots should use
|
||||
|
||||
+1229
-40
File diff suppressed because it is too large
Load Diff
@@ -450,11 +450,12 @@ float GetCubeHeight(int x, int y)
|
||||
|
||||
const char *SkillNrToSkillName(short skillnr)
|
||||
{
|
||||
if (skillnr == 0) return "best";
|
||||
else if (skillnr == 1) return "good";
|
||||
else if (skillnr == 2) return "medium";
|
||||
else if (skillnr == 3) return "worse";
|
||||
else if (skillnr == 4) return "bad";
|
||||
if (skillnr == 0) return "best+";
|
||||
else if (skillnr == 1) return "best";
|
||||
else if (skillnr == 2) return "good";
|
||||
else if (skillnr == 3) return "medium";
|
||||
else if (skillnr == 4) return "worse";
|
||||
else if (skillnr == 5) return "bad";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1965,8 +1965,11 @@ bool CBot::FindWaypoint()
|
||||
|
||||
// about 20% of the time choose a waypoint at random
|
||||
// (don't do this any more often than every 10 seconds)
|
||||
// Elite bots should look purposeful, so they do this far less often
|
||||
|
||||
if ((RandomLong(1, 100) <= 20) && (m_iRandomWaypointTime <= lastmillis))
|
||||
short sRandomPercent = m_pBotSkill->bSmartMovement ? 5 : 20;
|
||||
|
||||
if ((RandomLong(1, 100) <= sRandomPercent) && (m_iRandomWaypointTime <= lastmillis))
|
||||
{
|
||||
m_iRandomWaypointTime = lastmillis + 10000;
|
||||
|
||||
@@ -2148,11 +2151,41 @@ bool CBot::HeadToWaypoint()
|
||||
m_iWaypointTime += 200;
|
||||
}
|
||||
|
||||
if (m_iWaypointHeadPauseTime >= lastmillis)
|
||||
// Elite bots keep moving while they turn: the steering below decides what
|
||||
// is safe to do
|
||||
if (!m_pBotSkill->bSmartMovement && (m_iWaypointHeadPauseTime >= lastmillis))
|
||||
{
|
||||
m_pMyEnt->move = 0;
|
||||
//conoutf("Pause in HeadToWaypoint()");
|
||||
}
|
||||
else if (m_pBotSkill->bSmartMovement)
|
||||
{
|
||||
vec vGoal = m_pCurrentWaypoint->pNode->v_origin;
|
||||
vec vDir = vGoal;
|
||||
vDir.sub(m_pMyEnt->o);
|
||||
vDir.z = 0.0f;
|
||||
|
||||
float flGoalDist = vDir.magnitude();
|
||||
|
||||
if (flGoalDist > 1.0f)
|
||||
{
|
||||
vDir.div(flGoalDist);
|
||||
|
||||
// Low wall on the way? Hop it. Anything higher is walked around
|
||||
// by the steering below, so the bot stops bumping into things.
|
||||
float flClear = GetMoveClearance(vDir, 3.0f);
|
||||
|
||||
if ((flClear < 3.0f) && (flGoalDist > flClear))
|
||||
{
|
||||
m_pMyEnt->jumpnext = true;
|
||||
condebug("Low wall in HeadToWaypoint()");
|
||||
}
|
||||
}
|
||||
|
||||
// Strafe-run: two keys are ~1.4x faster, and the 45 degree aim offset
|
||||
// makes the combined movement point straight at the waypoint
|
||||
SteerTo(vGoal, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if bot has to jump
|
||||
@@ -2664,6 +2697,8 @@ void CBot::ResetWaypointVars()
|
||||
m_AStarNodeList.DeleteAllNodes();
|
||||
CleanAStarLists(false);
|
||||
m_bGoToDebugGoal = false;
|
||||
m_vWanderGoal = g_vecZero;
|
||||
m_iWanderTime = 0;
|
||||
}
|
||||
|
||||
void CBot::SetCurrentWaypoint(node_s *pNode)
|
||||
|
||||
+174
-108
@@ -31,7 +31,7 @@ void CBotManager::Init()
|
||||
|
||||
m_iFrameTime = 0;
|
||||
m_iPrevTime = lastmillis;
|
||||
m_sBotSkill = 1; // Default all bots have the skill 'Good'
|
||||
m_sBotSkill = 2; // Default all bots have the skill 'Good'
|
||||
|
||||
CreateSkillData();
|
||||
LoadBotNamesFile();
|
||||
@@ -543,6 +543,8 @@ void CBotManager::CreateSkillData()
|
||||
SkillNr = 3;
|
||||
else if (strcasecmp(cmd, "[SKILL5]") == 0)
|
||||
SkillNr = 4;
|
||||
else if (strcasecmp(cmd, "[SKILL6]") == 0)
|
||||
SkillNr = 5;
|
||||
|
||||
if ((arg1 == NULL) || (*arg1 == 0))
|
||||
continue;
|
||||
@@ -628,6 +630,26 @@ void CBotManager::CreateSkillData()
|
||||
{
|
||||
m_BotSkills[SkillNr].bCanSearchItemsInCombat = value!=0;
|
||||
}
|
||||
else if (strcasecmp(cmd, "smart_movement") == 0)
|
||||
{
|
||||
m_BotSkills[SkillNr].bSmartMovement = value!=0;
|
||||
}
|
||||
else if (strcasecmp(cmd, "smart_weapons") == 0)
|
||||
{
|
||||
m_BotSkills[SkillNr].bSmartWeapons = value!=0;
|
||||
}
|
||||
else if (strcasecmp(cmd, "smart_grenades") == 0)
|
||||
{
|
||||
m_BotSkills[SkillNr].bSmartGrenades = value!=0;
|
||||
}
|
||||
else if (strcasecmp(cmd, "smart_targeting") == 0)
|
||||
{
|
||||
m_BotSkills[SkillNr].bSmartTargeting = value!=0;
|
||||
}
|
||||
else if (strcasecmp(cmd, "dodge_fire") == 0)
|
||||
{
|
||||
m_BotSkills[SkillNr].bDodgeFire = value!=0;
|
||||
}
|
||||
}
|
||||
|
||||
conoutf("done");
|
||||
@@ -635,120 +657,160 @@ void CBotManager::CreateSkillData()
|
||||
|
||||
void CBotManager::InitSkillData()
|
||||
{
|
||||
// Best skill
|
||||
m_BotSkills[0].flMinReactionDelay = 0.015f;
|
||||
m_BotSkills[0].flMaxReactionDelay = 0.035f;
|
||||
m_BotSkills[0].flMinAimXOffset = 15.0f;
|
||||
m_BotSkills[0].flMaxAimXOffset = 20.0f;
|
||||
m_BotSkills[0].flMinAimYOffset = 10.0f;
|
||||
m_BotSkills[0].flMaxAimYOffset = 15.0f;
|
||||
m_BotSkills[0].flMinAimXSpeed = 330.0f;
|
||||
m_BotSkills[0].flMaxAimXSpeed = 355.0f;
|
||||
m_BotSkills[0].flMinAimYSpeed = 400.0f;
|
||||
m_BotSkills[0].flMaxAimYSpeed = 450.0f;
|
||||
m_BotSkills[0].flMinAttackDelay = 0.1f;
|
||||
m_BotSkills[0].flMaxAttackDelay = 0.4f;
|
||||
m_BotSkills[0].flMinEnemySearchDelay = 0.09f;
|
||||
m_BotSkills[0].flMaxEnemySearchDelay = 0.12f;
|
||||
m_BotSkills[0].flAlwaysDetectDistance = 12.0f;
|
||||
// The elite features are only enabled for the best+ skill below
|
||||
for (int i=0;i<6;i++)
|
||||
{
|
||||
m_BotSkills[i].bSmartMovement = false;
|
||||
m_BotSkills[i].bSmartWeapons = false;
|
||||
m_BotSkills[i].bSmartGrenades = false;
|
||||
m_BotSkills[i].bSmartTargeting = false;
|
||||
m_BotSkills[i].bDodgeFire = false;
|
||||
}
|
||||
|
||||
// Best+ skill (elite)
|
||||
m_BotSkills[0].flMinReactionDelay = 0.005f;
|
||||
m_BotSkills[0].flMaxReactionDelay = 0.015f;
|
||||
m_BotSkills[0].flMinAimXOffset = 0.0f;
|
||||
m_BotSkills[0].flMaxAimXOffset = 2.0f;
|
||||
m_BotSkills[0].flMinAimYOffset = 0.0f;
|
||||
m_BotSkills[0].flMaxAimYOffset = 2.0f;
|
||||
m_BotSkills[0].flMinAimXSpeed = 450.0f;
|
||||
m_BotSkills[0].flMaxAimXSpeed = 520.0f;
|
||||
m_BotSkills[0].flMinAimYSpeed = 500.0f;
|
||||
m_BotSkills[0].flMaxAimYSpeed = 560.0f;
|
||||
m_BotSkills[0].flMinAttackDelay = 0.02f;
|
||||
m_BotSkills[0].flMaxAttackDelay = 0.08f;
|
||||
m_BotSkills[0].flMinEnemySearchDelay = 0.04f;
|
||||
m_BotSkills[0].flMaxEnemySearchDelay = 0.07f;
|
||||
m_BotSkills[0].flAlwaysDetectDistance = 20.0f;
|
||||
m_BotSkills[0].bCanPredict = true;
|
||||
m_BotSkills[0].iMaxHearVolume = 75;
|
||||
m_BotSkills[0].iFov = 200;
|
||||
m_BotSkills[0].iMaxHearVolume = 100;
|
||||
m_BotSkills[0].iFov = 240;
|
||||
m_BotSkills[0].bCircleStrafe = true;
|
||||
m_BotSkills[0].bCanSearchItemsInCombat = true;
|
||||
m_BotSkills[0].bSmartMovement = true;
|
||||
m_BotSkills[0].bSmartWeapons = true;
|
||||
m_BotSkills[0].bSmartGrenades = true;
|
||||
m_BotSkills[0].bSmartTargeting = true;
|
||||
m_BotSkills[0].bDodgeFire = true;
|
||||
|
||||
// Good skill
|
||||
m_BotSkills[1].flMinReactionDelay = 0.035f;
|
||||
m_BotSkills[1].flMaxReactionDelay = 0.045f;
|
||||
m_BotSkills[1].flMinAimXOffset = 20.0f;
|
||||
m_BotSkills[1].flMaxAimXOffset = 25.0f;
|
||||
m_BotSkills[1].flMinAimYOffset = 15.0f;
|
||||
m_BotSkills[1].flMaxAimYOffset = 20.0f;
|
||||
m_BotSkills[1].flMinAimXSpeed = 250.0f;
|
||||
m_BotSkills[1].flMaxAimXSpeed = 265.0f;
|
||||
m_BotSkills[1].flMinAimYSpeed = 260.0f;
|
||||
m_BotSkills[1].flMaxAimYSpeed = 285.0f;
|
||||
m_BotSkills[1].flMinAttackDelay = 0.3f;
|
||||
m_BotSkills[1].flMaxAttackDelay = 0.6f;
|
||||
m_BotSkills[1].flMinEnemySearchDelay = 0.12f;
|
||||
m_BotSkills[1].flMaxEnemySearchDelay = 0.17f;
|
||||
m_BotSkills[1].flAlwaysDetectDistance = 10.0f;
|
||||
// Best skill
|
||||
m_BotSkills[1].flMinReactionDelay = 0.015f;
|
||||
m_BotSkills[1].flMaxReactionDelay = 0.035f;
|
||||
m_BotSkills[1].flMinAimXOffset = 15.0f;
|
||||
m_BotSkills[1].flMaxAimXOffset = 20.0f;
|
||||
m_BotSkills[1].flMinAimYOffset = 10.0f;
|
||||
m_BotSkills[1].flMaxAimYOffset = 15.0f;
|
||||
m_BotSkills[1].flMinAimXSpeed = 330.0f;
|
||||
m_BotSkills[1].flMaxAimXSpeed = 355.0f;
|
||||
m_BotSkills[1].flMinAimYSpeed = 400.0f;
|
||||
m_BotSkills[1].flMaxAimYSpeed = 450.0f;
|
||||
m_BotSkills[1].flMinAttackDelay = 0.1f;
|
||||
m_BotSkills[1].flMaxAttackDelay = 0.4f;
|
||||
m_BotSkills[1].flMinEnemySearchDelay = 0.09f;
|
||||
m_BotSkills[1].flMaxEnemySearchDelay = 0.12f;
|
||||
m_BotSkills[1].flAlwaysDetectDistance = 12.0f;
|
||||
m_BotSkills[1].bCanPredict = true;
|
||||
m_BotSkills[1].iMaxHearVolume = 60;
|
||||
m_BotSkills[1].iFov = 160;
|
||||
m_BotSkills[1].iMaxHearVolume = 75;
|
||||
m_BotSkills[1].iFov = 200;
|
||||
m_BotSkills[1].bCircleStrafe = true;
|
||||
m_BotSkills[1].bCanSearchItemsInCombat = true;
|
||||
|
||||
// Medium skill
|
||||
m_BotSkills[2].flMinReactionDelay = 0.075f;
|
||||
m_BotSkills[2].flMaxReactionDelay = 0.010f;
|
||||
m_BotSkills[2].flMinAimXOffset = 25.0f;
|
||||
m_BotSkills[2].flMaxAimXOffset = 30.0f;
|
||||
m_BotSkills[2].flMinAimYOffset = 20.0f;
|
||||
m_BotSkills[2].flMaxAimYOffset = 25.0f;
|
||||
m_BotSkills[2].flMinAimXSpeed = 190.0f;
|
||||
m_BotSkills[2].flMaxAimXSpeed = 125.0f;
|
||||
m_BotSkills[2].flMinAimYSpeed = 210.0f;
|
||||
m_BotSkills[2].flMaxAimYSpeed = 240.0f;
|
||||
m_BotSkills[2].flMinAttackDelay = 0.75f;
|
||||
m_BotSkills[2].flMaxAttackDelay = 1.0f;
|
||||
m_BotSkills[2].flMinEnemySearchDelay = 0.18f;
|
||||
m_BotSkills[2].flMaxEnemySearchDelay = 0.22f;
|
||||
m_BotSkills[2].flAlwaysDetectDistance = 8.0f;
|
||||
m_BotSkills[2].bCanPredict = false;
|
||||
m_BotSkills[2].iMaxHearVolume = 45;
|
||||
m_BotSkills[2].iFov = 130;
|
||||
// Good skill
|
||||
m_BotSkills[2].flMinReactionDelay = 0.035f;
|
||||
m_BotSkills[2].flMaxReactionDelay = 0.045f;
|
||||
m_BotSkills[2].flMinAimXOffset = 20.0f;
|
||||
m_BotSkills[2].flMaxAimXOffset = 25.0f;
|
||||
m_BotSkills[2].flMinAimYOffset = 15.0f;
|
||||
m_BotSkills[2].flMaxAimYOffset = 20.0f;
|
||||
m_BotSkills[2].flMinAimXSpeed = 250.0f;
|
||||
m_BotSkills[2].flMaxAimXSpeed = 265.0f;
|
||||
m_BotSkills[2].flMinAimYSpeed = 260.0f;
|
||||
m_BotSkills[2].flMaxAimYSpeed = 285.0f;
|
||||
m_BotSkills[2].flMinAttackDelay = 0.3f;
|
||||
m_BotSkills[2].flMaxAttackDelay = 0.6f;
|
||||
m_BotSkills[2].flMinEnemySearchDelay = 0.12f;
|
||||
m_BotSkills[2].flMaxEnemySearchDelay = 0.17f;
|
||||
m_BotSkills[2].flAlwaysDetectDistance = 10.0f;
|
||||
m_BotSkills[2].bCanPredict = true;
|
||||
m_BotSkills[2].iMaxHearVolume = 60;
|
||||
m_BotSkills[2].iFov = 160;
|
||||
m_BotSkills[2].bCircleStrafe = true;
|
||||
m_BotSkills[2].bCanSearchItemsInCombat = false;
|
||||
m_BotSkills[2].bCanSearchItemsInCombat = true;
|
||||
|
||||
// Worse skill
|
||||
m_BotSkills[3].flMinReactionDelay = 0.15f;
|
||||
m_BotSkills[3].flMaxReactionDelay = 0.20f;
|
||||
m_BotSkills[3].flMinAimXOffset = 30.0f;
|
||||
m_BotSkills[3].flMaxAimXOffset = 35.0f;
|
||||
m_BotSkills[3].flMinAimYOffset = 25.0f;
|
||||
m_BotSkills[3].flMaxAimYOffset = 30.0f;
|
||||
m_BotSkills[3].flMinAimXSpeed = 155.0f;
|
||||
m_BotSkills[3].flMaxAimXSpeed = 170.0f;
|
||||
m_BotSkills[3].flMinAimYSpeed = 160.0f;
|
||||
m_BotSkills[3].flMaxAimYSpeed = 210.0f;
|
||||
m_BotSkills[3].flMinAttackDelay = 1.2f;
|
||||
m_BotSkills[3].flMaxAttackDelay = 1.6f;
|
||||
m_BotSkills[3].flMinEnemySearchDelay = 0.25f;
|
||||
m_BotSkills[3].flMaxEnemySearchDelay = 0.30f;
|
||||
m_BotSkills[3].flAlwaysDetectDistance = 6.0f;
|
||||
// Medium skill
|
||||
m_BotSkills[3].flMinReactionDelay = 0.075f;
|
||||
m_BotSkills[3].flMaxReactionDelay = 0.010f;
|
||||
m_BotSkills[3].flMinAimXOffset = 25.0f;
|
||||
m_BotSkills[3].flMaxAimXOffset = 30.0f;
|
||||
m_BotSkills[3].flMinAimYOffset = 20.0f;
|
||||
m_BotSkills[3].flMaxAimYOffset = 25.0f;
|
||||
m_BotSkills[3].flMinAimXSpeed = 190.0f;
|
||||
m_BotSkills[3].flMaxAimXSpeed = 125.0f;
|
||||
m_BotSkills[3].flMinAimYSpeed = 210.0f;
|
||||
m_BotSkills[3].flMaxAimYSpeed = 240.0f;
|
||||
m_BotSkills[3].flMinAttackDelay = 0.75f;
|
||||
m_BotSkills[3].flMaxAttackDelay = 1.0f;
|
||||
m_BotSkills[3].flMinEnemySearchDelay = 0.18f;
|
||||
m_BotSkills[3].flMaxEnemySearchDelay = 0.22f;
|
||||
m_BotSkills[3].flAlwaysDetectDistance = 8.0f;
|
||||
m_BotSkills[3].bCanPredict = false;
|
||||
m_BotSkills[3].iMaxHearVolume = 30;
|
||||
m_BotSkills[3].iFov = 120;
|
||||
m_BotSkills[3].bCircleStrafe = false;
|
||||
m_BotSkills[3].iMaxHearVolume = 45;
|
||||
m_BotSkills[3].iFov = 130;
|
||||
m_BotSkills[3].bCircleStrafe = true;
|
||||
m_BotSkills[3].bCanSearchItemsInCombat = false;
|
||||
|
||||
// Bad skill
|
||||
m_BotSkills[4].flMinReactionDelay = 0.30f;
|
||||
m_BotSkills[4].flMaxReactionDelay = 0.50f;
|
||||
m_BotSkills[4].flMinAimXOffset = 35.0f;
|
||||
m_BotSkills[4].flMaxAimXOffset = 40.0f;
|
||||
m_BotSkills[4].flMinAimYOffset = 30.0f;
|
||||
m_BotSkills[4].flMaxAimYOffset = 35.0f;
|
||||
m_BotSkills[4].flMinAimXSpeed = 45.0f;
|
||||
m_BotSkills[4].flMaxAimXSpeed = 60.0f;
|
||||
m_BotSkills[4].flMinAimYSpeed = 125.0f;
|
||||
m_BotSkills[4].flMaxAimYSpeed = 180.0f;
|
||||
m_BotSkills[4].flMinAttackDelay = 1.5f;
|
||||
m_BotSkills[4].flMaxAttackDelay = 2.0f;
|
||||
m_BotSkills[4].flMinEnemySearchDelay = 0.30f;
|
||||
m_BotSkills[4].flMaxEnemySearchDelay = 0.36f;
|
||||
m_BotSkills[4].flAlwaysDetectDistance = 4.0f;
|
||||
// Worse skill
|
||||
m_BotSkills[4].flMinReactionDelay = 0.15f;
|
||||
m_BotSkills[4].flMaxReactionDelay = 0.20f;
|
||||
m_BotSkills[4].flMinAimXOffset = 30.0f;
|
||||
m_BotSkills[4].flMaxAimXOffset = 35.0f;
|
||||
m_BotSkills[4].flMinAimYOffset = 25.0f;
|
||||
m_BotSkills[4].flMaxAimYOffset = 30.0f;
|
||||
m_BotSkills[4].flMinAimXSpeed = 155.0f;
|
||||
m_BotSkills[4].flMaxAimXSpeed = 170.0f;
|
||||
m_BotSkills[4].flMinAimYSpeed = 160.0f;
|
||||
m_BotSkills[4].flMaxAimYSpeed = 210.0f;
|
||||
m_BotSkills[4].flMinAttackDelay = 1.2f;
|
||||
m_BotSkills[4].flMaxAttackDelay = 1.6f;
|
||||
m_BotSkills[4].flMinEnemySearchDelay = 0.25f;
|
||||
m_BotSkills[4].flMaxEnemySearchDelay = 0.30f;
|
||||
m_BotSkills[4].flAlwaysDetectDistance = 6.0f;
|
||||
m_BotSkills[4].bCanPredict = false;
|
||||
m_BotSkills[4].iMaxHearVolume = 15;
|
||||
m_BotSkills[4].iFov = 110;
|
||||
m_BotSkills[4].iMaxHearVolume = 30;
|
||||
m_BotSkills[4].iFov = 120;
|
||||
m_BotSkills[4].bCircleStrafe = false;
|
||||
m_BotSkills[4].bCanSearchItemsInCombat = false;
|
||||
|
||||
// Bad skill
|
||||
m_BotSkills[5].flMinReactionDelay = 0.30f;
|
||||
m_BotSkills[5].flMaxReactionDelay = 0.50f;
|
||||
m_BotSkills[5].flMinAimXOffset = 35.0f;
|
||||
m_BotSkills[5].flMaxAimXOffset = 40.0f;
|
||||
m_BotSkills[5].flMinAimYOffset = 30.0f;
|
||||
m_BotSkills[5].flMaxAimYOffset = 35.0f;
|
||||
m_BotSkills[5].flMinAimXSpeed = 45.0f;
|
||||
m_BotSkills[5].flMaxAimXSpeed = 60.0f;
|
||||
m_BotSkills[5].flMinAimYSpeed = 125.0f;
|
||||
m_BotSkills[5].flMaxAimYSpeed = 180.0f;
|
||||
m_BotSkills[5].flMinAttackDelay = 1.5f;
|
||||
m_BotSkills[5].flMaxAttackDelay = 2.0f;
|
||||
m_BotSkills[5].flMinEnemySearchDelay = 0.30f;
|
||||
m_BotSkills[5].flMaxEnemySearchDelay = 0.36f;
|
||||
m_BotSkills[5].flAlwaysDetectDistance = 4.0f;
|
||||
m_BotSkills[5].bCanPredict = false;
|
||||
m_BotSkills[5].iMaxHearVolume = 15;
|
||||
m_BotSkills[5].iFov = 110;
|
||||
m_BotSkills[5].bCircleStrafe = false;
|
||||
m_BotSkills[5].bCanSearchItemsInCombat = false;
|
||||
}
|
||||
|
||||
void CBotManager::ChangeBotSkill(short Skill, botent *bot)
|
||||
{
|
||||
static const char *SkillNames[5] = { "best", "good", "medium", "worse", "bad" };
|
||||
static const char *SkillNames[6] = { "best+", "best", "good", "medium", "worse", "bad" };
|
||||
|
||||
if ((Skill < 0) || (Skill > 5))
|
||||
return;
|
||||
|
||||
if (bot && bot->pBot)
|
||||
{
|
||||
@@ -898,15 +960,16 @@ botent *CBotManager::CreateBot(const char *team, const char *skill, const char *
|
||||
|
||||
if (skill && *skill && strcmp(skill, "random"))
|
||||
{
|
||||
if (!strcasecmp(skill, "best")) m->pBot->m_sSkillNr = 0;
|
||||
else if (!strcasecmp(skill, "good")) m->pBot->m_sSkillNr = 1;
|
||||
else if (!strcasecmp(skill, "medium")) m->pBot->m_sSkillNr = 2;
|
||||
else if (!strcasecmp(skill, "worse")) m->pBot->m_sSkillNr = 3;
|
||||
else if (!strcasecmp(skill, "bad")) m->pBot->m_sSkillNr = 4;
|
||||
if (!strcasecmp(skill, "best+")) m->pBot->m_sSkillNr = 0;
|
||||
else if (!strcasecmp(skill, "best")) m->pBot->m_sSkillNr = 1;
|
||||
else if (!strcasecmp(skill, "good")) m->pBot->m_sSkillNr = 2;
|
||||
else if (!strcasecmp(skill, "medium")) m->pBot->m_sSkillNr = 3;
|
||||
else if (!strcasecmp(skill, "worse")) m->pBot->m_sSkillNr = 4;
|
||||
else if (!strcasecmp(skill, "bad")) m->pBot->m_sSkillNr = 5;
|
||||
else
|
||||
{
|
||||
conoutf("Wrong skill specified. Should be best, good, medium, "
|
||||
"worse or bad");
|
||||
conoutf("Wrong skill specified. Should be best+, best, good, "
|
||||
"medium, worse or bad");
|
||||
conoutf("Using default skill instead...");
|
||||
m->pBot->m_sSkillNr = BotManager.m_sBotSkill;
|
||||
}
|
||||
@@ -917,6 +980,7 @@ botent *CBotManager::CreateBot(const char *team, const char *skill, const char *
|
||||
// Sync waypoints
|
||||
m->pBot->SyncWaypoints();
|
||||
m->pBot->Spawn();
|
||||
m->pBot->RollTemperament();
|
||||
bots.add(m);
|
||||
return m;
|
||||
}
|
||||
@@ -1075,19 +1139,21 @@ void botskill(char *bot, char *skill)
|
||||
|
||||
short SkillNr;
|
||||
|
||||
if (!strcasecmp(skill, "best"))
|
||||
if (!strcasecmp(skill, "best+"))
|
||||
SkillNr = 0;
|
||||
else if (!strcasecmp(skill, "good"))
|
||||
else if (!strcasecmp(skill, "best"))
|
||||
SkillNr = 1;
|
||||
else if (!strcasecmp(skill, "medium"))
|
||||
else if (!strcasecmp(skill, "good"))
|
||||
SkillNr = 2;
|
||||
else if (!strcasecmp(skill, "worse"))
|
||||
else if (!strcasecmp(skill, "medium"))
|
||||
SkillNr = 3;
|
||||
else if (!strcasecmp(skill, "bad"))
|
||||
else if (!strcasecmp(skill, "worse"))
|
||||
SkillNr = 4;
|
||||
else if (!strcasecmp(skill, "bad"))
|
||||
SkillNr = 5;
|
||||
else
|
||||
{
|
||||
conoutf("Wrong skill specified. Should be best, good, medium, worse or bad");
|
||||
conoutf("Wrong skill specified. Should be best+, best, good, medium, worse or bad");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,12 +41,14 @@ void throttle()
|
||||
enet_peer_throttle_configure(curpeer, throttle_interval*1000, throttle_accel, throttle_decel);
|
||||
}
|
||||
|
||||
string clientpassword = "";
|
||||
int connectrole = CR_DEFAULT;
|
||||
bool modprotocol = false;
|
||||
|
||||
void abortconnect()
|
||||
{
|
||||
if(!connpeer) return;
|
||||
clientpassword[0] = '\0';
|
||||
connectrole = CR_DEFAULT;
|
||||
if(connpeer->state!=ENET_PEER_STATE_DISCONNECTED) enet_peer_reset(connpeer);
|
||||
connpeer = NULL;
|
||||
@@ -63,6 +65,7 @@ void connectserv_(const char *servername, int serverport = 0, const char *passwo
|
||||
abortconnect();
|
||||
}
|
||||
connectrole = role;
|
||||
copystring(clientpassword, password ? password : "");
|
||||
ENetAddress address;
|
||||
address.port = serverport;
|
||||
|
||||
@@ -121,9 +124,9 @@ COMMANDN(connect, connectserv, "si");
|
||||
void connectadmin(char *servername, int *serverport, char *password)
|
||||
{
|
||||
modprotocol = false;
|
||||
connectserv_(servername, *serverport, NULL, CR_ADMIN);
|
||||
connectserv_(servername, *serverport, password, CR_ADMIN);
|
||||
}
|
||||
COMMAND(connectadmin, "si");
|
||||
COMMAND(connectadmin, "sis");
|
||||
|
||||
void lanconnect()
|
||||
{
|
||||
@@ -142,9 +145,9 @@ COMMANDN(modconnect, modconnectserv, "si");
|
||||
void modconnectadmin(char *servername, int *serverport, char *password)
|
||||
{
|
||||
modprotocol = true;
|
||||
connectserv_(servername, *serverport, NULL, CR_ADMIN);
|
||||
connectserv_(servername, *serverport, password, CR_ADMIN);
|
||||
}
|
||||
COMMAND(modconnectadmin, "si");
|
||||
COMMAND(modconnectadmin, "sis");
|
||||
|
||||
void modlanconnect()
|
||||
{
|
||||
@@ -511,9 +514,10 @@ void sendintro()
|
||||
putint(p, AC_VERSION);
|
||||
putint(p, getbuildtype());
|
||||
sendstring(player1->name, p);
|
||||
sendstring("", p);
|
||||
sendstring(genpwdhash(player1->name, clientpassword, sessionid), p);
|
||||
sendstring(!lang || strlen(lang) != 2 ? "" : lang, p);
|
||||
putint(p, connectrole);
|
||||
clientpassword[0] = '\0';
|
||||
connectrole = CR_DEFAULT;
|
||||
putint(p, player1->nextprimweap->type);
|
||||
loopi(2) putint(p, player1->skin(i));
|
||||
|
||||
@@ -432,9 +432,10 @@ extern int matchsourcephysics;
|
||||
static inline void sourcefriction(vec &vel, float dt)
|
||||
{
|
||||
float speed = vel.magnitudexy();
|
||||
if(speed < 0.01f) return;
|
||||
if(speed <= 0.0f) return;
|
||||
float control = max(speed, SRC_STOPSPEED);
|
||||
float newspeed = max(speed - control*SRC_FRICTION*dt, 0.0f) / speed;
|
||||
if(newspeed <= 0.0f) { vel.x = vel.y = 0.0f; return; } // stop completely - no residual gliding at low speed
|
||||
vel.x *= newspeed;
|
||||
vel.y *= newspeed;
|
||||
}
|
||||
@@ -471,6 +472,7 @@ void moveplayer(physent *pl, int moveres, bool local, int curtime)
|
||||
vec d; // vector of direction we ideally want to move in
|
||||
|
||||
float drop = 0, rise = 0;
|
||||
float srcspeed = 1.0f; // displacement per unit of velocity, to convert d back to velocity (Source physics)
|
||||
|
||||
if(pl->type==ENT_BOUNCE)
|
||||
{
|
||||
@@ -521,6 +523,7 @@ void moveplayer(physent *pl, int moveres, bool local, int curtime)
|
||||
}
|
||||
|
||||
const float speed = curtime/(water ? 2000.0f : 1000.0f)*pl->maxspeed*weaponspeedmul*(matchspeedmul ? matchspeedmul / 100.0f : 1.0f)*(crouching && pl->state != CS_EDITING ? chspeed : 1.0f)*(pl==player1 && isfly ? flyspeed : 1.0f);
|
||||
srcspeed = speed;
|
||||
// the constants below are really "inertia" (higher = slides more), so more friction means dividing them
|
||||
const float friction = (water ? 20.0f : (pl->onfloor || isfly ? 6.0f : (pl->onladder ? 1.5f : 30.0f))) * 100.0f / clamp(matchfriction, 10, 500);
|
||||
const float fpsfric = max(friction/curtime*20.0f, 1.0f);
|
||||
@@ -786,6 +789,7 @@ void moveplayer(physent *pl, int moveres, bool local, int curtime)
|
||||
if(!collide(pl, false, drop, rise))
|
||||
{
|
||||
d.x = vd.x; d.y = vd.y;
|
||||
if(srcphys && srcspeed > 1e-6f) { pl->vel.x = vd.x/srcspeed; pl->vel.y = vd.y/srcspeed; } // slide along the corner, don't keep the velocity into it
|
||||
continue;
|
||||
}
|
||||
pl->o = o_nullxy;
|
||||
@@ -796,6 +800,7 @@ void moveplayer(physent *pl, int moveres, bool local, int curtime)
|
||||
{
|
||||
d.x = 0;
|
||||
if(pl->type==ENT_BOUNCE) { pl->vel.x = -pl->vel.x; pl->vel.mul(0.7f); }
|
||||
else if(srcphys) pl->vel.x = 0.0f; // wall stopped us: drop the velocity into it
|
||||
continue;
|
||||
}
|
||||
pl->o = o_nullxy;
|
||||
@@ -805,6 +810,7 @@ void moveplayer(physent *pl, int moveres, bool local, int curtime)
|
||||
{
|
||||
d.y = 0;
|
||||
if(pl->type==ENT_BOUNCE) { pl->vel.y = -pl->vel.y; pl->vel.mul(0.7f); }
|
||||
else if(srcphys) pl->vel.y = 0.0f; // wall stopped us: drop the velocity into it
|
||||
continue;
|
||||
}
|
||||
pl->o = o_nullxy;
|
||||
@@ -812,10 +818,12 @@ void moveplayer(physent *pl, int moveres, bool local, int curtime)
|
||||
if(!collide(pl, false, drop, rise))
|
||||
{
|
||||
d.y = d.x = 0;
|
||||
if(srcphys) pl->vel.x = pl->vel.y = 0.0f;
|
||||
continue;
|
||||
}
|
||||
pl->o = o_null;
|
||||
if(pl->type==ENT_BOUNCE) { pl->vel.z = -pl->vel.z; pl->vel.mul(0.5f); }
|
||||
else if(srcphys) pl->vel.x = pl->vel.y = 0.0f; // nothing worked: don't keep pushing into whatever blocks us
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -1449,7 +1449,9 @@ void grenades::onselecting(bool sound)
|
||||
void grenades::onownerdies()
|
||||
{
|
||||
reset();
|
||||
if(owner==player1 && inhandnade) dropnade();
|
||||
// Bots cook grenades too. Without this their live grenade would be left in
|
||||
// the world at the origin, exploding there two seconds later.
|
||||
if(inhandnade && ((owner==player1) || (owner->type==ENT_BOT))) dropnade();
|
||||
}
|
||||
|
||||
void grenades::removebounceent(bounceent *b)
|
||||
|
||||
Reference in New Issue
Block a user