- cd gmqcc && make -j $(nproc) && export QCC="$PWD/gmqcc"
- cd ..
+report_cloc:
+ stage: test
+ script:
+ - cloc --force-lang-def=qcsrc/tools/cloc.txt --sql 1 --sql-project xonotic qcsrc | sqlite3 code.db
+ - sqlite3 code.db 'select file,nCode from t where nCode > 1000 order by nBlank+nComment+nCode desc'
+
test_compilation_units:
stage: test
script:
- wget -O data/maps/g-23.waypoints.cache https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/g-23.waypoints.cache
- wget -O data/maps/g-23.waypoints.hardwired https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/g-23.waypoints.hardwired
- make
- - EXPECT=d17f62e08ff11b8b25116fa4a64f7e86
+ - EXPECT=74f3802009cec230bdaa3b87235368ca
- HASH=$(${ENGINE} -noconfig -nohome +exec serverbench.cfg
| tee /dev/stderr
| grep '^:'
//seta hud_panel_mapvote 1 "enable this panel"
seta hud_panel_itemstime 2 "enable this panel, 1 = show when spectating, 2 = even playing in warmup stage"
//seta hud_panel_quickmenu 1 "enable this panel"
+//seta hud_panel_scoreboard 1 "enable this panel"
+seta hud_panel_scoreboard_accuracy 1 "show weapon accuracy stats panel on scoreboard; colors can be configured with accuracy_color* cvars"
seta hud_panel_weapons_dynamichud 1 "apply the dynamic hud effects to this panel"
seta hud_panel_ammo_dynamichud 1 "apply the dynamic hud effects to this panel"
seta hud_panel_physics_dynamichud 1 "apply the dynamic hud effects to this panel"
seta hud_panel_centerprint_dynamichud 1 "apply the dynamic hud effects to this panel"
seta hud_panel_itemstime_dynamichud 1 "apply the dynamic hud effects to this panel"
+seta hud_panel_scoreboard_dynamichud 0 "apply the dynamic hud effects to this panel"
seta hud_panel_weapons_ammo_full_shells 60 "show 100% of the status bar at this ammo count"
seta hud_panel_weapons_ammo_full_nails 320 "show 100% of the status bar at this ammo count"
seta hud_panel_weapons_ammo_full_plasma 180 "show 100% of the status bar at this ammo count"
seta hud_panel_weapons_ammo_full_rockets 160 "show 100% of the status bar at this ammo count"
seta hud_panel_weapons_ammo_full_fuel 100 "show 100% of the status bar at this ammo count"
+seta hud_panel_weapons_hide_ondeath 0 "hide this panel when dead"
seta hud_panel_ammo_maxammo "40" "when you have this much ammo, the ammo status bar is full"
+seta hud_panel_ammo_hide_ondeath 0 "hide this panel when dead"
+
+seta hud_panel_powerups_hide_ondeath 0 "hide this panel when dead"
seta hud_panel_healtharmor_maxhealth "200" "when you have this much health, the health status bar is full"
seta hud_panel_healtharmor_maxarmor "200" "when you have this much armor, the armor status bar is full"
seta hud_panel_healtharmor_progressbar_gfx_damage 5 "show damage effect when damaged at least by this amount; 0 disables the effect"
seta hud_panel_healtharmor_progressbar_gfx_lowhealth 40 "health progressbar blinks when health is lower than this amount"
+seta hud_panel_healtharmor_hide_ondeath 0 "hide this panel when dead"
seta hud_panel_timer_increment "0" "show elapsed time instead of remaining time"
seta hud_panel_quickmenu_translatecommands 0 "when the game is translated, translate strings inside commands too (useful for chat commands)"
seta hud_panel_quickmenu_time 5 "quickmenu expires after this number of seconds in the same page"
+seta hud_panel_infomessages_group0 1 "show group 0 messages (showing keys for non-crucial actions you can do while spectating/observing)"
+seta hud_panel_infomessages_group_time 6 "number of seconds a message of a group lasts before it gets changed"
+seta hud_panel_infomessages_group_fadetime 0.4 "group message fade in/out time"
+
// hud panel aliases
alias quickmenu "cl_cmd hud quickmenu ${* ?}"
seta hud_panel_mapvote_bg_alpha "" "if set to something else than \"\" = override default panel background alpha"
seta hud_panel_mapvote_bg_border "" "if set to something else than \"\" = override default size of border around the background"
seta hud_panel_mapvote_bg_padding "" "if set to something else than \"\" = override default padding of contents from border"
+seta hud_panel_mapvote_highlight_border "" "highlight border size of the selected map"
seta hud_panel_itemstime_pos "" "position of this base of the panel"
seta hud_panel_itemstime_size "" "size of this panel"
seta hud_panel_quickmenu_bg_border "" "if set to something else than \"\" = override default size of border around the background"
seta hud_panel_quickmenu_bg_padding "" "if set to something else than \"\" = override default padding of contents from border"
seta hud_panel_quickmenu_align "" "text alignment: 0 left, 0.5 center, 1 right"
+
+seta hud_panel_scoreboard_pos "" "position of this base of the panel"
+seta hud_panel_scoreboard_size "" "size of this panel"
+seta hud_panel_scoreboard_bg "" "if set to something else than \"\" = override default background"
+seta hud_panel_scoreboard_bg_color "" "if set to something else than \"\" = override default panel background color"
+seta hud_panel_scoreboard_bg_color_team "" "override panel color with team color in team based games"
+seta hud_panel_scoreboard_bg_alpha "" "if set to something else than \"\" = override default panel background alpha"
+seta hud_panel_scoreboard_bg_border "" "if set to something else than \"\" = override default size of border around the background"
+seta hud_panel_scoreboard_bg_padding "" "if set to something else than \"\" = override default padding of contents from border"
+seta hud_panel_scoreboard_fadeinspeed "" "speed at which scoreboard fades in, higher is faster (0 = instant)"
+seta hud_panel_scoreboard_fadeoutspeed "" "speed at which scoreboard fades out, higher is faster (0 = instant)"
+seta hud_panel_scoreboard_respawntime_decimals "" "decimal places to show for the respawntime countdown display on the scoreboard"
+seta hud_panel_scoreboard_table_bg_alpha "" "background alpha of a scoreboard table"
+seta hud_panel_scoreboard_table_bg_scale "" "scale for the tiled scoreboard background"
+seta hud_panel_scoreboard_table_fg_alpha "" "foreground alpha of a scoreboard table"
+seta hud_panel_scoreboard_table_fg_alpha_self "" "self foreground alpha of a scoreboard table"
+seta hud_panel_scoreboard_table_highlight "" "enable highlighting for rows and columns in scoreboard tables"
+seta hud_panel_scoreboard_table_highlight_alpha "" "highlight alpha of a scoreboard table"
+seta hud_panel_scoreboard_table_highlight_alpha_self "" "self highlight alpha of a scoreboard table"
+seta hud_panel_scoreboard_bg_teams_color_team "" "override panel team color in team tables"
+seta hud_panel_scoreboard_accuracy_doublerows "" "use two rows instead of one"
+seta hud_panel_scoreboard_accuracy_nocolors "" "don't use colors displaying accuracy stats"
// scoreboard
seta scoreboard_columns default
+
+// keep old scoreboard cvars for compatibility's sake
+// they've been replaced by hud_panel_scoreboard_* cvars
+// TODO remove them after a future release (0.8.2+)
seta scoreboard_border_thickness 1 "scoreboard border thickness"
seta scoreboard_accuracy_border_thickness 1 "accuracy stats border thickness"
seta scoreboard_accuracy_doublerows 0 "use two rows instead of one"
set g_ban_sync_timeout 45 "time out in seconds for the ban sync requests"
set g_ban_sync_trusted_servers_verify 0 "when set to 1, additional bans sent by the servers are ignored, and only bans for the requested IP are used"
-set g_showweaponspawns 1 "display sprites for weapon spawns found on the map when a weapon key is pressed and the weapon is not available"
+set g_showweaponspawns 1 "1: display waypoints for weapon spawns found on the map when a weapon key is pressed and the weapon is not owned; 2: for dropped weapons too; 3: for all the weapons sharing the same impulse"
// ballistics use physical units, but qu based
// Quake-Newton: 1 qN = 1 qu * 1 g / 1 s^2
set cl_weapon_stay_color "2 0.5 0.5" "Color of picked up weapons when g_weapon_stay > 0"
set cl_weapon_stay_alpha 0.75 "Alpha of picked up weapons when g_weapon_stay > 0"
+set sv_showspectators 0 "Show who's spectating who in the player info panel. Shouldn't be used on competitive servers, also disable when watching a suspected cheater"
+seta cl_showspectators 1
+
// Facility for config.cfg use ONLY.
// Interpreted in post-config.cfg.
seta menu_forced_saved_cvars "" "These cvars will always be saved, despite engine/Xonotic cvar saving status"
seta hud_progressbar_vehicles_ammo1_color "0.77 0.67 0"
seta hud_progressbar_vehicles_ammo2_color "0.86 0.35 0"
-seta _hud_panelorder "17 15 12 9 5 10 6 14 0 7 4 11 2 1 3 8 13 16 18 23 19 20 21 22 "
+seta _hud_panelorder "17 15 12 9 5 10 6 14 0 7 4 11 2 1 3 8 13 16 18 23 19 20 21 22 23 24 "
seta hud_configure_grid "1"
seta hud_configure_grid_xsize "0.005000"
seta hud_panel_engineinfo_framecounter_time "0.1"
seta hud_panel_engineinfo_framecounter_decimals "0"
-seta hud_panel_infomessages_pos "0.720000 0.100000"
+seta hud_panel_infomessages_pos "0.680000 0.100000"
seta hud_panel_infomessages_size "0.280000 0.080000"
seta hud_panel_infomessages_bg "0"
seta hud_panel_infomessages_bg_color ""
seta hud_panel_mapvote_bg_alpha ""
seta hud_panel_mapvote_bg_border ""
seta hud_panel_mapvote_bg_padding ""
+seta hud_panel_mapvote_highlight_border "1"
seta hud_panel_itemstime_pos "0.030000 0.260000"
seta hud_panel_itemstime_size "0.070000 0.230000"
seta hud_panel_quickmenu_bg_padding ""
seta hud_panel_quickmenu_align "0"
+seta hud_panel_scoreboard_pos "0.150000 0.150000"
+seta hud_panel_scoreboard_size "0.700000 0.700000"
+seta hud_panel_scoreboard_bg "border_default"
+seta hud_panel_scoreboard_bg_color "0 0.3 0.5"
+seta hud_panel_scoreboard_bg_color_team ""
+seta hud_panel_scoreboard_bg_alpha "0.7"
+seta hud_panel_scoreboard_bg_border ""
+seta hud_panel_scoreboard_bg_padding ""
+seta hud_panel_scoreboard_fadeinspeed "10"
+seta hud_panel_scoreboard_fadeoutspeed "5"
+seta hud_panel_scoreboard_respawntime_decimals "1"
+seta hud_panel_scoreboard_table_bg_alpha "0"
+seta hud_panel_scoreboard_table_bg_scale "0.25"
+seta hud_panel_scoreboard_table_fg_alpha "0.9"
+seta hud_panel_scoreboard_table_fg_alpha_self "1"
+seta hud_panel_scoreboard_table_highlight "1"
+seta hud_panel_scoreboard_table_highlight_alpha "0.2"
+seta hud_panel_scoreboard_table_highlight_alpha_self "0.4"
+seta hud_panel_scoreboard_bg_teams_color_team "0"
+seta hud_panel_scoreboard_accuracy_doublerows "0"
+seta hud_panel_scoreboard_accuracy_nocolors "0"
+
menu_sync
seta hud_progressbar_vehicles_ammo1_color "0.8 0.7 0"
seta hud_progressbar_vehicles_ammo2_color "0.7 0.4 0"
-seta _hud_panelorder "17 15 12 9 10 5 6 14 0 7 4 11 2 1 3 8 13 16 18 23 19 20 21 22 "
+seta _hud_panelorder "17 15 12 9 10 5 6 14 0 7 4 11 2 1 3 8 13 16 18 23 19 20 21 22 23 24 "
seta hud_configure_grid "1"
seta hud_configure_grid_xsize "0.010000"
seta hud_panel_engineinfo_framecounter_time "0.1"
seta hud_panel_engineinfo_framecounter_decimals "0"
-seta hud_panel_infomessages_pos "0.720000 0.100000"
+seta hud_panel_infomessages_pos "0.680000 0.100000"
seta hud_panel_infomessages_size "0.280000 0.080000"
seta hud_panel_infomessages_bg "0"
seta hud_panel_infomessages_bg_color ""
seta hud_panel_mapvote_bg_alpha ""
seta hud_panel_mapvote_bg_border ""
seta hud_panel_mapvote_bg_padding ""
+seta hud_panel_mapvote_highlight_border "1"
seta hud_panel_itemstime_pos "0.030000 0.260000"
seta hud_panel_itemstime_size "0.070000 0.230000"
seta hud_panel_quickmenu_bg_padding ""
seta hud_panel_quickmenu_align "0"
+seta hud_panel_scoreboard_pos "0.150000 0.150000"
+seta hud_panel_scoreboard_size "0.700000 0.700000"
+seta hud_panel_scoreboard_bg "border_default"
+seta hud_panel_scoreboard_bg_color ""
+seta hud_panel_scoreboard_bg_color_team "0.7"
+seta hud_panel_scoreboard_bg_alpha "0.7"
+seta hud_panel_scoreboard_bg_border ""
+seta hud_panel_scoreboard_bg_padding ""
+seta hud_panel_scoreboard_fadeinspeed "10"
+seta hud_panel_scoreboard_fadeoutspeed "5"
+seta hud_panel_scoreboard_respawntime_decimals "1"
+seta hud_panel_scoreboard_table_bg_alpha "0.8"
+seta hud_panel_scoreboard_table_bg_scale "0.25"
+seta hud_panel_scoreboard_table_fg_alpha "0.9"
+seta hud_panel_scoreboard_table_fg_alpha_self "1"
+seta hud_panel_scoreboard_table_highlight "1"
+seta hud_panel_scoreboard_table_highlight_alpha "0.08"
+seta hud_panel_scoreboard_table_highlight_alpha_self "0.3"
+seta hud_panel_scoreboard_bg_teams_color_team "0"
+seta hud_panel_scoreboard_accuracy_doublerows "1"
+seta hud_panel_scoreboard_accuracy_nocolors "0"
+
menu_sync
seta hud_progressbar_vehicles_ammo1_color "0.8 0.7 0"
seta hud_progressbar_vehicles_ammo2_color "0.7 0.4 0"
-seta _hud_panelorder "17 10 3 0 14 6 9 13 4 1 2 11 12 7 5 8 15 16 18 23 19 20 21 22 "
+seta _hud_panelorder "17 10 3 0 14 6 9 13 4 1 2 11 12 7 5 8 15 16 18 23 19 20 21 22 23 24 "
seta hud_configure_grid "1"
seta hud_configure_grid_xsize "0.010000"
seta hud_panel_engineinfo_framecounter_decimals "0"
seta hud_panel_infomessages_pos "0.710000 0"
-seta hud_panel_infomessages_size "0.290000 0.100000"
+seta hud_panel_infomessages_size "0.280000 0.090000"
seta hud_panel_infomessages_bg "0"
seta hud_panel_infomessages_bg_color ""
seta hud_panel_infomessages_bg_color_team ""
seta hud_panel_mapvote_bg_alpha ""
seta hud_panel_mapvote_bg_border ""
seta hud_panel_mapvote_bg_padding ""
+seta hud_panel_mapvote_highlight_border "1"
seta hud_panel_itemstime_pos "0.000000 0.310000"
seta hud_panel_itemstime_size "0.070000 0.180000"
seta hud_panel_quickmenu_bg_padding ""
seta hud_panel_quickmenu_align "0"
+seta hud_panel_scoreboard_pos "0.150000 0.150000"
+seta hud_panel_scoreboard_size "0.700000 0.700000"
+seta hud_panel_scoreboard_bg "0"
+seta hud_panel_scoreboard_bg_color ""
+seta hud_panel_scoreboard_bg_color_team ""
+seta hud_panel_scoreboard_bg_alpha ""
+seta hud_panel_scoreboard_bg_border ""
+seta hud_panel_scoreboard_bg_padding ""
+seta hud_panel_scoreboard_fadeinspeed "10"
+seta hud_panel_scoreboard_fadeoutspeed "5"
+seta hud_panel_scoreboard_respawntime_decimals "1"
+seta hud_panel_scoreboard_table_bg_alpha "0.8"
+seta hud_panel_scoreboard_table_bg_scale "0.25"
+seta hud_panel_scoreboard_table_fg_alpha "0.9"
+seta hud_panel_scoreboard_table_fg_alpha_self "1"
+seta hud_panel_scoreboard_table_highlight "1"
+seta hud_panel_scoreboard_table_highlight_alpha "0.08"
+seta hud_panel_scoreboard_table_highlight_alpha_self "0.3"
+seta hud_panel_scoreboard_bg_teams_color_team "0.7"
+seta hud_panel_scoreboard_accuracy_doublerows "1"
+seta hud_panel_scoreboard_accuracy_nocolors "0"
+
menu_sync
seta hud_progressbar_vehicles_ammo1_color "0.8 0.7 0"
seta hud_progressbar_vehicles_ammo2_color "0.7 0.4 0"
-seta _hud_panelorder "17 15 3 1 2 11 10 0 14 6 9 13 4 12 7 5 8 16 18 23 19 20 21 22 "
+seta _hud_panelorder "17 15 3 1 2 11 10 0 14 6 9 13 4 12 7 5 8 16 18 23 19 20 21 22 23 24 "
seta hud_configure_grid "1"
seta hud_configure_grid_xsize "0.010000"
seta hud_panel_engineinfo_framecounter_decimals "0"
seta hud_panel_infomessages_pos "0.710000 0"
-seta hud_panel_infomessages_size "0.290000 0.100000"
+seta hud_panel_infomessages_size "0.280000 0.090000"
seta hud_panel_infomessages_bg "0"
seta hud_panel_infomessages_bg_color ""
seta hud_panel_infomessages_bg_color_team ""
seta hud_panel_mapvote_bg_alpha ""
seta hud_panel_mapvote_bg_border ""
seta hud_panel_mapvote_bg_padding ""
+seta hud_panel_mapvote_highlight_border "1"
seta hud_panel_itemstime_pos "0.000000 0.310000"
seta hud_panel_itemstime_size "0.070000 0.180000"
seta hud_panel_quickmenu_bg_padding ""
seta hud_panel_quickmenu_align "0"
+seta hud_panel_scoreboard_pos "0.150000 0.150000"
+seta hud_panel_scoreboard_size "0.700000 0.700000"
+seta hud_panel_scoreboard_bg "0"
+seta hud_panel_scoreboard_bg_color ""
+seta hud_panel_scoreboard_bg_color_team ""
+seta hud_panel_scoreboard_bg_alpha ""
+seta hud_panel_scoreboard_bg_border ""
+seta hud_panel_scoreboard_bg_padding ""
+seta hud_panel_scoreboard_fadeinspeed "10"
+seta hud_panel_scoreboard_fadeoutspeed "5"
+seta hud_panel_scoreboard_respawntime_decimals "1"
+seta hud_panel_scoreboard_table_bg_alpha "0.8"
+seta hud_panel_scoreboard_table_bg_scale "0.25"
+seta hud_panel_scoreboard_table_fg_alpha "0.9"
+seta hud_panel_scoreboard_table_fg_alpha_self "1"
+seta hud_panel_scoreboard_table_highlight "1"
+seta hud_panel_scoreboard_table_highlight_alpha "0.08"
+seta hud_panel_scoreboard_table_highlight_alpha_self "0.3"
+seta hud_panel_scoreboard_bg_teams_color_team "0.7"
+seta hud_panel_scoreboard_accuracy_doublerows "1"
+seta hud_panel_scoreboard_accuracy_nocolors "0"
+
menu_sync
seta hud_progressbar_vehicles_ammo1_color "0.8 0.7 0"
seta hud_progressbar_vehicles_ammo2_color "0.7 0.4 0"
-seta _hud_panelorder "17 15 10 9 6 8 14 5 0 4 13 2 7 1 3 11 12 16 18 23 19 20 21 22 "
+seta _hud_panelorder "17 15 10 9 6 8 14 5 0 4 13 2 7 1 3 11 12 16 18 23 19 20 21 22 23 24 "
seta hud_configure_grid "1"
seta hud_configure_grid_xsize "0.010000"
seta hud_panel_mapvote_bg_alpha ""
seta hud_panel_mapvote_bg_border ""
seta hud_panel_mapvote_bg_padding ""
+seta hud_panel_mapvote_highlight_border "1"
seta hud_panel_itemstime_pos "0.020000 0.490000"
seta hud_panel_itemstime_size "0.090000 0.140000"
seta hud_panel_quickmenu_bg_padding ""
seta hud_panel_quickmenu_align "1"
+seta hud_panel_scoreboard_pos "0.150000 0.150000"
+seta hud_panel_scoreboard_size "0.700000 0.700000"
+seta hud_panel_scoreboard_bg ""
+seta hud_panel_scoreboard_bg_color ""
+seta hud_panel_scoreboard_bg_color_team ""
+seta hud_panel_scoreboard_bg_alpha ""
+seta hud_panel_scoreboard_bg_border ""
+seta hud_panel_scoreboard_bg_padding ""
+seta hud_panel_scoreboard_fadeinspeed "10"
+seta hud_panel_scoreboard_fadeoutspeed "5"
+seta hud_panel_scoreboard_respawntime_decimals "1"
+seta hud_panel_scoreboard_table_bg_alpha "0.8"
+seta hud_panel_scoreboard_table_bg_scale "0.25"
+seta hud_panel_scoreboard_table_fg_alpha "0.9"
+seta hud_panel_scoreboard_table_fg_alpha_self "1"
+seta hud_panel_scoreboard_table_highlight "1"
+seta hud_panel_scoreboard_table_highlight_alpha "0.08"
+seta hud_panel_scoreboard_table_highlight_alpha_self "0.3"
+seta hud_panel_scoreboard_bg_teams_color_team "0.7"
+seta hud_panel_scoreboard_accuracy_doublerows "1"
+seta hud_panel_scoreboard_accuracy_nocolors "0"
+
menu_sync
seta hud_progressbar_vehicles_ammo1_color "0.8 0.7 0"
seta hud_progressbar_vehicles_ammo2_color "0.7 0.4 0"
-seta _hud_panelorder "17 15 0 11 8 5 6 14 9 13 7 2 3 1 10 12 4 16 18 23 19 20 21 22 "
+seta _hud_panelorder "17 15 0 11 8 5 6 14 9 13 7 2 3 1 10 12 4 16 18 23 19 20 21 22 23 24 "
seta hud_configure_grid "1"
seta hud_configure_grid_xsize "0.010000"
seta hud_panel_mapvote_bg_alpha ""
seta hud_panel_mapvote_bg_border ""
seta hud_panel_mapvote_bg_padding ""
+seta hud_panel_mapvote_highlight_border "1"
seta hud_panel_itemstime_pos "0.000000 0.290000"
seta hud_panel_itemstime_size "0.150000 0.060000"
seta hud_panel_quickmenu_bg_padding ""
seta hud_panel_quickmenu_align "0"
+seta hud_panel_scoreboard_pos "0.150000 0.150000"
+seta hud_panel_scoreboard_size "0.700000 0.700000"
+seta hud_panel_scoreboard_bg ""
+seta hud_panel_scoreboard_bg_color ""
+seta hud_panel_scoreboard_bg_color_team ""
+seta hud_panel_scoreboard_bg_alpha "0.7"
+seta hud_panel_scoreboard_bg_border ""
+seta hud_panel_scoreboard_bg_padding ""
+seta hud_panel_scoreboard_fadeinspeed "10"
+seta hud_panel_scoreboard_fadeoutspeed "5"
+seta hud_panel_scoreboard_respawntime_decimals "1"
+seta hud_panel_scoreboard_table_bg_alpha "0.8"
+seta hud_panel_scoreboard_table_bg_scale "0.25"
+seta hud_panel_scoreboard_table_fg_alpha "0.9"
+seta hud_panel_scoreboard_table_fg_alpha_self "1"
+seta hud_panel_scoreboard_table_highlight "1"
+seta hud_panel_scoreboard_table_highlight_alpha "0.1"
+seta hud_panel_scoreboard_table_highlight_alpha_self "0.25"
+seta hud_panel_scoreboard_bg_teams_color_team "0.7"
+seta hud_panel_scoreboard_accuracy_doublerows "1"
+seta hud_panel_scoreboard_accuracy_nocolors "0"
+
menu_sync
"INIT(class)=class::class()" \
"CONSTRUCTOR(class)=class::class(" \
"DESTRUCTOR(class)=class::~class()" \
- "ATTRIB(class, name, T, val)=T name = val;" \
- "ATTRIB_STRZONE(class, name, T, val)=T name = val;" \
- "STATIC_ATTRIB(class, name, T, val)=static T name = val;" \
- "STATIC_ATTRIB_STRZONE(class, name, T, val)=static T name = val;" \
+ "ATTRIB(class, name, T, val)=T name = val" \
+ "ATTRIB_STRZONE(class, name, T, val)=T name = val" \
+ "ATTRIBARRAY(class, name, T, val)=T name[val]" \
+ "STATIC_ATTRIB(class, name, T, val)=static T name = val" \
+ "STATIC_ATTRIB_STRZONE(class, name, T, val)=static T name = val" \
"METHOD(class, name, prototype)=virtual void class::name()" \
"ENDCLASS(class)=};" \
__STDC__
#include <client/mapvoting.qc>
#include <client/miscfunctions.qc>
#include <client/player_skeleton.qc>
-#include <client/scoreboard.qc>
#include <client/shownames.qc>
#include <client/teamradar.qc>
#include <client/view.qc>
#include <client/mapvoting.qh>
#include <client/miscfunctions.qh>
#include <client/player_skeleton.qh>
-#include <client/scoreboard.qh>
#include <client/shownames.qh>
#include <client/teamradar.qh>
#include <client/view.qh>
if(roundstarttime == -1)
{
Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_ROUNDSTOP);
- remove(this);
+ delete(this);
announcer_countdown = NULL;
return;
}
{
Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_BEGIN);
Local_Notification(MSG_MULTI, MULTI_COUNTDOWN_BEGIN);
- remove(this);
+ delete(this);
announcer_countdown = NULL;
return;
}
{
Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_GAMESTART, countdown_rounded);
Notification annce_num = Announcer_PickNumber(CNT_GAMESTART, countdown_rounded);
- if(annce_num != NULL)
+ if(annce_num != NULL)
Local_Notification(MSG_ANNCE, annce_num);
}
centerprint_kill(ORDINAL(CPID_ROUND));
if(announcer_countdown)
{
- remove(announcer_countdown);
+ delete(announcer_countdown);
announcer_countdown = NULL;
}
}
bool autocvar_hud_panel_physics_dynamichud = true;
bool autocvar_hud_panel_centerprint_dynamichud = true;
bool autocvar_hud_panel_itemstime_dynamichud = true;
+bool autocvar_hud_panel_healtharmor_hide_ondeath = false;
+bool autocvar_hud_panel_ammo_hide_ondeath = false;
+bool autocvar_hud_panel_powerups_hide_ondeath = false;
+bool autocvar_hud_panel_weapons_hide_ondeath = false;
bool autocvar_hud_panel_ammo;
bool autocvar_hud_panel_ammo_iconalign;
int autocvar_hud_panel_ammo_maxammo;
int autocvar_hud_panel_healtharmor_text;
bool autocvar_hud_panel_infomessages;
bool autocvar_hud_panel_infomessages_flip;
+float autocvar_hud_panel_mapvote_highlight_border = 1;
bool autocvar_hud_panel_modicons;
int autocvar_hud_panel_modicons_ca_layout;
int autocvar_hud_panel_modicons_dom_layout;
int autocvar_r_fakelight;
int autocvar_r_fullbright;
float autocvar_r_letterbox;
-bool autocvar_scoreboard_accuracy;
-bool autocvar_scoreboard_accuracy_doublerows;
-bool autocvar_scoreboard_accuracy_nocolors;
-float autocvar_scoreboard_alpha_bg;
-float autocvar_scoreboard_alpha_fg = 1.0;
-float autocvar_scoreboard_alpha_name = 0.9;
-float autocvar_scoreboard_alpha_name_self = 1;
-float autocvar_scoreboard_bg_scale;
-float autocvar_scoreboard_border_thickness;
-float autocvar_scoreboard_color_bg_b;
-float autocvar_scoreboard_color_bg_g;
-float autocvar_scoreboard_color_bg_r;
-float autocvar_scoreboard_color_bg_team;
string autocvar_scoreboard_columns;
-float autocvar_scoreboard_fadeinspeed = 10;
-float autocvar_scoreboard_fadeoutspeed = 5;
-bool autocvar_scoreboard_highlight;
-float autocvar_scoreboard_highlight_alpha = 0.10;
-float autocvar_scoreboard_highlight_alpha_self = 0.25;
-float autocvar_scoreboard_offset_left;
-float autocvar_scoreboard_offset_right;
-float autocvar_scoreboard_offset_vertical;
-float autocvar_scoreboard_respawntime_decimals;
-bool autocvar_scoreboard_dynamichud = false;
bool autocvar_v_flipped;
float autocvar_vid_conheight;
float autocvar_vid_conwidth;
float autocvar_cl_deathglow;
bool autocvar_developer_csqcentities;
float autocvar_g_jetpack_attenuation;
+bool autocvar_cl_showspectators;
string autocvar_crosshair_hmg = "";
vector autocvar_crosshair_hmg_color = '0.2 1.0 0.2';
float autocvar_crosshair_hmg_alpha = 1;
float autocvar_crosshair_rpc_size = 1;
int autocvar_cl_nade_timer;
bool autocvar_cl_items_nofade;
-float autocvar_slowmo;
case "scoreboard_columns_set":
{
- Cmd_HUD_SetFields(argc);
+ Cmd_Scoreboard_SetFields(argc);
return;
}
case "scoreboard_columns_help":
{
- Cmd_HUD_Help();
+ Cmd_Scoreboard_Help();
return;
}
#pragma once
-void Cmd_HUD_SetFields(int);
-void Cmd_HUD_Help();
+void Cmd_Scoreboard_SetFields(int);
+void Cmd_Scoreboard_Help();
// used by common/command/generic.qc:GenericCommand_dumpcommands to list all commands into a .txt file
void LocalCommand_macro_write_aliases(int fh);
_setmodel(e, cvar_defstring("_cl_playermodel"));
forceplayermodels_goodmodel = e.model;
forceplayermodels_goodmodelindex = e.modelindex;
- remove(e);
+ delete(e);
}
// first, try finding it from the server
forceplayermodels_model = e.model;
forceplayermodels_modelindex = e.modelindex;
forceplayermodels_skin = autocvar__cl_playerskin;
- remove(e);
+ delete(e);
}
if(autocvar_cl_forcemyplayermodel != "" && autocvar_cl_forcemyplayermodel != forceplayermodels_mymodel)
forceplayermodels_myisgoodmodel = fexists(e.model);
forceplayermodels_mymodel = e.model;
forceplayermodels_mymodelindex = e.modelindex;
- remove(e);
+ delete(e);
}
// apply it
case 29: return 4; // anim_duckwalkbackright -> anim_duckwalk
case 30: return 4; // anim_duckwalkbackleft -> anim_duckwalk
}
- LOG_DEBUGF("Frame %d missing in model %s, and we have no fallback - FAIL!\n", f, this.model);
+ LOG_DEBUGF("Frame %d missing in model %s, and we have no fallback - FAIL!", f, this.model);
return f;
}
void CSQCPlayer_FallbackFrame_Apply(entity this)
// we need to prevent this from 'appening
this.tag_entity = NULL;
this.drawmask = 0;
- LOG_TRACE("h_ model lacks weapon attachment, but v_ model is attached to it\n");
+ LOG_TRACE("h_ model lacks weapon attachment, but v_ model is attached to it");
}
}
else if(this.tag_entity.isplayermodel)
// #include "panel/mapvote.qc"
// #include "panel/itemstime.qc"
#include "panel/quickmenu.qc"
+#include "panel/scoreboard.qc"
#include "hud_config.qh"
#include "../mapvoting.qh"
-#include "../scoreboard.qh"
#include "../teamradar.qh"
#include <common/t_items.qh>
#include <common/deathtypes/all.qh>
void HUD_Reset()
{
// reset gametype specific icons
- if(gametype == MAPINFO_TYPE_CTF)
- HUD_Mod_CTF_Reset();
+ if(gametype.m_modicons_reset)
+ gametype.m_modicons_reset();
}
float autocvar_hud_dynamic_shake = 1;
void HUD_Main()
{
int i;
- // global hud alpha fade
- if(menu_enabled == 1)
+ // global hud alpha fade (scoreboard-related panels behave differently and override it temporarly)
+ if(hud_configure_menu_open == 1)
hud_fade_alpha = 1;
+ else if(!autocvar__hud_configure)
+ hud_fade_alpha = (1 - scoreboard_fade_alpha) * (1 - autocvar__menu_alpha);
else
- hud_fade_alpha = (1 - autocvar__menu_alpha);
-
- if(scoreboard_fade_alpha)
- hud_fade_alpha = (1 - scoreboard_fade_alpha);
+ hud_fade_alpha = 1 - autocvar__menu_alpha;
HUD_Configure_Frame();
// they must fade only when the menu does
if(scoreboard_fade_alpha == 1)
{
- HUD_Panel_Draw(HUD_PANEL(CENTERPRINT));
- return;
+ if(autocvar__menu_alpha == 1)
+ return;
+ if(scoreboard_fade_alpha == 1)
+ {
+ HUD_Panel_Draw(HUD_PANEL(SCOREBOARD));
+ HUD_Panel_Draw(HUD_PANEL(CENTERPRINT));
+ return;
+ }
}
if(!autocvar__hud_configure && !hud_fade_alpha)
}
}
if (warning)
- LOG_TRACE("Automatically fixed wrong/missing panel numbers in _hud_panelorder\n");
+ LOG_TRACE("Automatically fixed wrong/missing panel numbers in _hud_panelorder");
cvar_set("_hud_panelorder", s);
if(hud_panelorder_prev)
float complain_weapon_type;
float complain_weapon_time;
-int ps_primary, ps_secondary;
+PlayerScoreField ps_primary, ps_secondary;
int ts_primary, ts_secondary;
Weapon last_switchweapon;
float teamnagger;
-float hud_configure_checkcollisions;
-float hud_configure_prev;
-vector hud_configure_gridSize;
-vector hud_configure_realGridSize;
-
int hudShiftState;
const int S_SHIFT = 1;
const int S_CTRL = 2;
const int S_ALT = 4;
-float menu_enabled; // 1 showing the entire HUD, 2 showing only the clicked panel
-
float hud_fade_alpha;
string hud_skin_path;
REGISTER_HUD_PANEL(MAPVOTE, MapVote_Draw, mapvote, PANEL_CONFIG_NO , PANEL_SHOW_MAPVOTE )
REGISTER_HUD_PANEL(ITEMSTIME, HUD_ItemsTime, itemstime, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
REGISTER_HUD_PANEL(QUICKMENU, HUD_QuickMenu, quickmenu, PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(SCOREBOARD, Scoreboard_Draw, scoreboard, PANEL_CONFIG_NO , PANEL_SHOW_ALWAYS )
// always add new panels to the end of list
// Because calling lots of functions in QC apparently cuts fps in half on many machines:
// Get value for panel_bg_color: if "" fetch default, else use panel_bg_color. Convert pants, shirt or teamcolor into a vector.
#define HUD_Panel_GetColor() MACRO_BEGIN { \
- if ((teamplay) && panel_bg_color_team) { \
+ if ((teamplay) && panel_bg_color_team > 0) { \
if (autocvar__hud_configure && myteam == NUM_SPECTATOR) \
panel_bg_color = '1 0 0' * panel_bg_color_team; \
else \
panel_bg_color = myteamcolors * panel_bg_color_team; \
- } else if (autocvar_hud_configure_teamcolorforced && autocvar__hud_configure && panel_bg_color_team) { \
+ } else if (autocvar_hud_configure_teamcolorforced && autocvar__hud_configure && panel_bg_color_team > 0) { \
panel_bg_color = '1 0 0' * panel_bg_color_team; \
} else { \
if (panel_bg_color_str == "") { \
if (autocvar__hud_configure) { \
if (!panel_enabled) \
panel_bg_alpha = 0.25; \
- else if (menu_enabled == 2 && panel == highlightedPanel) \
+ else if (hud_configure_menu_open == 2 && panel == highlightedPanel) \
panel_bg_alpha = (1 - autocvar__menu_alpha) * max(cvar("hud_configure_bg_minalpha"), panel_bg_alpha) + autocvar__menu_alpha * panel_bg_alpha;\
else \
panel_bg_alpha = max(cvar("hud_configure_bg_minalpha"), panel_bg_alpha); \
// return smoothly faded pos and size of given panel when a dialog is active
// don't center too wide panels, it doesn't work with different resolutions
#define HUD_Panel_UpdatePosSize_ForMenu() MACRO_BEGIN { \
- vector menu_enable_size = panel_size; \
+ vector new_size = panel_size; \
float max_panel_width = 0.52 * vid_conwidth; \
if(panel_size.x > max_panel_width) \
{ \
- menu_enable_size.x = max_panel_width; \
- menu_enable_size.y = panel_size.y * (menu_enable_size.x / panel_size.x); \
+ new_size.x = max_panel_width; \
+ new_size.y = panel_size.y * (new_size.x / panel_size.x); \
} \
- vector menu_enable_pos = eX * (panel_bg_border + 0.5 * max_panel_width) + eY * 0.5 * vid_conheight - 0.5 * menu_enable_size; \
- panel_pos = (1 - autocvar__menu_alpha) * panel_pos + (autocvar__menu_alpha) * menu_enable_pos; \
- panel_size = (1 - autocvar__menu_alpha) * panel_size + (autocvar__menu_alpha) * menu_enable_size; \
+ vector new_pos = eX * (panel_bg_border + 0.5 * max_panel_width) + eY * 0.5 * vid_conheight - 0.5 * new_size; \
+ panel_pos = (1 - autocvar__menu_alpha) * panel_pos + (autocvar__menu_alpha) * new_pos; \
+ panel_size = (1 - autocvar__menu_alpha) * panel_size + (autocvar__menu_alpha) * new_size; \
} MACRO_END
// Scale the pos and size vectors to absolute coordinates
panel_bg_padding_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_padding")); \
HUD_Panel_GetBg(); \
if (panel.current_panel_bg != "0") { \
- HUD_Panel_GetColorTeam(); \
- HUD_Panel_GetColor(); \
HUD_Panel_GetBgAlpha(); \
HUD_Panel_GetBorder(); \
} \
+ HUD_Panel_GetColorTeam(); \
+ HUD_Panel_GetColor(); \
HUD_Panel_GetFgAlpha(); \
HUD_Panel_GetPadding(); \
panel.current_panel_bg_alpha = panel_bg_alpha; \
panel.current_panel_fg_alpha = panel_fg_alpha; \
- if (menu_enabled == 2 && panel == highlightedPanel) { \
+ if (hud_configure_menu_open == 2 && panel == highlightedPanel) { \
HUD_Panel_UpdatePosSize_ForMenu(); \
} else { \
panel_bg_alpha *= hud_fade_alpha; \
panel_pos = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_pos"))); \
panel_size = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_size"))); \
HUD_Panel_ScalePosSize(); \
- if (menu_enabled == 2 && panel == highlightedPanel) { \
+ if (hud_configure_menu_open == 2 && panel == highlightedPanel) { \
HUD_Panel_UpdatePosSize_ForMenu(); \
} \
panel_bg_border_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_border")); \
#include "hud_config.qh"
#include "hud.qh"
+#include "panel/scoreboard.qh"
#define HUD_Write(s) fputs(fh, s)
#define HUD_Write_Cvar(cvar) HUD_Write(strcat("seta ", cvar, " \"", cvar_string(cvar), "\"\n"))
case HUD_PANEL_QUICKMENU:
HUD_Write_PanelCvar("_align");
break;
+ case HUD_PANEL_SCOREBOARD:
+ HUD_Write_PanelCvar("_fadeinspeed");
+ HUD_Write_PanelCvar("_fadeoutspeed");
+ HUD_Write_PanelCvar("_respawntime_decimals");
+ HUD_Write_PanelCvar("_table_bg_alpha");
+ HUD_Write_PanelCvar("_table_bg_scale");
+ HUD_Write_PanelCvar("_table_fg_alpha");
+ HUD_Write_PanelCvar("_table_fg_alpha_self");
+ HUD_Write_PanelCvar("_table_highlight");
+ HUD_Write_PanelCvar("_table_highlight_alpha");
+ HUD_Write_PanelCvar("_table_highlight_alpha_self");
+ HUD_Write_PanelCvar("_bg_teams_color_team");
+ HUD_Write_PanelCvar("_accuracy_doublerows");
+ HUD_Write_PanelCvar("_accuracy_nocolors");
+ break;
}
HUD_Write("\n");
}
void HUD_Configure_Exit_Force()
{
- if (menu_enabled)
+ if (hud_configure_menu_open)
{
- menu_enabled = 0;
+ hud_configure_menu_open = 0;
localcmd("togglemenu\n");
}
cvar_set("_hud_configure", "0");
{
if (bInputType == 1)
return true;
- menu_enabled = 1;
+ hud_configure_menu_open = 1;
localcmd("menu_showhudexit\n");
}
else if(nPrimary == K_BACKSPACE && hudShiftState & S_CTRL)
{
if (bInputType == 1)
return true;
- if (!menu_enabled)
+ if (!hud_configure_menu_open)
cvar_set("_hud_configure", "0");
}
else if(nPrimary == K_TAB && hudShiftState & S_CTRL) // switch panel
void HUD_Panel_EnableMenu()
{
- menu_enabled = 2;
+ hud_configure_menu_open = 2;
localcmd("menu_showhudoptions ", highlightedPanel.panel_name, "\n");
}
float mouse_over_panel;
{
if(prevMouseClicked)
highlightedAction = 0;
- if(menu_enabled == 2)
+ if(hud_configure_menu_open == 2)
mouse_over_panel = 0;
else
mouse_over_panel = HUD_Panel_Check_Mouse_Pos(true);
int i;
if(autocvar__hud_configure)
{
- if(isdemo() || intermission == 2)
+ if(isdemo() || intermission == 2 || scoreboard_active)
{
HUD_Configure_Exit_Force();
return;
if(autocvar__menu_alpha != _menu_alpha_prev)
{
if(autocvar__menu_alpha == 0)
- menu_enabled = 0;
+ hud_configure_menu_open = 0;
_menu_alpha_prev = autocvar__menu_alpha;
}
}
else if(hud_configure_prev)
{
- if(menu_enabled)
- menu_enabled = 0;
+ if(hud_configure_menu_open)
+ hud_configure_menu_open = 0;
if(autocvar_hud_cursormode)
setcursormode(0);
hud_dynamic_shake_factor = -1;
float prevMouseClickedTime; // time during previous left mouse click, to check for doubleclicks
vector prevMouseClickedPos; // pos during previous left mouse click, to check for doubleclicks
+float hud_configure_prev;
+float hud_configure_checkcollisions;
+vector hud_configure_gridSize;
+vector hud_configure_realGridSize;
+float hud_configure_menu_open; // 1 showing the entire HUD, 2 showing only the clicked panel
+
void HUD_Panel_ExportCfg(string cfgname);
void HUD_Panel_Mouse();
#include <client/hud/panel/timer.qc>
#include <client/hud/panel/vote.qc>
#include <client/hud/panel/weapons.qc>
+#include <client/hud/panel/scoreboard.qc>
#include <client/hud/panel/timer.qh>
#include <client/hud/panel/vote.qh>
#include <client/hud/panel/weapons.qh>
+#include <client/hud/panel/scoreboard.qh>
if(hud != HUD_NORMAL) return;
if(!autocvar__hud_configure)
{
- if(!autocvar_hud_panel_ammo) return;
- if(spectatee_status == -1) return;
+ if((!autocvar_hud_panel_ammo) || (spectatee_status == -1))
+ return;
+ if(STAT(HEALTH) < 1 && autocvar_hud_panel_ammo_hide_ondeath)
+ return;
}
HUD_Panel_UpdateCvars();
#include "centerprint.qh"
-#include <client/scoreboard.qh>
+#include "scoreboard.qh"
// CenterPrint (#16)
{
// fade out the current msg (duration and countdown_num are ignored)
centerprint_time[j] = min(5, autocvar_hud_panel_centerprint_fade_out);
- if (centerprint_expire_time[j] > time + min(5, autocvar_hud_panel_centerprint_fade_out) || centerprint_expire_time[j] < time)
- centerprint_expire_time[j] = time + min(5, autocvar_hud_panel_centerprint_fade_out);
+ centerprint_expire_time[j] = -1; // don't use the variable time here!
return;
}
break; // found a msg with the same id, at position j
if (duration < 0)
{
centerprint_time[j] = -1;
- centerprint_expire_time[j] = time;
+ centerprint_expire_time[j] = -1; // don't use the variable time here!
}
else
{
if(duration == 0)
duration = max(1, autocvar_hud_panel_centerprint_time);
centerprint_time[j] = duration;
- centerprint_expire_time[j] = time + duration;
+ centerprint_expire_time[j] = -1; // don't use the variable time here!
}
centerprint_countdown_num[j] = countdown_num;
}
}
// this panel fades only when the menu does
- float hud_fade_alpha_save = 0;
- if(scoreboard_fade_alpha)
- {
- hud_fade_alpha_save = hud_fade_alpha;
+ float hud_fade_alpha_save = hud_fade_alpha;
+ if(hud_configure_menu_open == 1)
+ hud_fade_alpha = 1;
+ else
hud_fade_alpha = 1 - autocvar__menu_alpha;
- }
+
HUD_Panel_UpdateCvars();
+ hud_fade_alpha = hud_fade_alpha_save;
if ( HUD_Radar_Clickable() )
{
panel_pos = eY * hud_panel_radar_bottom + eX * 0.5 * (vid_conwidth - panel_size_x);
panel_size_y = min(panel_size_y, vid_conheight - hud_panel_radar_bottom);
}
- else if(scoreboard_fade_alpha)
+ else if(!autocvar__hud_configure && scoreboard_fade_alpha)
{
- hud_fade_alpha = hud_fade_alpha_save;
-
// move the panel below the scoreboard
if (scoreboard_bottom >= 0.96 * vid_conheight)
return;
vector target_pos;
-
target_pos = eY * scoreboard_bottom + eX * 0.5 * (vid_conwidth - panel_size.x);
-
if(target_pos.y > panel_pos.y)
{
panel_pos = panel_pos + (target_pos - panel_pos) * sqrt(scoreboard_fade_alpha);
{
if (j == CENTERPRINT_MAX_MSGS)
j = 0;
+ if (centerprint_expire_time[j] == -1)
+ {
+ // here we are sure the time variable is not altered by CSQC_Ent_Update
+ centerprint_expire_time[j] = time;
+ if (centerprint_time[j] > 0)
+ centerprint_expire_time[j] += centerprint_time[j];
+ }
if (centerprint_expire_time[j] <= time)
{
if (centerprint_countdown_num[j] && centerprint_time[j] > 0)
int armor, health, fuel;
if(!autocvar__hud_configure)
{
- if(!autocvar_hud_panel_healtharmor) return;
+ if((!autocvar_hud_panel_healtharmor) || (spectatee_status == -1))
+ return;
if(hud != HUD_NORMAL) return;
- if(spectatee_status == -1) return;
health = STAT(HEALTH);
if(health <= 0)
{
+ health = 0;
prev_health = -1;
- return;
+ if(autocvar_hud_panel_healtharmor_hide_ondeath)
+ return;
}
armor = STAT(ARMOR);
- // code to check for spectatee_status changes is in Ent_ClientData()
+ // code to check for spectatee_status changes is in ENT_CLIENT_CLIENTDATA
// prev_p_health and prev_health can be set to -1 there
if (prev_p_health == -1)
// Info messages panel (#14)
-#define drawInfoMessage(s) MACRO_BEGIN { \
- if(autocvar_hud_panel_infomessages_flip) \
- o.x = pos.x + mySize.x - stringwidth(s, true, fontsize); \
- drawcolorcodedstring(o, s, fontsize, a, DRAWFLAG_NORMAL); \
- o.y += fontsize.y; \
+float autocvar_hud_panel_infomessages_group0 = 1;
+float autocvar_hud_panel_infomessages_group_fadetime = 0.4;
+float autocvar_hud_panel_infomessages_group_time = 6;
+const int IMG_COUNT = 1; // number of InfoMessage Groups
+float img_fade[IMG_COUNT];
+int img_cur_msg[IMG_COUNT];
+float img_time[IMG_COUNT];
+
+int img_select(int group_id)
+{
+ float fadetime = max(0.001, autocvar_hud_panel_infomessages_group_fadetime);
+ if(time > img_time[group_id])
+ {
+ img_fade[group_id] = max(0, img_fade[group_id] - frametime / fadetime);
+ if(!img_fade[group_id])
+ {
+ ++img_cur_msg[group_id];
+ img_time[group_id] = floor(time) + autocvar_hud_panel_infomessages_group_time;
+ }
+ }
+ else
+ img_fade[group_id] = min(1, img_fade[group_id] + frametime / fadetime);
+ return img_cur_msg[group_id];
+}
+
+float stringwidth_colors(string s, vector theSize);
+vector InfoMessages_drawstring(string s, vector pos, vector sz, float a, vector fontsize)
+{
+ getWrappedLine_remaining = s;
+ float offset = 0;
+ while(getWrappedLine_remaining)
+ {
+ s = getWrappedLine(sz.x - offset, fontsize, stringwidth_colors);
+ if(autocvar_hud_panel_infomessages_flip)
+ offset = sz.x - stringwidth_colors(s, fontsize) - offset;
+ drawcolorcodedstring(pos + eX * offset, s, fontsize, a, DRAWFLAG_NORMAL);
+ pos.y += fontsize.y;
+ offset = fontsize.x;
+ }
+ pos.y += fontsize.y * 0.25;
+ return pos;
+}
+
+#define InfoMessage(s) MACRO_BEGIN { \
+ pos = InfoMessages_drawstring(s, pos, mySize, ((img_curr_group >= 0) ? panel_fg_alpha * img_fade[img_curr_group] : panel_fg_alpha), fontsize); \
+ img_curr_group = -1; \
} MACRO_END
+
void HUD_InfoMessages()
{
if(!autocvar__hud_configure)
mySize -= '2 2 0' * panel_bg_padding;
}
- // always force 5:1 aspect
- vector newSize = '0 0 0';
- if(mySize.x/mySize.y > 5)
- {
- newSize.x = 5 * mySize.y;
- newSize.y = mySize.y;
-
- pos.x = pos.x + (mySize.x - newSize.x) / 2;
- }
- else
- {
- newSize.y = 1/5 * mySize.x;
- newSize.x = mySize.x;
-
- pos.y = pos.y + (mySize.y - newSize.y) / 2;
- }
-
- mySize = newSize;
- entity tm;
- vector o;
- o = pos;
-
- vector fontsize;
- fontsize = '0.20 0.20 0' * mySize.y;
-
- float a;
- a = panel_fg_alpha;
-
+ vector fontsize = '0.2 0.2 0' * mySize.y;
string s;
+ int img_curr_group = -1;
if(!autocvar__hud_configure)
{
if(spectatee_status)
{
- a = 1;
if(spectatee_status == -1)
s = _("^1Observing");
else
s = sprintf(_("^1Spectating: ^7%s"), entcs_GetName(current_player));
- drawInfoMessage(s);
-
- if(spectatee_status == -1)
- s = sprintf(_("^1Press ^3%s^1 to spectate"), getcommandkey("primary fire", "+fire"));
- else
- s = sprintf(_("^1Press ^3%s^1 or ^3%s^1 for next or previous player"), getcommandkey("next weapon", "weapnext"), getcommandkey("previous weapon", "weapprev"));
- drawInfoMessage(s);
-
- if(spectatee_status == -1)
- s = sprintf(_("^1Use ^3%s^1 or ^3%s^1 to change the speed"), getcommandkey("next weapon", "weapnext"), getcommandkey("previous weapon", "weapprev"));
- else
- s = sprintf(_("^1Press ^3%s^1 to observe, ^3%s^1 to change camera mode"), getcommandkey("secondary fire", "+fire2"), getcommandkey("drop weapon", "dropweapon"));
- drawInfoMessage(s);
+ InfoMessage(s);
- s = sprintf(_("^1Press ^3%s^1 for gamemode info"), getcommandkey("server info", "+show_info"));
- drawInfoMessage(s);
+ if(autocvar_hud_panel_infomessages_group0)
+ {
+ img_curr_group = 0;
+ switch(img_select(img_curr_group) % 3)
+ {
+ default:
+ case 0:
+ if(spectatee_status == -1)
+ s = sprintf(_("^1Press ^3%s^1 to spectate"), getcommandkey(_("primary fire"), "+fire"));
+ else
+ s = sprintf(_("^1Press ^3%s^1 or ^3%s^1 for next or previous player"), getcommandkey(_("next weapon"), "weapnext"), getcommandkey(_("previous weapon"), "weapprev"));
+ break;
+ case 1:
+ if(spectatee_status == -1)
+ s = sprintf(_("^1Use ^3%s^1 or ^3%s^1 to change the speed"), getcommandkey(_("next weapon"), "weapnext"), getcommandkey(_("previous weapon"), "weapprev"));
+ else
+ s = sprintf(_("^1Press ^3%s^1 to observe, ^3%s^1 to change camera mode"), getcommandkey(_("secondary fire"), "+fire2"), getcommandkey(_("drop weapon"), "dropweapon"));
+ break;
+ case 2:
+ s = sprintf(_("^1Press ^3%s^1 for gamemode info"), getcommandkey(_("server info"), "+show_info"));
+ break;
+ }
+ InfoMessage(s);
+ }
if(gametype == MAPINFO_TYPE_LMS)
{
entity sk;
sk = playerslots[player_localnum];
- if(sk.(scores[ps_primary]) >= 666)
+ if(sk.(scores(ps_primary)) >= 666)
s = _("^1Match has already begun");
- else if(sk.(scores[ps_primary]) > 0)
+ else if(sk.(scores(ps_primary)) > 0)
s = _("^1You have no more lives left");
else
- s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey("jump", "+jump"));
+ s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey(_("jump"), "+jump"));
}
else
- s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey("jump", "+jump"));
- drawInfoMessage(s);
+ s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey(_("jump"), "+jump"));
+ InfoMessage(s);
}
if (time < STAT(GAMESTARTTIME))
//we need to ceil, otherwise the countdown would be off by .5 when using round()
float countdown = ceil(STAT(GAMESTARTTIME) - time);
s = sprintf(_("^1Game starts in ^3%d^1 seconds"), countdown);
- drawInfoMessage(s);
+ InfoMessage(s);
}
if(warmup_stage)
{
s = _("^2Currently in ^1warmup^2 stage!");
- drawInfoMessage(s);
+ InfoMessage(s);
}
string blinkcolor;
if(ready_waiting_for_me)
{
if(warmup_stage)
- s = sprintf(_("%sPress ^3%s%s to end warmup"), blinkcolor, getcommandkey("ready", "ready"), blinkcolor);
+ s = sprintf(_("%sPress ^3%s%s to end warmup"), blinkcolor, getcommandkey(_("ready"), "ready"), blinkcolor);
else
- s = sprintf(_("%sPress ^3%s%s once you are ready"), blinkcolor, getcommandkey("ready", "ready"), blinkcolor);
+ s = sprintf(_("%sPress ^3%s%s once you are ready"), blinkcolor, getcommandkey(_("ready"), "ready"), blinkcolor);
}
else
{
else
s = _("^2Waiting for others to ready up...");
}
- drawInfoMessage(s);
+ InfoMessage(s);
}
else if(warmup_stage && !spectatee_status)
{
- s = sprintf(_("^2Press ^3%s^2 to end warmup"), getcommandkey("ready", "ready"));
- drawInfoMessage(s);
+ s = sprintf(_("^2Press ^3%s^2 to end warmup"), getcommandkey(_("ready"), "ready"));
+ InfoMessage(s);
}
if(teamplay && !spectatee_status && gametype != MAPINFO_TYPE_CA && teamnagger)
{
float ts_min = 0, ts_max = 0;
- tm = teams.sort_next;
+ entity tm = teams.sort_next;
if (tm)
{
for (; tm.sort_next; tm = tm.sort_next)
{
s = strcat(blinkcolor, _("Teamnumbers are unbalanced!"));
tm = GetTeam(myteam, false);
- if (tm)
- if (tm.team != NUM_SPECTATOR)
- if (tm.team_size == ts_max)
- s = strcat(s, sprintf(_(" Press ^3%s%s to adjust"), getcommandkey("team menu", "menu_showteamselect"), blinkcolor));
- drawInfoMessage(s);
+ if (tm && tm.team != NUM_SPECTATOR && tm.team_size == ts_max)
+ s = strcat(s, sprintf(_(" Press ^3%s%s to adjust"), getcommandkey(_("team menu"), "menu_showteamselect"), blinkcolor));
+ InfoMessage(s);
}
}
}
+
+ if(autocvar_cl_showspectators)
+ if(num_spectators)
+ //if(spectatee_status != -1)
+ {
+ s = ((spectatee_status) ? _("^1Spectating this player:") : _("^1Spectating you:"));
+ // InfoMessage(s)
+ int limit = min(num_spectators, MAX_SPECTATORS);
+ for(int i = 0; i < limit; ++i)
+ {
+ float slot = spectatorlist[i];
+ if(i == 0)
+ s = strcat(s, " ^7", entcs_GetName(slot));
+ else
+ s = strcat("^7", entcs_GetName(slot));
+ InfoMessage(s);
+ }
+ }
}
else
{
- s = _("^7Press ^3ESC ^7to show HUD options.");
- drawInfoMessage(s);
- s = _("^3Doubleclick ^7a panel for panel-specific options.");
- drawInfoMessage(s);
- s = _("^3CTRL ^7to disable collision testing, ^3SHIFT ^7and");
- drawInfoMessage(s);
- s = _("^3ALT ^7+ ^3ARROW KEYS ^7for fine adjustments.");
- drawInfoMessage(s);
+ InfoMessage(_("^7Press ^3ESC ^7to show HUD options."));
+ InfoMessage(_("^3Doubleclick ^7a panel for panel-specific options."));
+ InfoMessage(_("^3CTRL ^7to disable collision testing, ^3SHIFT ^7and"));
+ InfoMessage(_("^3ALT ^7+ ^3ARROW KEYS ^7for fine adjustments."));
}
}
entity me;
me = playerslots[player_localnum];
float score;
- score = me.(scores[ps_primary]);
+ score = me.(scores(ps_primary));
- if(!(scores_flags[ps_primary] & SFL_TIME) || teamplay) // race/cts record display on HUD
+ if(!(scores_flags(ps_primary) & SFL_TIME) || teamplay) // race/cts record display on HUD
return; // no records in the actual race
// clientside personal record
void HUD_ModIcons_SetFunc()
{
- switch(gametype)
- {
- case MAPINFO_TYPE_KEYHUNT: HUD_ModIcons_GameType = HUD_Mod_KH; break;
- case MAPINFO_TYPE_CTF: HUD_ModIcons_GameType = HUD_Mod_CTF; break;
- case MAPINFO_TYPE_NEXBALL: HUD_ModIcons_GameType = HUD_Mod_NexBall; break;
- case MAPINFO_TYPE_CTS:
- case MAPINFO_TYPE_RACE: HUD_ModIcons_GameType = HUD_Mod_Race; break;
- case MAPINFO_TYPE_CA:
- case MAPINFO_TYPE_FREEZETAG: HUD_ModIcons_GameType = HUD_Mod_CA; break;
- case MAPINFO_TYPE_DOMINATION: HUD_ModIcons_GameType = HUD_Mod_Dom; break;
- case MAPINFO_TYPE_KEEPAWAY: HUD_ModIcons_GameType = HUD_Mod_Keepaway; break;
- }
+ HUD_ModIcons_GameType = gametype.m_modicons;
}
int mod_prev; // previous state of mod_active to check for a change
// Initialize items
if(!autocvar__hud_configure)
{
- if(!autocvar_hud_panel_powerups) return;
- if(spectatee_status == -1) return;
- if(STAT(HEALTH) <= 0) return;
+ if((!autocvar_hud_panel_powerups) || (spectatee_status == -1))
+ return;
+ if(STAT(HEALTH) <= 0 && autocvar_hud_panel_powerups_hide_ondeath)
+ return;
if(!(allItems & (ITEM_Strength.m_itemid | ITEM_Shield.m_itemid | IT_SUPERWEAPON)) && !allBuffs) return;
strengthTime = bound(0, STAT(STRENGTH_FINISHED) - time, 99);
}
else
{
- LOG_WARNINGF("Unrecognized mode %s\n", mode);
+ LOG_WARNF("Unrecognized mode %s", mode);
return false;
}
// printf("^1 skipping %s\n", s);
}
if(QuickMenu_Buffer_Index == QuickMenu_Buffer_Size)
- LOG_WARNINGF("Couldn't find submenu \"%s\"\n", z_submenu);
+ LOG_WARNF("Couldn't find submenu \"%s\"", z_submenu);
}
// only the last page can contain up to QUICKMENU_MAXLINES entries
if(target_submenu != "" && !target_submenu_found)
{
- LOG_WARNINGF("Couldn't find submenu \"%s\"\n", target_submenu);
+ LOG_WARNF("Couldn't find submenu \"%s\"", target_submenu);
if(prvm_language != "en")
- LOG_WARNINGF("^3Warning: submenu must be in English\n", target_submenu);
+ LOG_WARNF("^3Warning: submenu must be in English", target_submenu);
QuickMenu_Buffer_Size = 0;
}
}
#include "score.qh"
-#include <client/scoreboard.qh>
+#include "scoreboard.qh"
#include <common/ent_cs.qh>
#include <common/mapinfo.qh>
// Score (#7)
-void HUD_UpdatePlayerTeams();
+void Scoreboard_UpdatePlayerTeams();
void HUD_Score_Rankings(vector pos, vector mySize, entity me)
{
float score;
return;
}
- if (!scoreboard_fade_alpha) // the scoreboard too calls HUD_UpdatePlayerTeams
- HUD_UpdatePlayerTeams();
+ if (!scoreboard_fade_alpha) // the scoreboard too calls Scoreboard_UpdatePlayerTeams
+ Scoreboard_UpdatePlayerTeams();
if (team_count)
{
// show team scores in the first line
for(tm = teams.sort_next; tm; tm = tm.sort_next) {
if(tm.team == NUM_SPECTATOR)
continue;
- if(!tm.team && teamplay)
+ if(!tm.team)
continue;
+
if (tm.team == myteam)
drawfill(pos + eX * score_size * i, eX * score_size + eY * fontsize.y, '1 1 1', highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect(pos + eX * score_size * i, ftos(tm.(teamscores[ts_primary])), eX * score_size + eY * fontsize.y, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring_aspect(pos + eX * score_size * i, ftos(tm.(teamscores(ts_primary))), eX * score_size + eY * fontsize.y, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
++i;
}
first_pl = 1;
score_color = Team_ColorRGB(pl.team) * 0.8;
s = textShortenToWidth(entcs_GetName(pl.sv_entnum), name_size, fontsize, stringwidth_colors);
drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring(pos + eX * (name_size + spacing_size), ftos(pl.(scores[ps_primary])), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring(pos + eX * (name_size + spacing_size), ftos(pl.(scores(ps_primary))), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
pos.y += fontsize.y;
++i;
}
me = playerslots[current_player];
- if((scores_flags[ps_primary] & SFL_TIME) && !teamplay) { // race/cts record display on HUD
+ if((scores_flags(ps_primary) & SFL_TIME) && !teamplay) { // race/cts record display on HUD
string timer, distrtimer;
pl = players.sort_next;
if(pl == me)
pl = pl.sort_next;
- if(scores_flags[ps_primary] & SFL_ZERO_IS_WORST)
- if(pl.scores[ps_primary] == 0)
+ if(scores_flags(ps_primary) & SFL_ZERO_IS_WORST)
+ if(pl.scores(ps_primary) == 0)
pl = NULL;
- score = me.(scores[ps_primary]);
+ score = me.(scores(ps_primary));
timer = TIME_ENCODED_TOSTRING(score);
draw_beginBoldFont();
- if (pl && ((!(scores_flags[ps_primary] & SFL_ZERO_IS_WORST)) || score)) {
+ if (pl && ((!(scores_flags(ps_primary) & SFL_ZERO_IS_WORST)) || score)) {
// distribution display
- distribution = me.(scores[ps_primary]) - pl.(scores[ps_primary]);
+ distribution = me.(scores(ps_primary)) - pl.(scores(ps_primary));
distrtimer = ftos_decimals(fabs(distribution/pow(10, TIME_DECIMALS)), TIME_DECIMALS);
if(autocvar__hud_configure)
distribution = 42;
else if(pl)
- distribution = me.(scores[ps_primary]) - pl.(scores[ps_primary]);
+ distribution = me.(scores(ps_primary)) - pl.(scores(ps_primary));
else
distribution = 0;
- score = me.(scores[ps_primary]);
+ score = me.(scores(ps_primary));
if(autocvar__hud_configure)
score = 123;
for(tm = teams.sort_next; tm; tm = tm.sort_next) {
if(tm.team == NUM_SPECTATOR)
continue;
- if(!tm.team && teamplay)
+ if(!tm.team)
continue;
- score = tm.(teamscores[ts_primary]);
+
+ score = tm.(teamscores(ts_primary));
if(autocvar__hud_configure)
score = 123;
--- /dev/null
+#include "scoreboard.qh"
+
+#include "quickmenu.qh"
+#include <common/ent_cs.qh>
+#include <common/constants.qh>
+#include <common/mapinfo.qh>
+#include <common/minigames/cl_minigames.qh>
+#include <common/stats.qh>
+#include <common/teams.qh>
+
+float sbt_bg_alpha;
+float sbt_fg_alpha;
+float sbt_fg_alpha_self;
+bool sbt_highlight;
+float sbt_highlight_alpha;
+float sbt_highlight_alpha_self;
+
+// provide basic panel cvars to old clients
+// TODO remove them after a future release (0.8.2+)
+string autocvar_hud_panel_scoreboard_pos = "0.150000 0.150000";
+string autocvar_hud_panel_scoreboard_size = "0.700000 0.700000";
+string autocvar_hud_panel_scoreboard_bg = "border_default";
+string autocvar_hud_panel_scoreboard_bg_color = "0 0.3 0.5";
+string autocvar_hud_panel_scoreboard_bg_color_team = "";
+string autocvar_hud_panel_scoreboard_bg_alpha = "0.7";
+string autocvar_hud_panel_scoreboard_bg_border = "";
+string autocvar_hud_panel_scoreboard_bg_padding = "";
+
+float autocvar_hud_panel_scoreboard_fadeinspeed = 10;
+float autocvar_hud_panel_scoreboard_fadeoutspeed = 5;
+float autocvar_hud_panel_scoreboard_respawntime_decimals = 1;
+float autocvar_hud_panel_scoreboard_table_bg_alpha = 0;
+float autocvar_hud_panel_scoreboard_table_bg_scale = 0.25;
+float autocvar_hud_panel_scoreboard_table_fg_alpha = 0.9;
+float autocvar_hud_panel_scoreboard_table_fg_alpha_self = 1;
+bool autocvar_hud_panel_scoreboard_table_highlight = true;
+float autocvar_hud_panel_scoreboard_table_highlight_alpha = 0.2;
+float autocvar_hud_panel_scoreboard_table_highlight_alpha_self = 0.4;
+float autocvar_hud_panel_scoreboard_bg_teams_color_team = 0;
+
+bool autocvar_hud_panel_scoreboard_accuracy = true;
+bool autocvar_hud_panel_scoreboard_accuracy_doublerows = false;
+bool autocvar_hud_panel_scoreboard_accuracy_nocolors = false;
+
+bool autocvar_hud_panel_scoreboard_dynamichud = false;
+
+
+void drawstringright(vector, string, vector, vector, float, float);
+void drawstringcenter(vector, string, vector, vector, float, float);
+
+// wrapper to put all possible scores titles through gettext
+string TranslateScoresLabel(string l)
+{
+ switch(l)
+ {
+ case "bckills": return CTX(_("SCO^bckills"));
+ case "bctime": return CTX(_("SCO^bctime"));
+ case "caps": return CTX(_("SCO^caps"));
+ case "captime": return CTX(_("SCO^captime"));
+ case "deaths": return CTX(_("SCO^deaths"));
+ case "destroyed": return CTX(_("SCO^destroyed"));
+ case "dmg": return CTX(_("SCO^dmg"));
+ case "dmgtaken": return CTX(_("SCO^dmgtaken"));
+ case "drops": return CTX(_("SCO^drops"));
+ case "faults": return CTX(_("SCO^faults"));
+ case "fckills": return CTX(_("SCO^fckills"));
+ case "goals": return CTX(_("SCO^goals"));
+ case "kckills": return CTX(_("SCO^kckills"));
+ case "kdratio": return CTX(_("SCO^kdratio"));
+ case "k/d": return CTX(_("SCO^k/d"));
+ case "kd": return CTX(_("SCO^kd"));
+ case "kdr": return CTX(_("SCO^kdr"));
+ case "kills": return CTX(_("SCO^kills"));
+ case "laps": return CTX(_("SCO^laps"));
+ case "lives": return CTX(_("SCO^lives"));
+ case "losses": return CTX(_("SCO^losses"));
+ case "name": return CTX(_("SCO^name"));
+ case "sum": return CTX(_("SCO^sum"));
+ case "nick": return CTX(_("SCO^nick"));
+ case "objectives": return CTX(_("SCO^objectives"));
+ case "pickups": return CTX(_("SCO^pickups"));
+ case "ping": return CTX(_("SCO^ping"));
+ case "pl": return CTX(_("SCO^pl"));
+ case "pushes": return CTX(_("SCO^pushes"));
+ case "rank": return CTX(_("SCO^rank"));
+ case "returns": return CTX(_("SCO^returns"));
+ case "revivals": return CTX(_("SCO^revivals"));
+ case "rounds": return CTX(_("SCO^rounds won"));
+ case "score": return CTX(_("SCO^score"));
+ case "suicides": return CTX(_("SCO^suicides"));
+ case "takes": return CTX(_("SCO^takes"));
+ case "ticks": return CTX(_("SCO^ticks"));
+ default: return l;
+ }
+}
+
+void Scoreboard_InitScores()
+{
+ int i, f;
+
+ ps_primary = ps_secondary = NULL;
+ ts_primary = ts_secondary = -1;
+ FOREACH(Scores, true, {
+ f = (scores_flags(it) & SFL_SORT_PRIO_MASK);
+ if(f == SFL_SORT_PRIO_PRIMARY)
+ ps_primary = it;
+ if(f == SFL_SORT_PRIO_SECONDARY)
+ ps_secondary = it;
+ });
+ if(ps_secondary == NULL)
+ ps_secondary = ps_primary;
+
+ for(i = 0; i < MAX_TEAMSCORE; ++i)
+ {
+ f = (teamscores_flags(i) & SFL_SORT_PRIO_MASK);
+ if(f == SFL_SORT_PRIO_PRIMARY)
+ ts_primary = i;
+ if(f == SFL_SORT_PRIO_SECONDARY)
+ ts_secondary = i;
+ }
+ if(ts_secondary == -1)
+ ts_secondary = ts_primary;
+
+ Cmd_Scoreboard_SetFields(0);
+}
+
+float SetTeam(entity pl, float Team);
+//float lastpnum;
+void Scoreboard_UpdatePlayerTeams()
+{
+ float Team;
+ entity pl, tmp;
+ float num;
+
+ num = 0;
+ for(pl = players.sort_next; pl; pl = pl.sort_next)
+ {
+ num += 1;
+ Team = entcs_GetScoreTeam(pl.sv_entnum);
+ if(SetTeam(pl, Team))
+ {
+ tmp = pl.sort_prev;
+ Scoreboard_UpdatePlayerPos(pl);
+ if(tmp)
+ pl = tmp;
+ else
+ pl = players.sort_next;
+ }
+ }
+ /*
+ if(num != lastpnum)
+ print(strcat("PNUM: ", ftos(num), "\n"));
+ lastpnum = num;
+ */
+}
+
+int Scoreboard_CompareScore(int vl, int vr, int f)
+{
+ TC(int, vl); TC(int, vr); TC(int, f);
+ if(f & SFL_ZERO_IS_WORST)
+ {
+ if(vl == 0 && vr != 0)
+ return 1;
+ if(vl != 0 && vr == 0)
+ return 0;
+ }
+ if(vl > vr)
+ return IS_INCREASING(f);
+ if(vl < vr)
+ return IS_DECREASING(f);
+ return -1;
+}
+
+float Scoreboard_ComparePlayerScores(entity left, entity right)
+{
+ float vl, vr, r;
+ vl = entcs_GetTeam(left.sv_entnum);
+ vr = entcs_GetTeam(right.sv_entnum);
+
+ if(!left.gotscores)
+ vl = NUM_SPECTATOR;
+ if(!right.gotscores)
+ vr = NUM_SPECTATOR;
+
+ if(vl > vr)
+ return true;
+ if(vl < vr)
+ return false;
+
+ if(vl == NUM_SPECTATOR)
+ {
+ // FIRST the one with scores (spectators), THEN the ones without (downloaders)
+ // no other sorting
+ if(!left.gotscores && right.gotscores)
+ return true;
+ return false;
+ }
+
+ r = Scoreboard_CompareScore(left.scores(ps_primary), right.scores(ps_primary), scores_flags(ps_primary));
+ if (r >= 0)
+ return r;
+
+ r = Scoreboard_CompareScore(left.scores(ps_secondary), right.scores(ps_secondary), scores_flags(ps_secondary));
+ if (r >= 0)
+ return r;
+
+ FOREACH(Scores, true, {
+ r = Scoreboard_CompareScore(left.scores(it), right.scores(it), scores_flags(it));
+ if (r >= 0) return r;
+ });
+
+ if (left.sv_entnum < right.sv_entnum)
+ return true;
+
+ return false;
+}
+
+void Scoreboard_UpdatePlayerPos(entity player)
+{
+ entity ent;
+ for(ent = player.sort_next; ent && Scoreboard_ComparePlayerScores(player, ent); ent = player.sort_next)
+ {
+ SORT_SWAP(player, ent);
+ }
+ for(ent = player.sort_prev; ent != players && Scoreboard_ComparePlayerScores(ent, player); ent = player.sort_prev)
+ {
+ SORT_SWAP(ent, player);
+ }
+}
+
+float Scoreboard_CompareTeamScores(entity left, entity right)
+{
+ int i, r;
+
+ if(left.team == NUM_SPECTATOR)
+ return 1;
+ if(right.team == NUM_SPECTATOR)
+ return 0;
+
+ r = Scoreboard_CompareScore(left.teamscores(ts_primary), right.teamscores(ts_primary), teamscores_flags(ts_primary));
+ if (r >= 0)
+ return r;
+
+ r = Scoreboard_CompareScore(left.teamscores(ts_secondary), right.teamscores(ts_secondary), teamscores_flags(ts_secondary));
+ if (r >= 0)
+ return r;
+
+ for(i = 0; i < MAX_TEAMSCORE; ++i)
+ {
+ r = Scoreboard_CompareScore(left.teamscores(i), right.teamscores(i), teamscores_flags(i));
+ if (r >= 0)
+ return r;
+ }
+
+ if (left.team < right.team)
+ return true;
+
+ return false;
+}
+
+void Scoreboard_UpdateTeamPos(entity Team)
+{
+ entity ent;
+ for(ent = Team.sort_next; ent && Scoreboard_CompareTeamScores(Team, ent); ent = Team.sort_next)
+ {
+ SORT_SWAP(Team, ent);
+ }
+ for(ent = Team.sort_prev; ent != teams && Scoreboard_CompareTeamScores(ent, Team); ent = Team.sort_prev)
+ {
+ SORT_SWAP(ent, Team);
+ }
+}
+
+void Cmd_Scoreboard_Help()
+{
+ LOG_INFO(_("You can modify the scoreboard using the ^2scoreboard_columns_set command.\n"));
+ LOG_INFO(_("^3|---------------------------------------------------------------|\n"));
+ LOG_INFO(_("Usage:\n"));
+ LOG_INFO(_("^2scoreboard_columns_set default\n"));
+ LOG_INFO(_("^2scoreboard_columns_set ^7field1 field2 ...\n"));
+ LOG_INFO(_("The following field names are recognized (case insensitive):\n"));
+ LOG_INFO(_("You can use a ^3|^7 to start the right-aligned fields.\n"));
+ LOG_INFO("\n");
+
+ LOG_INFO(_("^3name^7 or ^3nick^7 Name of a player\n"));
+ LOG_INFO(_("^3ping^7 Ping time\n"));
+ LOG_INFO(_("^3pl^7 Packet loss\n"));
+ LOG_INFO(_("^3elo^7 Player ELO\n"));
+ LOG_INFO(_("^3kills^7 Number of kills\n"));
+ LOG_INFO(_("^3deaths^7 Number of deaths\n"));
+ LOG_INFO(_("^3suicides^7 Number of suicides\n"));
+ LOG_INFO(_("^3frags^7 kills - suicides\n"));
+ LOG_INFO(_("^3kd^7 The kill-death ratio\n"));
+ LOG_INFO(_("^3dmg^7 The total damage done\n"));
+ LOG_INFO(_("^3dmgtaken^7 The total damage taken\n"));
+ LOG_INFO(_("^3sum^7 frags - deaths\n"));
+ LOG_INFO(_("^3caps^7 How often a flag (CTF) or a key (KeyHunt) was captured\n"));
+ LOG_INFO(_("^3pickups^7 How often a flag (CTF) or a key (KeyHunt) or a ball (Keepaway) was picked up\n"));
+ LOG_INFO(_("^3captime^7 Time of fastest cap (CTF)\n"));
+ LOG_INFO(_("^3fckills^7 Number of flag carrier kills\n"));
+ LOG_INFO(_("^3returns^7 Number of flag returns\n"));
+ LOG_INFO(_("^3drops^7 Number of flag drops\n"));
+ LOG_INFO(_("^3lives^7 Number of lives (LMS)\n"));
+ LOG_INFO(_("^3rank^7 Player rank\n"));
+ LOG_INFO(_("^3pushes^7 Number of players pushed into void\n"));
+ LOG_INFO(_("^3destroyed^7 Number of keys destroyed by pushing them into void\n"));
+ LOG_INFO(_("^3kckills^7 Number of keys carrier kills\n"));
+ LOG_INFO(_("^3losses^7 Number of times a key was lost\n"));
+ LOG_INFO(_("^3laps^7 Number of laps finished (race/cts)\n"));
+ LOG_INFO(_("^3time^7 Total time raced (race/cts)\n"));
+ LOG_INFO(_("^3fastest^7 Time of fastest lap (race/cts)\n"));
+ LOG_INFO(_("^3ticks^7 Number of ticks (DOM)\n"));
+ LOG_INFO(_("^3takes^7 Number of domination points taken (DOM)\n"));
+ LOG_INFO(_("^3bckills^7 Number of ball carrier kills\n"));
+ LOG_INFO(_("^3bctime^7 Total amount of time holding the ball in Keepaway\n"));
+ LOG_INFO(_("^3score^7 Total score\n"));
+ LOG_INFO("\n");
+
+ LOG_INFO(_("Before a field you can put a + or - sign, then a comma separated list\n"
+ "of game types, then a slash, to make the field show up only in these\n"
+ "or in all but these game types. You can also specify 'all' as a\n"
+ "field to show all fields available for the current game mode.\n\n"));
+
+ LOG_INFO(_("The special game type names 'teams' and 'noteams' can be used to\n"
+ "include/exclude ALL teams/noteams game modes.\n\n"));
+
+ LOG_INFO(_("Example: scoreboard_columns_set name ping pl | +ctf/field3 -dm/field4\n"));
+ LOG_INFO(_("will display name, ping and pl aligned to the left, and the fields\n"
+ "right of the vertical bar aligned to the right.\n"));
+ LOG_INFO(_("'field3' will only be shown in CTF, and 'field4' will be shown in all\n"
+ "other gamemodes except DM.\n"));
+}
+
+// NOTE: adding a gametype with ? to not warn for an optional field
+// make sure it's excluded in a previous exclusive rule, if any
+// otherwise the previous exclusive rule warns anyway
+// e.g. -teams,rc,cts,lms/kills ?+rc/kills
+#define SCOREBOARD_DEFAULT_COLUMNS \
+"ping pl name |" \
+" -teams,rc,cts,inv,lms/kills +ft,tdm/kills ?+rc,inv/kills" \
+" -teams,lms/deaths +ft,tdm/deaths" \
+" -teams,lms,rc,cts,inv,ka/suicides +ft,tdm/suicides ?+rc,inv/suicides" \
+" -cts,dm,tdm,ka,ft/frags" /* tdm already has this in "score" */ \
+" -rc,cts,nb/dmg -rc,cts,nb/dmgtaken" \
+" +ctf/caps +ctf/pickups +ctf/fckills +ctf/returns +ons/caps +ons/takes" \
+" +lms/lives +lms/rank" \
+" +kh/caps +kh/pushes +kh/destroyed" \
+" ?+rc/laps ?+rc/time +rc,cts/fastest" \
+" +as/objectives +nb/faults +nb/goals" \
+" +ka/pickups +ka/bckills +ka/bctime +ft/revivals" \
+" -lms,rc,cts,inv,nb/score"
+
+void Cmd_Scoreboard_SetFields(int argc)
+{
+ TC(int, argc);
+ int i, slash;
+ string str, pattern;
+ float have_name = 0, have_primary = 0, have_secondary = 0, have_separator = 0;
+ float missing;
+
+ if(!gametype)
+ {
+ // set up a temporary scoreboard layout
+ // no layout can be properly set up until score_info data haven't been received
+ argc = tokenizebyseparator("0 1 ping pl name | score", " ");
+ ps_primary = SP_SCORE;
+ ps_secondary = SP_SCORE;
+ scores_label(ps_primary) = strzone("score");
+ scores_flags(ps_primary) = SFL_ALLOW_HIDE;
+ }
+
+ // TODO: re enable with gametype dependant cvars?
+ if(argc < 3) // no arguments provided
+ argc = tokenizebyseparator(strcat("0 1 ", autocvar_scoreboard_columns), " ");
+
+ if(argc < 3)
+ argc = tokenizebyseparator(strcat("0 1 ", SCOREBOARD_DEFAULT_COLUMNS), " ");
+
+ if(argc == 3)
+ {
+ if(argv(2) == "default")
+ argc = tokenizebyseparator(strcat("0 1 ", SCOREBOARD_DEFAULT_COLUMNS), " ");
+ else if(argv(2) == "all")
+ {
+ string s;
+ s = "ping pl name |";
+ FOREACH(Scores, true, {
+ if(it != ps_primary)
+ if(it != ps_secondary)
+ if(scores_label(it) != "")
+ s = strcat(s, " ", scores_label(it));
+ });
+ if(ps_secondary != ps_primary)
+ s = strcat(s, " ", scores_label(ps_secondary));
+ s = strcat(s, " ", scores_label(ps_primary));
+ argc = tokenizebyseparator(strcat("0 1 ", s), " ");
+ }
+ }
+
+
+ sbt_num_fields = 0;
+
+ hud_fontsize = HUD_GetFontsize("hud_fontsize");
+
+ for(i = 1; i < argc - 1; ++i)
+ {
+ float nocomplain;
+ str = argv(i+1);
+
+ nocomplain = false;
+ if(substring(str, 0, 1) == "?")
+ {
+ nocomplain = true;
+ str = substring(str, 1, strlen(str) - 1);
+ }
+
+ slash = strstrofs(str, "/", 0);
+ if(slash >= 0)
+ {
+ pattern = substring(str, 0, slash);
+ str = substring(str, slash + 1, strlen(str) - (slash + 1));
+
+ if (!isGametypeInFilter(gametype, teamplay, false, pattern))
+ continue;
+ }
+
+ strunzone(sbt_field_title[sbt_num_fields]);
+ sbt_field_title[sbt_num_fields] = strzone(TranslateScoresLabel(str));
+ sbt_field_size[sbt_num_fields] = stringwidth(sbt_field_title[sbt_num_fields], false, hud_fontsize);
+ str = strtolower(str);
+
+ PlayerScoreField j;
+ switch(str)
+ {
+ case "ping": sbt_field[sbt_num_fields] = SP_PING; break;
+ case "pl": sbt_field[sbt_num_fields] = SP_PL; break;
+ case "kd": case "kdr": case "kdratio": case "k/d": sbt_field[sbt_num_fields] = SP_KDRATIO; break;
+ case "sum": case "diff": case "k-d": sbt_field[sbt_num_fields] = SP_SUM; break;
+ case "name": case "nick": sbt_field[sbt_num_fields] = SP_NAME; have_name = true; break;
+ case "|": sbt_field[sbt_num_fields] = SP_SEPARATOR; have_separator = true; break;
+ case "elo": sbt_field[sbt_num_fields] = SP_ELO; break;
+ case "dmg": sbt_field[sbt_num_fields] = SP_DMG; break;
+ case "dmgtaken": sbt_field[sbt_num_fields] = SP_DMGTAKEN; break;
+ default:
+ {
+ FOREACH(Scores, true, {
+ if (str == strtolower(scores_label(it))) {
+ j = it;
+ goto found; // sorry, but otherwise fteqcc -O3 miscompiles this and warns about "unreachable code"
+ }
+ });
+
+LABEL(notfound)
+ if(str == "frags")
+ j = SP_FRAGS;
+ else
+ {
+ if(!nocomplain)
+ LOG_INFOF("^1Error:^7 Unknown score field: '%s'\n", str);
+ continue;
+ }
+LABEL(found)
+ sbt_field[sbt_num_fields] = j;
+ if(j == ps_primary)
+ have_primary = 1;
+ if(j == ps_secondary)
+ have_secondary = 1;
+
+ }
+ }
+ ++sbt_num_fields;
+ if(sbt_num_fields >= MAX_SBT_FIELDS)
+ break;
+ }
+
+ if(scores_flags(ps_primary) & SFL_ALLOW_HIDE)
+ have_primary = 1;
+ if(scores_flags(ps_secondary) & SFL_ALLOW_HIDE)
+ have_secondary = 1;
+ if(ps_primary == ps_secondary)
+ have_secondary = 1;
+ missing = (!have_primary) + (!have_secondary) + (!have_separator) + (!have_name);
+
+ if(sbt_num_fields + missing < MAX_SBT_FIELDS)
+ {
+ if(!have_name)
+ {
+ strunzone(sbt_field_title[sbt_num_fields]);
+ for(i = sbt_num_fields; i > 0; --i)
+ {
+ sbt_field_title[i] = sbt_field_title[i-1];
+ sbt_field_size[i] = sbt_field_size[i-1];
+ sbt_field[i] = sbt_field[i-1];
+ }
+ sbt_field_title[0] = strzone(TranslateScoresLabel("name"));
+ sbt_field[0] = SP_NAME;
+ ++sbt_num_fields;
+ LOG_INFO("fixed missing field 'name'\n");
+
+ if(!have_separator)
+ {
+ strunzone(sbt_field_title[sbt_num_fields]);
+ for(i = sbt_num_fields; i > 1; --i)
+ {
+ sbt_field_title[i] = sbt_field_title[i-1];
+ sbt_field_size[i] = sbt_field_size[i-1];
+ sbt_field[i] = sbt_field[i-1];
+ }
+ sbt_field_title[1] = strzone("|");
+ sbt_field[1] = SP_SEPARATOR;
+ sbt_field_size[1] = stringwidth("|", false, hud_fontsize);
+ ++sbt_num_fields;
+ LOG_INFO("fixed missing field '|'\n");
+ }
+ }
+ else if(!have_separator)
+ {
+ strunzone(sbt_field_title[sbt_num_fields]);
+ sbt_field_title[sbt_num_fields] = strzone("|");
+ sbt_field_size[sbt_num_fields] = stringwidth("|", false, hud_fontsize);
+ sbt_field[sbt_num_fields] = SP_SEPARATOR;
+ ++sbt_num_fields;
+ LOG_INFO("fixed missing field '|'\n");
+ }
+ if(!have_secondary)
+ {
+ strunzone(sbt_field_title[sbt_num_fields]);
+ sbt_field_title[sbt_num_fields] = strzone(TranslateScoresLabel(scores_label(ps_secondary)));
+ sbt_field_size[sbt_num_fields] = stringwidth(sbt_field_title[sbt_num_fields], false, hud_fontsize);
+ sbt_field[sbt_num_fields] = ps_secondary;
+ ++sbt_num_fields;
+ LOG_INFOF("fixed missing field '%s'\n", scores_label(ps_secondary));
+ }
+ if(!have_primary)
+ {
+ strunzone(sbt_field_title[sbt_num_fields]);
+ sbt_field_title[sbt_num_fields] = strzone(TranslateScoresLabel(scores_label(ps_primary)));
+ sbt_field_size[sbt_num_fields] = stringwidth(sbt_field_title[sbt_num_fields], false, hud_fontsize);
+ sbt_field[sbt_num_fields] = ps_primary;
+ ++sbt_num_fields;
+ LOG_INFOF("fixed missing field '%s'\n", scores_label(ps_primary));
+ }
+ }
+
+ sbt_field[sbt_num_fields] = SP_END;
+}
+
+// MOVEUP::
+vector sbt_field_rgb;
+string sbt_field_icon0;
+string sbt_field_icon1;
+string sbt_field_icon2;
+vector sbt_field_icon0_rgb;
+vector sbt_field_icon1_rgb;
+vector sbt_field_icon2_rgb;
+float sbt_field_icon0_alpha;
+float sbt_field_icon1_alpha;
+float sbt_field_icon2_alpha;
+string Scoreboard_GetField(entity pl, PlayerScoreField field)
+{
+ float tmp, num, denom;
+ int f;
+ string str;
+ sbt_field_rgb = '1 1 1';
+ sbt_field_icon0 = "";
+ sbt_field_icon1 = "";
+ sbt_field_icon2 = "";
+ sbt_field_icon0_rgb = '1 1 1';
+ sbt_field_icon1_rgb = '1 1 1';
+ sbt_field_icon2_rgb = '1 1 1';
+ sbt_field_icon0_alpha = 1;
+ sbt_field_icon1_alpha = 1;
+ sbt_field_icon2_alpha = 1;
+ switch(field)
+ {
+ case SP_PING:
+ if (!pl.gotscores)
+ return "\xE2\x96\xB6\xE2\x96\xB6\xE2\x96\xB6"; // >>> sign using U+25B6
+ //str = getplayerkeyvalue(pl.sv_entnum, "ping");
+ f = pl.ping;
+ if(f == 0)
+ return _("N/A");
+ tmp = max(0, min(220, f-80)) / 220;
+ sbt_field_rgb = '1 1 1' - '0 1 1' * tmp;
+ return ftos(f);
+
+ case SP_PL:
+ if (!pl.gotscores)
+ return _("N/A");
+ f = pl.ping_packetloss;
+ tmp = pl.ping_movementloss;
+ if(f == 0 && tmp == 0)
+ return "";
+ str = ftos(ceil(f * 100));
+ if(tmp != 0)
+ str = strcat(str, "~", ftos(ceil(tmp * 100)));
+ tmp = bound(0, f / 0.2 + tmp / 0.04, 1); // 20% is REALLY BAD pl
+ sbt_field_rgb = '1 0.5 0.5' - '0 0.5 0.5' * tmp;
+ return str;
+
+ case SP_NAME:
+ if(ready_waiting && pl.ready)
+ {
+ sbt_field_icon0 = "gfx/scoreboard/player_ready";
+ }
+ else if(!teamplay)
+ {
+ f = stof(getplayerkeyvalue(pl.sv_entnum, "colors"));
+ {
+ sbt_field_icon0 = "gfx/scoreboard/playercolor_base";
+ sbt_field_icon1 = "gfx/scoreboard/playercolor_shirt";
+ sbt_field_icon1_rgb = colormapPaletteColor(floor(f / 16), 0);
+ sbt_field_icon2 = "gfx/scoreboard/playercolor_pants";
+ sbt_field_icon2_rgb = colormapPaletteColor(f % 16, 1);
+ }
+ }
+ return entcs_GetName(pl.sv_entnum);
+
+ case SP_FRAGS:
+ f = pl.(scores(SP_KILLS));
+ f -= pl.(scores(SP_SUICIDES));
+ return ftos(f);
+
+ case SP_KDRATIO:
+ num = pl.(scores(SP_KILLS));
+ denom = pl.(scores(SP_DEATHS));
+
+ if(denom == 0) {
+ sbt_field_rgb = '0 1 0';
+ str = sprintf("%d", num);
+ } else if(num <= 0) {
+ sbt_field_rgb = '1 0 0';
+ str = sprintf("%.1f", num/denom);
+ } else
+ str = sprintf("%.1f", num/denom);
+ return str;
+
+ case SP_SUM:
+ f = pl.(scores(SP_KILLS));
+ f -= pl.(scores(SP_DEATHS));
+
+ if(f > 0) {
+ sbt_field_rgb = '0 1 0';
+ } else if(f == 0) {
+ sbt_field_rgb = '1 1 1';
+ } else {
+ sbt_field_rgb = '1 0 0';
+ }
+ return ftos(f);
+
+ case SP_ELO:
+ {
+ float elo = pl.(scores(SP_ELO));
+ switch (elo) {
+ case -1: return "...";
+ case -2: return _("N/A");
+ default: return ftos(elo);
+ }
+ }
+
+ case SP_DMG:
+ num = pl.(scores(SP_DMG));
+ denom = 1000;
+
+ str = sprintf("%.1f k", num/denom);
+ return str;
+
+ case SP_DMGTAKEN:
+ num = pl.(scores(SP_DMGTAKEN));
+ denom = 1000;
+
+ str = sprintf("%.1f k", num/denom);
+ return str;
+
+ default:
+ tmp = pl.(scores(field));
+ f = scores_flags(field);
+ if(field == ps_primary)
+ sbt_field_rgb = '1 1 0';
+ else if(field == ps_secondary)
+ sbt_field_rgb = '0 1 1';
+ else
+ sbt_field_rgb = '1 1 1';
+ return ScoreString(f, tmp);
+ }
+ //return "error";
+}
+
+float sbt_fixcolumnwidth_len;
+float sbt_fixcolumnwidth_iconlen;
+float sbt_fixcolumnwidth_marginlen;
+
+string Scoreboard_FixColumnWidth(int i, string str)
+{
+ TC(int, i);
+ float f;
+ vector sz;
+ PlayerScoreField field = sbt_field[i];
+
+ sbt_fixcolumnwidth_iconlen = 0;
+
+ if(sbt_field_icon0 != "")
+ {
+ sz = draw_getimagesize(sbt_field_icon0);
+ f = sz.x / sz.y;
+ if(sbt_fixcolumnwidth_iconlen < f)
+ sbt_fixcolumnwidth_iconlen = f;
+ }
+
+ if(sbt_field_icon1 != "")
+ {
+ sz = draw_getimagesize(sbt_field_icon1);
+ f = sz.x / sz.y;
+ if(sbt_fixcolumnwidth_iconlen < f)
+ sbt_fixcolumnwidth_iconlen = f;
+ }
+
+ if(sbt_field_icon2 != "")
+ {
+ sz = draw_getimagesize(sbt_field_icon2);
+ f = sz.x / sz.y;
+ if(sbt_fixcolumnwidth_iconlen < f)
+ sbt_fixcolumnwidth_iconlen = f;
+ }
+
+ sbt_fixcolumnwidth_iconlen *= hud_fontsize.y / hud_fontsize.x; // fix icon aspect
+
+ if(sbt_fixcolumnwidth_iconlen != 0)
+ sbt_fixcolumnwidth_marginlen = stringwidth(" ", false, hud_fontsize);
+ else
+ sbt_fixcolumnwidth_marginlen = 0;
+
+ if(field == SP_NAME) // name gets all remaining space
+ {
+ int j;
+ float namesize;
+ namesize = panel_size.x;
+ for(j = 0; j < sbt_num_fields; ++j)
+ if(j != i)
+ if (sbt_field[i] != SP_SEPARATOR)
+ namesize -= sbt_field_size[j] + hud_fontsize.x;
+ sbt_field_size[i] = namesize;
+
+ if (sbt_fixcolumnwidth_iconlen != 0)
+ namesize -= sbt_fixcolumnwidth_marginlen + sbt_fixcolumnwidth_iconlen * hud_fontsize.x;
+ str = textShortenToWidth(str, namesize, hud_fontsize, stringwidth_colors);
+ sbt_fixcolumnwidth_len = stringwidth(str, true, hud_fontsize);
+ }
+ else
+ sbt_fixcolumnwidth_len = stringwidth(str, false, hud_fontsize);
+
+ f = sbt_fixcolumnwidth_len + sbt_fixcolumnwidth_marginlen + sbt_fixcolumnwidth_iconlen * hud_fontsize.x;
+ if(sbt_field_size[i] < f)
+ sbt_field_size[i] = f;
+
+ return str;
+}
+
+vector Scoreboard_DrawHeader(vector pos, vector rgb)
+{
+ int i;
+ vector column_dim = eY * panel_size.y;
+ vector text_offset = eY * (1.25 - 1) / 2 * hud_fontsize.y;
+ pos.x += hud_fontsize.x * 0.5;
+ for(i = 0; i < sbt_num_fields; ++i)
+ {
+ if(sbt_field[i] == SP_SEPARATOR)
+ break;
+ column_dim.x = sbt_field_size[i] + hud_fontsize.x;
+ if (sbt_highlight)
+ if (i % 2)
+ drawfill(pos - eX * hud_fontsize.x * 0.5, column_dim, '0 0 0', sbt_highlight_alpha, DRAWFLAG_NORMAL);
+ drawstring(pos + text_offset, sbt_field_title[i], hud_fontsize, rgb * 1.5, sbt_fg_alpha, DRAWFLAG_NORMAL);
+ pos.x += column_dim.x;
+ }
+ if(sbt_field[i] == SP_SEPARATOR)
+ {
+ pos.x = panel_pos.x + panel_size.x - hud_fontsize.x * 0.5;
+ for(i = sbt_num_fields - 1; i > 0; --i)
+ {
+ if(sbt_field[i] == SP_SEPARATOR)
+ break;
+
+ pos.x -= sbt_field_size[i];
+
+ if (sbt_highlight)
+ if (!(i % 2))
+ {
+ if (i == sbt_num_fields-1)
+ column_dim.x = sbt_field_size[i] + hud_fontsize.x * 0.5;
+ else
+ column_dim.x = sbt_field_size[i] + hud_fontsize.x;
+ drawfill(pos - eX * hud_fontsize.x * 0.5, column_dim, '0 0 0', sbt_highlight_alpha, DRAWFLAG_NORMAL);
+ }
+
+ text_offset.x = sbt_field_size[i] - stringwidth(sbt_field_title[i], false, hud_fontsize);
+ drawstring(pos + text_offset, sbt_field_title[i], hud_fontsize, rgb * 1.5, sbt_fg_alpha, DRAWFLAG_NORMAL);
+ pos.x -= hud_fontsize.x;
+ }
+ }
+
+ pos.x = panel_pos.x;
+ pos.y += 1.25 * hud_fontsize.y;
+ return pos;
+}
+
+void Scoreboard_DrawItem(vector item_pos, vector rgb, entity pl, bool is_self, int pl_number)
+{
+ TC(bool, is_self); TC(int, pl_number);
+ string str;
+ bool is_spec = (entcs_GetTeam(pl.sv_entnum) == NUM_SPECTATOR);
+ if(is_spec && !is_self)
+ rgb = '0 0 0';
+
+ vector h_pos = item_pos;
+ vector h_size = eX * panel_size.x + eY * hud_fontsize.y * 1.25;
+ // alternated rows highlighting
+ if(is_self)
+ drawfill(h_pos, h_size, rgb, sbt_highlight_alpha_self, DRAWFLAG_NORMAL);
+ else if((sbt_highlight) && (!(pl_number % 2)))
+ drawfill(h_pos, h_size, rgb, sbt_highlight_alpha, DRAWFLAG_NORMAL);
+
+ vector pos = item_pos;
+ pos.x += hud_fontsize.x * 0.5;
+ pos.y += (1.25 - 1) / 2 * hud_fontsize.y; // center text vertically
+ vector tmp = '0 0 0';
+ int i;
+ PlayerScoreField field;
+ for(i = 0; i < sbt_num_fields; ++i)
+ {
+ field = sbt_field[i];
+ if(field == SP_SEPARATOR)
+ break;
+
+ if(is_spec && field != SP_NAME && field != SP_PING) {
+ pos.x += sbt_field_size[i] + hud_fontsize.x;
+ continue;
+ }
+ str = Scoreboard_GetField(pl, field);
+ str = Scoreboard_FixColumnWidth(i, str);
+
+ pos.x += sbt_field_size[i] + hud_fontsize.x;
+
+ if(field == SP_NAME) {
+ tmp.x = sbt_field_size[i] - hud_fontsize.x * sbt_fixcolumnwidth_iconlen - sbt_fixcolumnwidth_marginlen + hud_fontsize.x;
+ if (is_self)
+ drawcolorcodedstring(pos - tmp, str, hud_fontsize, sbt_fg_alpha_self, DRAWFLAG_NORMAL);
+ else
+ drawcolorcodedstring(pos - tmp, str, hud_fontsize, sbt_fg_alpha, DRAWFLAG_NORMAL);
+ } else {
+ tmp.x = sbt_fixcolumnwidth_len + hud_fontsize.x;
+ if (is_self)
+ drawstring(pos - tmp, str, hud_fontsize, sbt_field_rgb, sbt_fg_alpha_self, DRAWFLAG_NORMAL);
+ else
+ drawstring(pos - tmp, str, hud_fontsize, sbt_field_rgb, sbt_fg_alpha, DRAWFLAG_NORMAL);
+ }
+
+ tmp.x = sbt_field_size[i] + hud_fontsize.x;
+ if(sbt_field_icon0 != "")
+ if (is_self)
+ drawpic(pos - tmp, sbt_field_icon0, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon1_rgb, sbt_field_icon0_alpha * sbt_fg_alpha_self, DRAWFLAG_NORMAL);
+ else
+ drawpic(pos - tmp, sbt_field_icon0, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon1_rgb, sbt_field_icon0_alpha * sbt_fg_alpha, DRAWFLAG_NORMAL);
+ if(sbt_field_icon1 != "")
+ if (is_self)
+ drawpic(pos - tmp, sbt_field_icon1, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon1_rgb, sbt_field_icon1_alpha * sbt_fg_alpha_self, DRAWFLAG_NORMAL);
+ else
+ drawpic(pos - tmp, sbt_field_icon1, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon1_rgb, sbt_field_icon1_alpha * sbt_fg_alpha, DRAWFLAG_NORMAL);
+ if(sbt_field_icon2 != "")
+ if (is_self)
+ drawpic(pos - tmp, sbt_field_icon2, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon2_rgb, sbt_field_icon2_alpha * sbt_fg_alpha_self, DRAWFLAG_NORMAL);
+ else
+ drawpic(pos - tmp, sbt_field_icon2, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon2_rgb, sbt_field_icon2_alpha * sbt_fg_alpha, DRAWFLAG_NORMAL);
+ }
+
+ if(sbt_field[i] == SP_SEPARATOR)
+ {
+ pos.x = item_pos.x + panel_size.x - hud_fontsize.x * 0.5;
+ for(i = sbt_num_fields-1; i > 0; --i)
+ {
+ field = sbt_field[i];
+ if(field == SP_SEPARATOR)
+ break;
+
+ if(is_spec && field != SP_NAME && field != SP_PING) {
+ pos.x -= sbt_field_size[i] + hud_fontsize.x;
+ continue;
+ }
+
+ str = Scoreboard_GetField(pl, field);
+ str = Scoreboard_FixColumnWidth(i, str);
+
+ if(field == SP_NAME) {
+ tmp.x = sbt_fixcolumnwidth_len; // left or right aligned? let's put it right...
+ if(is_self)
+ drawcolorcodedstring(pos - tmp, str, hud_fontsize, sbt_fg_alpha_self, DRAWFLAG_NORMAL);
+ else
+ drawcolorcodedstring(pos - tmp, str, hud_fontsize, sbt_fg_alpha, DRAWFLAG_NORMAL);
+ } else {
+ tmp.x = sbt_fixcolumnwidth_len;
+ if(is_self)
+ drawstring(pos - tmp, str, hud_fontsize, sbt_field_rgb, sbt_fg_alpha_self, DRAWFLAG_NORMAL);
+ else
+ drawstring(pos - tmp, str, hud_fontsize, sbt_field_rgb, sbt_fg_alpha, DRAWFLAG_NORMAL);
+ }
+
+ tmp.x = sbt_field_size[i];
+ if(sbt_field_icon0 != "")
+ if (is_self)
+ drawpic(pos - tmp, sbt_field_icon0, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon1_rgb, sbt_field_icon0_alpha * sbt_fg_alpha_self, DRAWFLAG_NORMAL);
+ else
+ drawpic(pos - tmp, sbt_field_icon0, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon1_rgb, sbt_field_icon0_alpha * sbt_fg_alpha, DRAWFLAG_NORMAL);
+ if(sbt_field_icon1 != "")
+ if (is_self)
+ drawpic(pos - tmp, sbt_field_icon1, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon1_rgb, sbt_field_icon1_alpha * sbt_fg_alpha_self, DRAWFLAG_NORMAL);
+ else
+ drawpic(pos - tmp, sbt_field_icon1, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon1_rgb, sbt_field_icon1_alpha * sbt_fg_alpha, DRAWFLAG_NORMAL);
+ if(sbt_field_icon2 != "")
+ if (is_self)
+ drawpic(pos - tmp, sbt_field_icon2, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon2_rgb, sbt_field_icon2_alpha * sbt_fg_alpha_self, DRAWFLAG_NORMAL);
+ else
+ drawpic(pos - tmp, sbt_field_icon2, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon2_rgb, sbt_field_icon2_alpha * sbt_fg_alpha, DRAWFLAG_NORMAL);
+ pos.x -= sbt_field_size[i] + hud_fontsize.x;
+ }
+ }
+
+ if(pl.eliminated)
+ drawfill(h_pos, h_size, '0 0 0', 0.5 * panel_fg_alpha, DRAWFLAG_NORMAL);
+}
+
+vector Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_size)
+{
+ entity pl;
+
+ panel_pos = pos;
+ panel_size.y = 1.25 * hud_fontsize.y * (1 + max(1, tm.team_size));
+ panel_size.y += panel_bg_padding * 2;
+ HUD_Panel_DrawBg(scoreboard_fade_alpha);
+
+ vector end_pos = panel_pos + eY * (panel_size.y + hud_fontsize.y);
+ if(panel.current_panel_bg != "0")
+ end_pos.y += panel_bg_border * 2;
+
+ if(panel_bg_padding)
+ {
+ panel_pos += '1 1 0' * panel_bg_padding;
+ panel_size -= '2 2 0' * panel_bg_padding;
+ }
+
+ pos = panel_pos;
+ vector tmp = eX * panel_size.x + eY * 1.25 * hud_fontsize.y;
+
+ // rounded header
+ if (sbt_bg_alpha)
+ drawpic(pos, "gfx/scoreboard/scoreboard_tableheader", tmp, rgb + '0.5 0.5 0.5', sbt_bg_alpha, DRAWFLAG_NORMAL);
+
+ pos.y += 1.25 * hud_fontsize.y;
+
+ // table background
+ tmp.y = panel_size.y - 1.25 * hud_fontsize.y;
+ if (sbt_bg_alpha)
+ drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, sbt_bg_alpha, DRAWFLAG_NORMAL);
+
+
+ // print header row and highlight columns
+ pos = Scoreboard_DrawHeader(panel_pos, rgb);
+
+ // fill the table and draw the rows
+ int i = 0;
+ if (teamplay)
+ for(pl = players.sort_next; pl; pl = pl.sort_next)
+ {
+ if(pl.team != tm.team)
+ continue;
+ Scoreboard_DrawItem(pos, rgb, pl, (pl.sv_entnum == player_localnum), i);
+ pos.y += 1.25 * hud_fontsize.y;
+ ++i;
+ }
+ else
+ for(pl = players.sort_next; pl; pl = pl.sort_next)
+ {
+ if(pl.team == NUM_SPECTATOR)
+ continue;
+ Scoreboard_DrawItem(pos, rgb, pl, (pl.sv_entnum == player_localnum), i);
+ pos.y += 1.25 * hud_fontsize.y;
+ ++i;
+ }
+
+ panel_size.x += panel_bg_padding * 2; // restore initial width
+ return end_pos;
+}
+
+float Scoreboard_WouldDraw() {
+ if (QuickMenu_IsOpened())
+ return 0;
+ else if (HUD_Radar_Clickable())
+ return 0;
+ else if (scoreboard_showscores)
+ return 1;
+ else if (intermission == 1)
+ return 1;
+ else if (intermission == 2)
+ return 0;
+ else if (spectatee_status != -1 && STAT(HEALTH) <= 0 && autocvar_cl_deathscoreboard && gametype != MAPINFO_TYPE_CTS && !active_minigame)
+ return 1;
+ else if (scoreboard_showscores_force)
+ return 1;
+ return 0;
+}
+
+float average_accuracy;
+vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size)
+{
+ WepSet weapons_stat = WepSet_GetFromStat();
+ WepSet weapons_inmap = WepSet_GetFromStat_InMap();
+ int disownedcnt = 0;
+ FOREACH(Weapons, it != WEP_Null, {
+ int weapon_stats = weapon_accuracy[i - WEP_FIRST];
+
+ WepSet set = it.m_wepset;
+ if (weapon_stats < 0 && !(weapons_stat & set || weapons_inmap & set))
+ ++disownedcnt;
+ });
+
+ int weapon_cnt = (Weapons_COUNT - 1) - disownedcnt;
+ if (weapon_cnt <= 0) return pos;
+
+ int rows = 1;
+ if (autocvar_hud_panel_scoreboard_accuracy_doublerows && weapon_cnt >= floor((Weapons_COUNT - 1) * 0.5))
+ rows = 2;
+ int columnns = ceil(weapon_cnt / rows);
+
+ float height = 40;
+
+ drawstring(pos + eX * panel_bg_padding, sprintf(_("Accuracy stats (average %d%%)"), average_accuracy), hud_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ pos.y += 1.25 * hud_fontsize.y;
+ if(panel.current_panel_bg != "0")
+ pos.y += panel_bg_border;
+
+ panel_pos = pos;
+ panel_size.y = height * rows;
+ panel_size.y += panel_bg_padding * 2;
+ HUD_Panel_DrawBg(scoreboard_fade_alpha);
+
+ vector end_pos = panel_pos + eY * (panel_size.y + hud_fontsize.y);
+ if(panel.current_panel_bg != "0")
+ end_pos.y += panel_bg_border * 2;
+
+ if(panel_bg_padding)
+ {
+ panel_pos += '1 1 0' * panel_bg_padding;
+ panel_size -= '2 2 0' * panel_bg_padding;
+ }
+
+ pos = panel_pos;
+ vector tmp = panel_size;
+
+ float fontsize = height * 1/3;
+ float weapon_height = height * 2/3;
+ float weapon_width = tmp.x / columnns / rows;
+
+ if (sbt_bg_alpha)
+ drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, sbt_bg_alpha, DRAWFLAG_NORMAL);
+
+ if(sbt_highlight)
+ {
+ // column highlighting
+ for (int i = 0; i < columnns; ++i)
+ if ((i % 2) == 0)
+ drawfill(pos + eX * weapon_width * rows * i, eY * height * rows + eX * weapon_width * rows, '0 0 0', sbt_highlight_alpha, DRAWFLAG_NORMAL);
+
+ // row highlighting
+ for (int i = 0; i < rows; ++i)
+ drawfill(pos + eY * weapon_height + eY * height * i, eX * tmp.x + eY * fontsize, '1 1 1', sbt_highlight_alpha, DRAWFLAG_NORMAL);
+ }
+
+ average_accuracy = 0;
+ int weapons_with_stats = 0;
+ if (rows == 2)
+ pos.x += weapon_width / 2;
+
+ if (autocvar_hud_panel_scoreboard_accuracy_nocolors)
+ rgb = '1 1 1';
+ else
+ Accuracy_LoadColors();
+
+ float oldposx = pos.x;
+ vector tmpos = pos;
+
+ int column = 0;
+ FOREACH(Weapons, it != WEP_Null, {
+ int weapon_stats = weapon_accuracy[i - WEP_FIRST];
+
+ WepSet set = it.m_wepset;
+ if (weapon_stats < 0 && !(weapons_stat & set || weapons_inmap & set))
+ continue;
+
+ float weapon_alpha;
+ if (weapon_stats >= 0)
+ weapon_alpha = sbt_fg_alpha;
+ else
+ weapon_alpha = 0.2 * sbt_fg_alpha;
+
+ // weapon icon
+ drawpic_aspect_skin(tmpos, it.model2, eX * weapon_width + eY * weapon_height, '1 1 1', weapon_alpha, DRAWFLAG_NORMAL);
+ // the accuracy
+ if (weapon_stats >= 0) {
+ weapons_with_stats += 1;
+ average_accuracy += weapon_stats; // store sum of all accuracies in average_accuracy
+
+ string s;
+ s = sprintf("%d%%", weapon_stats * 100);
+
+ float padding;
+ padding = (weapon_width - stringwidth(s, false, eX * fontsize)) / 2; // center the accuracy value
+
+ if(!autocvar_hud_panel_scoreboard_accuracy_nocolors)
+ rgb = Accuracy_GetColor(weapon_stats);
+
+ drawstring(tmpos + eX * padding + eY * weapon_height, s, '1 1 0' * fontsize, rgb, sbt_fg_alpha, DRAWFLAG_NORMAL);
+ }
+ tmpos.x += weapon_width * rows;
+ pos.x += weapon_width * rows;
+ if (rows == 2 && column == columnns - 1) {
+ tmpos.x = oldposx;
+ tmpos.y += height;
+ pos.y += height;
+ }
+ ++column;
+ });
+
+ if (weapons_with_stats)
+ average_accuracy = floor((average_accuracy * 100 / weapons_with_stats) + 0.5);
+
+ panel_size.x += panel_bg_padding * 2; // restore initial width
+ return end_pos;
+}
+
+vector MapStats_DrawKeyValue(vector pos, string key, string value) {
+ float px = pos.x;
+ pos.x += hud_fontsize.x * 0.25;
+ drawstring(pos, key, hud_fontsize, '1 1 1', sbt_fg_alpha, DRAWFLAG_NORMAL);
+ pos.x = panel_pos.x + panel_size.x - stringwidth(value, false, hud_fontsize) - hud_fontsize.x * 0.25;
+ drawstring(pos, value, hud_fontsize, '1 1 1', sbt_fg_alpha, DRAWFLAG_NORMAL);
+ pos.x = px;
+ pos.y += hud_fontsize.y;
+
+ return pos;
+}
+
+vector Scoreboard_MapStats_Draw(vector pos, vector rgb, vector bg_size) {
+ float stat_secrets_found, stat_secrets_total;
+ float stat_monsters_killed, stat_monsters_total;
+ float rows = 0;
+ string val;
+
+ // get monster stats
+ stat_monsters_killed = STAT(MONSTERS_KILLED);
+ stat_monsters_total = STAT(MONSTERS_TOTAL);
+
+ // get secrets stats
+ stat_secrets_found = STAT(SECRETS_FOUND);
+ stat_secrets_total = STAT(SECRETS_TOTAL);
+
+ // get number of rows
+ if(stat_secrets_total)
+ rows += 1;
+ if(stat_monsters_total)
+ rows += 1;
+
+ // if no rows, return
+ if (!rows)
+ return pos;
+
+ // draw table header
+ drawstring(pos + eX * panel_bg_padding, _("Map stats:"), hud_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ pos.y += 1.25 * hud_fontsize.y;
+ if(panel.current_panel_bg != "0")
+ pos.y += panel_bg_border;
+
+ panel_pos = pos;
+ panel_size.y = hud_fontsize.y * rows;
+ panel_size.y += panel_bg_padding * 2;
+ HUD_Panel_DrawBg(scoreboard_fade_alpha);
+
+ vector end_pos = panel_pos + eY * (panel_size.y + hud_fontsize.y);
+ if(panel.current_panel_bg != "0")
+ end_pos.y += panel_bg_border * 2;
+
+ if(panel_bg_padding)
+ {
+ panel_pos += '1 1 0' * panel_bg_padding;
+ panel_size -= '2 2 0' * panel_bg_padding;
+ }
+
+ pos = panel_pos;
+ vector tmp = panel_size;
+
+ if (sbt_bg_alpha)
+ drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, sbt_bg_alpha, DRAWFLAG_NORMAL);
+
+ // draw monsters
+ if(stat_monsters_total)
+ {
+ val = sprintf("%d/%d", stat_monsters_killed, stat_monsters_total);
+ pos = MapStats_DrawKeyValue(pos, _("Monsters killed:"), val);
+ }
+
+ // draw secrets
+ if(stat_secrets_total)
+ {
+ val = sprintf("%d/%d", stat_secrets_found, stat_secrets_total);
+ pos = MapStats_DrawKeyValue(pos, _("Secrets found:"), val);
+ }
+
+ panel_size.x += panel_bg_padding * 2; // restore initial width
+ return end_pos;
+}
+
+
+vector Scoreboard_Rankings_Draw(vector pos, entity pl, vector rgb, vector bg_size)
+{
+ int i;
+ RANKINGS_RECEIVED_CNT = 0;
+ for (i=RANKINGS_CNT-1; i>=0; --i)
+ if (grecordtime[i])
+ ++RANKINGS_RECEIVED_CNT;
+
+ if (RANKINGS_RECEIVED_CNT == 0)
+ return pos;
+
+ vector hl_rgb = rgb + '0.5 0.5 0.5';
+
+ pos.y += hud_fontsize.y;
+ drawstring(pos + eX * panel_bg_padding, _("Rankings"), hud_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ pos.y += 1.25 * hud_fontsize.y;
+ if(panel.current_panel_bg != "0")
+ pos.y += panel_bg_border;
+
+ panel_pos = pos;
+ panel_size.y = 1.25 * hud_fontsize.y * RANKINGS_RECEIVED_CNT;
+ panel_size.y += panel_bg_padding * 2;
+ HUD_Panel_DrawBg(scoreboard_fade_alpha);
+
+ vector end_pos = panel_pos + eY * (panel_size.y + hud_fontsize.y);
+ if(panel.current_panel_bg != "0")
+ end_pos.y += panel_bg_border * 2;
+
+ if(panel_bg_padding)
+ {
+ panel_pos += '1 1 0' * panel_bg_padding;
+ panel_size -= '2 2 0' * panel_bg_padding;
+ }
+
+ pos = panel_pos;
+ vector tmp = panel_size;
+
+ if (sbt_bg_alpha)
+ drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, sbt_bg_alpha, DRAWFLAG_NORMAL);
+
+ // row highlighting
+ for(i = 0; i < RANKINGS_RECEIVED_CNT; ++i)
+ {
+ string n, p;
+ float t;
+ t = grecordtime[i];
+ if (t == 0)
+ continue;
+ n = grecordholder[i];
+ p = count_ordinal(i+1);
+ if(grecordholder[i] == entcs_GetName(player_localnum))
+ drawfill(pos, eX * panel_size.x + '0 1.25 0' * hud_fontsize.y, hl_rgb, sbt_highlight_alpha_self, DRAWFLAG_NORMAL);
+ else if(!(i % 2) && sbt_highlight)
+ drawfill(pos, eX * panel_size.x + '0 1.25 0' * hud_fontsize.y, hl_rgb, sbt_highlight_alpha, DRAWFLAG_NORMAL);
+ drawstring(pos, p, '1 1 0' * hud_fontsize.y, '1 1 1', sbt_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring(pos + '3 0 0' * hud_fontsize.y, TIME_ENCODED_TOSTRING(t), '1 1 0' * hud_fontsize.y, '1 1 1', sbt_fg_alpha, DRAWFLAG_NORMAL);
+ drawcolorcodedstring(pos + '8 0 0' * hud_fontsize.y, n, '1 1 0' * hud_fontsize.y, sbt_fg_alpha, DRAWFLAG_NORMAL);
+ pos.y += 1.25 * hud_fontsize.y;
+ }
+
+ panel_size.x += panel_bg_padding * 2; // restore initial width
+ return end_pos;
+}
+
+void Scoreboard_Draw()
+{
+ if(!autocvar__hud_configure)
+ {
+ // frametime checks allow to toggle the scoreboard even when the game is paused
+ if(scoreboard_active) {
+ if(hud_configure_menu_open == 1)
+ scoreboard_fade_alpha = 1;
+ float scoreboard_fadeinspeed = autocvar_hud_panel_scoreboard_fadeinspeed;
+ if (scoreboard_fadeinspeed && frametime)
+ scoreboard_fade_alpha = min(1, scoreboard_fade_alpha + frametime * scoreboard_fadeinspeed);
+ else
+ scoreboard_fade_alpha = 1;
+ }
+ else {
+ float scoreboard_fadeoutspeed = autocvar_hud_panel_scoreboard_fadeoutspeed;
+ if (scoreboard_fadeoutspeed && frametime)
+ scoreboard_fade_alpha = max(0, scoreboard_fade_alpha - frametime * scoreboard_fadeoutspeed);
+ else
+ scoreboard_fade_alpha = 0;
+ }
+
+ if (!scoreboard_fade_alpha)
+ return;
+ }
+ else
+ scoreboard_fade_alpha = 0;
+
+ if (autocvar_hud_panel_scoreboard_dynamichud)
+ HUD_Scale_Enable();
+ else
+ HUD_Scale_Disable();
+
+ float hud_fade_alpha_save = hud_fade_alpha;
+ if(hud_configure_menu_open == 1)
+ hud_fade_alpha = 1;
+ else
+ hud_fade_alpha = scoreboard_fade_alpha * (1 - autocvar__menu_alpha);
+ HUD_Panel_UpdateCvars();
+
+ sbt_bg_alpha = autocvar_hud_panel_scoreboard_table_bg_alpha * panel_fg_alpha;
+ sbt_highlight = autocvar_hud_panel_scoreboard_table_highlight;
+ sbt_highlight_alpha = autocvar_hud_panel_scoreboard_table_highlight_alpha * panel_fg_alpha;
+ sbt_highlight_alpha_self = autocvar_hud_panel_scoreboard_table_highlight_alpha_self * panel_fg_alpha;
+ sbt_fg_alpha = autocvar_hud_panel_scoreboard_table_fg_alpha * panel_fg_alpha;
+ sbt_fg_alpha_self = autocvar_hud_panel_scoreboard_table_fg_alpha_self * panel_fg_alpha;
+
+ hud_fade_alpha = hud_fade_alpha_save;
+
+ // don't overlap with con_notify
+ if(!autocvar__hud_configure)
+ panel_pos.y = max((autocvar_con_notify * autocvar_con_notifysize), panel_pos.y);
+
+ Scoreboard_UpdatePlayerTeams();
+
+ vector pos, tmp;
+ entity pl, tm;
+ string str;
+
+ // Initializes position
+ pos = panel_pos;
+
+ // Heading
+ vector sb_heading_fontsize;
+ sb_heading_fontsize = hud_fontsize * 2;
+ draw_beginBoldFont();
+ drawstring(pos + eX * panel_bg_padding, _("Scoreboard"), sb_heading_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ draw_endBoldFont();
+
+ pos.y += sb_heading_fontsize.y;
+ if(panel.current_panel_bg != "0")
+ pos.y += panel_bg_border;
+
+ // Draw the scoreboard
+ float scale = autocvar_hud_panel_scoreboard_table_bg_scale;
+ if(scale <= 0)
+ scale = 0.25;
+ vector bg_size = draw_getimagesize("gfx/scoreboard/scoreboard_bg") * scale;
+
+ if(teamplay)
+ {
+ vector panel_bg_color_save = panel_bg_color;
+ vector team_score_baseoffset = eY * hud_fontsize.y - eX * hud_fontsize.x * 0.5;
+ if(panel.current_panel_bg != "0")
+ team_score_baseoffset.x -= panel_bg_border;
+ for(tm = teams.sort_next; tm; tm = tm.sort_next)
+ {
+ if(tm.team == NUM_SPECTATOR)
+ continue;
+ if(!tm.team)
+ continue;
+
+ draw_beginBoldFont();
+ vector rgb = Team_ColorRGB(tm.team);
+ str = ftos(tm.(teamscores(ts_primary)));
+ drawstring(pos + team_score_baseoffset - eX * stringwidth(str, false, hud_fontsize * 1.5), str, hud_fontsize * 1.5, rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ if(ts_primary != ts_secondary)
+ {
+ str = ftos(tm.(teamscores(ts_secondary)));
+ drawstring(pos + team_score_baseoffset - eX * stringwidth(str, false, hud_fontsize) + eY * hud_fontsize.y * 1.5, str, hud_fontsize, rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+ draw_endBoldFont();
+ if(autocvar_hud_panel_scoreboard_bg_teams_color_team > 0)
+ panel_bg_color = rgb * autocvar_hud_panel_scoreboard_bg_teams_color_team;
+ else if(panel_bg_color_team > 0)
+ panel_bg_color = rgb * panel_bg_color_team;
+ else
+ panel_bg_color = rgb;
+ pos = Scoreboard_MakeTable(pos, tm, panel_bg_color, bg_size);
+ }
+ panel_bg_color = panel_bg_color_save;
+ }
+ else
+ {
+ for(tm = teams.sort_next; tm; tm = tm.sort_next)
+ {
+ if(tm.team == NUM_SPECTATOR)
+ continue;
+
+ pos = Scoreboard_MakeTable(pos, tm, panel_bg_color, bg_size);
+ }
+ }
+
+ if(gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE) {
+ if(race_speedaward) {
+ drawcolorcodedstring(pos, sprintf(_("Speed award: %d%s ^7(%s^7)"), race_speedaward, race_speedaward_unit, race_speedaward_holder), hud_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+ pos.y += 1.25 * hud_fontsize.y;
+ }
+ if(race_speedaward_alltimebest) {
+ drawcolorcodedstring(pos, sprintf(_("All-time fastest: %d%s ^7(%s^7)"), race_speedaward_alltimebest, race_speedaward_alltimebest_unit, race_speedaward_alltimebest_holder), hud_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+ pos.y += 1.25 * hud_fontsize.y;
+ }
+ pos = Scoreboard_Rankings_Draw(pos, playerslots[player_localnum], panel_bg_color, bg_size);
+ }
+ else if (autocvar_hud_panel_scoreboard_accuracy && !warmup_stage && gametype != MAPINFO_TYPE_NEXBALL)
+ pos = Scoreboard_AccuracyStats_Draw(pos, panel_bg_color, bg_size);
+
+ pos = Scoreboard_MapStats_Draw(pos, panel_bg_color, bg_size);
+
+ // List spectators
+ float specs = 0;
+ tmp = pos;
+ for(pl = players.sort_next; pl; pl = pl.sort_next)
+ {
+ if(pl.team != NUM_SPECTATOR)
+ continue;
+ pos.y += 1.25 * hud_fontsize.y;
+ Scoreboard_DrawItem(pos, panel_bg_color, pl, (pl.sv_entnum == player_localnum), specs);
+ ++specs;
+ }
+
+ if(specs)
+ {
+ draw_beginBoldFont();
+ drawstring(tmp, _("Spectators"), hud_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ draw_endBoldFont();
+ pos.y += 1.25 * hud_fontsize.y;
+ }
+
+ // Print info string
+ float tl, fl, ll;
+ str = sprintf(_("playing ^3%s^7 on ^2%s^7"), MapInfo_Type_ToText(gametype), shortmapname);
+ tl = STAT(TIMELIMIT);
+ fl = STAT(FRAGLIMIT);
+ ll = STAT(LEADLIMIT);
+ if(gametype == MAPINFO_TYPE_LMS)
+ {
+ if(tl > 0)
+ str = strcat(str, sprintf(_(" for up to ^1%1.0f minutes^7"), tl));
+ }
+ else
+ {
+ if(tl > 0)
+ str = strcat(str, sprintf(_(" for up to ^1%1.0f minutes^7"), tl));
+ if(fl > 0)
+ {
+ if(tl > 0)
+ str = strcat(str, _(" or"));
+ if(teamplay)
+ {
+ str = strcat(str, sprintf(_(" until ^3%s %s^7"), ScoreString(teamscores_flags(ts_primary), fl),
+ (teamscores_label(ts_primary) == "score") ? CTX(_("SCO^points")) :
+ (teamscores_label(ts_primary) == "fastest") ? CTX(_("SCO^is beaten")) :
+ TranslateScoresLabel(teamscores_label(ts_primary))));
+ }
+ else
+ {
+ str = strcat(str, sprintf(_(" until ^3%s %s^7"), ScoreString(scores_flags(ps_primary), fl),
+ (scores_label(ps_primary) == "score") ? CTX(_("SCO^points")) :
+ (scores_label(ps_primary) == "fastest") ? CTX(_("SCO^is beaten")) :
+ TranslateScoresLabel(scores_label(ps_primary))));
+ }
+ }
+ if(ll > 0)
+ {
+ if(tl > 0 || fl > 0)
+ str = strcat(str, _(" or"));
+ if(teamplay)
+ {
+ str = strcat(str, sprintf(_(" until a lead of ^3%s %s^7"), ScoreString(teamscores_flags(ts_primary), ll),
+ (teamscores_label(ts_primary) == "score") ? CTX(_("SCO^points")) :
+ (teamscores_label(ts_primary) == "fastest") ? CTX(_("SCO^is beaten")) :
+ TranslateScoresLabel(teamscores_label(ts_primary))));
+ }
+ else
+ {
+ str = strcat(str, sprintf(_(" until a lead of ^3%s %s^7"), ScoreString(scores_flags(ps_primary), ll),
+ (scores_label(ps_primary) == "score") ? CTX(_("SCO^points")) :
+ (scores_label(ps_primary) == "fastest") ? CTX(_("SCO^is beaten")) :
+ TranslateScoresLabel(scores_label(ps_primary))));
+ }
+ }
+ }
+
+ pos.y += 1.2 * hud_fontsize.y;
+ drawcolorcodedstring(pos + '0.5 0 0' * (panel_size.x - stringwidth(str, true, hud_fontsize)), str, hud_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ // print information about respawn status
+ float respawn_time = STAT(RESPAWN_TIME);
+ if(!intermission)
+ if(respawn_time)
+ {
+ if(respawn_time < 0)
+ {
+ // a negative number means we are awaiting respawn, time value is still the same
+ respawn_time *= -1; // remove mark now that we checked it
+
+ if(respawn_time < time) // it happens for a few frames when server is respawning the player
+ str = ""; // draw an empty string to not change suddenly scoreboard_bottom
+ else
+ str = sprintf(_("^1Respawning in ^3%s^1..."),
+ (autocvar_hud_panel_scoreboard_respawntime_decimals ?
+ count_seconds_decs(respawn_time - time, autocvar_hud_panel_scoreboard_respawntime_decimals)
+ :
+ count_seconds(ceil(respawn_time - time))
+ )
+ );
+ }
+ else if(time < respawn_time)
+ {
+ str = sprintf(_("You are dead, wait ^3%s^7 before respawning"),
+ (autocvar_hud_panel_scoreboard_respawntime_decimals ?
+ count_seconds_decs(respawn_time - time, autocvar_hud_panel_scoreboard_respawntime_decimals)
+ :
+ count_seconds(ceil(respawn_time - time))
+ )
+ );
+ }
+ else if(time >= respawn_time)
+ str = sprintf(_("You are dead, press ^2%s^7 to respawn"), getcommandkey("jump", "+jump"));
+
+ pos.y += 1.2 * hud_fontsize.y;
+ drawcolorcodedstring(pos + '0.5 0 0' * (panel_size.x - stringwidth(str, true, hud_fontsize)), str, hud_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+
+ scoreboard_bottom = pos.y + 2 * hud_fontsize.y;
+}
--- /dev/null
+#pragma once
+#include "../panel.qh"
+
+float scoreboard_active;
+float scoreboard_fade_alpha;
+
+void Cmd_Scoreboard_SetFields(float argc);
+void Scoreboard_Draw();
+void Scoreboard_InitScores();
+void Scoreboard_UpdatePlayerPos(entity pl);
+void Scoreboard_UpdateTeamPos(entity Team);
+float Scoreboard_WouldDraw();
panel_size = eX * 0.4 * vid_conwidth + eY * 0.3 * vid_conheight;
}
- // these must be below above block
vector pos, mySize;
pos = panel_pos;
mySize = panel_size;
drawcolorcodedstring_aspect(pos + eY * (2/8) * mySize.y, s, eX * mySize.x + eY * (1.75/8) * mySize.y, a, DRAWFLAG_NORMAL);
// print the yes/no counts
- s = sprintf(_("Yes (%s): %d"), getcommandkey("vyes", "vyes"), vote_yescount);
- drawstring_aspect(pos + eY * (4/8) * mySize.y, s, eX * 0.5 * mySize.x + eY * (1.5/8) * mySize.y, '0 1 0', a, DRAWFLAG_NORMAL);
- s = sprintf(_("No (%s): %d"), getcommandkey("vno", "vno"), vote_nocount);
- drawstring_aspect(pos + eX * 0.5 * mySize.x + eY * (4/8) * mySize.y, s, eX * 0.5 * mySize.x + eY * (1.5/8) * mySize.y, '1 0 0', a, DRAWFLAG_NORMAL);
+ s = sprintf("^2%s ^7(%d)", getcommandkey_forcename(_("Yes"), "vyes"), vote_yescount);
+ drawcolorcodedstring_aspect(pos + eY * (4/8) * mySize.y, s, eX * 0.5 * mySize.x + eY * (1.5/8) * mySize.y, a, DRAWFLAG_NORMAL);
+ s = sprintf("^1%s ^7(%d)", getcommandkey_forcename(_("No"), "vno"), vote_nocount);
+ drawcolorcodedstring_aspect(pos + eX * 0.5 * mySize.x + eY * (4/8) * mySize.y, s, eX * 0.5 * mySize.x + eY * (1.5/8) * mySize.y, a, DRAWFLAG_NORMAL);
// draw the progress bar backgrounds
drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_back", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
{
if((!autocvar_hud_panel_weapons) || (spectatee_status == -1))
return;
+ if(STAT(HEALTH) <= 0 && autocvar_hud_panel_weapons_hide_ondeath)
+ return;
if(timeout && time >= weapontime + timeout + timeout_effect_length)
if(autocvar_hud_panel_weapons_timeout_effect == 3 || (autocvar_hud_panel_weapons_timeout_effect == 1 && !(autocvar_hud_panel_weapons_timeout_fadebgmin + autocvar_hud_panel_weapons_timeout_fadefgmin)))
{
{
if(autocvar__hud_configure)
{
- if(menu_enabled != 2)
+ if(hud_configure_menu_open != 2)
HUD_Panel_DrawBg(1); // also draw the bg of the entire panel
}
vector label_size = '1 1 0' * min(weapon_size.x, weapon_size.y) * bound(0, autocvar_hud_panel_weapons_label_scale, 1);
vector noncurrent_size = weapon_size * bound(0.01, autocvar_hud_panel_weapons_noncurrent_scale, 1);
float noncurrent_alpha = panel_fg_alpha * bound(0, autocvar_hud_panel_weapons_noncurrent_alpha, 1);
- bool isCurrent;
static vector weapon_pos_current = '-1 0 0';
if(weapon_pos_current.x == -1)
weapon_pos_current = panel_pos;
switch_speed = frametime * autocvar_hud_panel_weapons_selection_speed;
vector radius_size = weapon_size * (autocvar_hud_panel_weapons_selection_radius + 1);
- if(!panel_switchweapon)
+ if(switchweapon == WEP_Null)
+ panel_switchweapon = NULL;
+ else if(!panel_switchweapon)
panel_switchweapon = switchweapon;
// draw background behind currently selected weapon
weapon_pos = (panel_pos + eX * column * weapon_size.x + eY * row * weapon_size.y);
// update position of the currently selected weapon
- isCurrent = (it == panel_switchweapon);
- if(isCurrent)
+ if(it == panel_switchweapon)
{
if(weapon_pos_current.y > weapon_pos.y)
weapon_pos_current.y = max(weapon_pos.y, weapon_pos_current.y - switch_speed * (weapon_pos_current.y - weapon_pos.y));
#include "hud/all.qh"
#include "mapvoting.qh"
#include "mutators/events.qh"
+#include "hud/panel/scoreboard.qh"
#include "hud/panel/quickmenu.qh"
-#include "scoreboard.qh"
#include "shownames.qh"
#include <common/t_items.qh>
#include "wall.qh"
binddb = db_create();
tempdb = db_create();
ClientProgsDB = db_load("client.db");
- compressShortVector_init();
draw_endBoldFont();
registercvar("cl_spawn_near_teammate", "1");
- gametype = 0;
+ gametype = NULL;
- // hud_fields uses strunzone on the titles!
- for(int i = 0; i < MAX_HUD_FIELDS; ++i)
- hud_title[i] = strzone("(null)");
+ // sbt_fields uses strunzone on the titles!
+ for(int i = 0; i < MAX_SBT_FIELDS; ++i)
+ sbt_field_title[i] = strzone("(null)");
- Cmd_HUD_SetFields(0);
+ Cmd_Scoreboard_SetFields(0);
postinit = false;
{
WarpZone_Shutdown();
- remove(teams);
- remove(players);
+ delete(teams);
+ delete(players);
db_close(binddb);
db_close(tempdb);
if(autocvar_cl_db_saveasdump)
default:
if(GetTeam(Team, false) == NULL)
{
- LOG_TRACEF("trying to switch to unsupported team %d\n", Team);
+ LOG_TRACEF("trying to switch to unsupported team %d", Team);
Team = NUM_SPECTATOR;
}
break;
default:
if(GetTeam(Team, false) == NULL)
{
- LOG_TRACEF("trying to switch to unsupported team %d\n", Team);
+ LOG_TRACEF("trying to switch to unsupported team %d", Team);
Team = NUM_SPECTATOR;
}
break;
e.ping_movementloss = 0;
//e.gotscores = 0; // we might already have the scores...
int t = entcs_GetScoreTeam(i);
- if (t) SetTeam(e, t); // will not hurt; later updates come with HUD_UpdatePlayerTeams
+ if (t) SetTeam(e, t); // will not hurt; later updates come with Scoreboard_UpdatePlayerTeams
RegisterPlayer(e);
- HUD_UpdatePlayerPos(e);
+ Scoreboard_UpdatePlayerPos(e);
}
}
}
if(this.owner) {
SetTeam(this.owner, -1);
this.owner.gotscores = 0;
- for(int i = 0; i < MAX_SCORE; ++i) {
- this.owner.(scores[i]) = 0; // clear all scores
- }
+ FOREACH(Scores, true, {
+ this.owner.(scores(it)) = 0; // clear all scores
+ });
}
}
NET_HANDLE(ENT_CLIENT_SCORES, bool isnew)
{
make_pure(this);
- int i, n;
- bool isNew;
entity o;
// damnit -.- don't want to go change every single .sv_entnum in hud.qc AGAIN
// (no I've never heard of M-x replace-string, sed, or anything like that)
- isNew = !this.owner; // workaround for DP bug
- n = ReadByte()-1;
+ bool isNew = !this.owner; // workaround for DP bug
+ int n = ReadByte()-1;
#ifdef DP_CSQC_ENTITY_REMOVE_IS_B0RKED
if(!isNew && n != this.sv_entnum)
//playerchecker will do this for us later, if it has not already done so
int sf, lf;
-#if MAX_SCORE <= 8
- sf = ReadByte();
- lf = ReadByte();
-#else
sf = ReadShort();
lf = ReadShort();
-#endif
- int p;
- for(i = 0, p = 1; i < MAX_SCORE; ++i, p *= 2)
- if(sf & p)
+ FOREACH(Scores, true, {
+ int p = 1 << (i % 16);
+ if (sf & p)
{
- if(lf & p)
- o.(scores[i]) = ReadInt24_t();
+ if (lf & p)
+ o.(scores(it)) = ReadInt24_t();
else
- o.(scores[i]) = ReadChar();
+ o.(scores(it)) = ReadChar();
}
+ });
return = true;
if(o.sort_prev)
- HUD_UpdatePlayerPos(o); // if not registered, we cannot do this yet!
+ Scoreboard_UpdatePlayerPos(o); // if not registered, we cannot do this yet!
this.entremove = Ent_RemovePlayerScore;
}
if(sf & p)
{
if(lf & p)
- o.(teamscores[i]) = ReadInt24_t();
+ o.(teamscores(i)) = ReadInt24_t();
else
- o.(teamscores[i]) = ReadChar();
+ o.(teamscores(i)) = ReadChar();
}
return = true;
- HUD_UpdateTeamPos(o);
+ Scoreboard_UpdateTeamPos(o);
}
NET_HANDLE(ENT_CLIENT_CLIENTDATA, bool isnew)
else
angles_held_status = 0;
+ if(f & 16)
+ {
+ num_spectators = ReadByte();
+
+ float i, slot;
+
+ for(i = 0; i < MAX_SPECTATORS; ++i)
+ spectatorlist[i] = 0; // reset list first
+
+ for(i = 0; i < num_spectators; ++i)
+ {
+ slot = ReadByte();
+ spectatorlist[i] = slot - 1;
+ }
+ }
+
return = true;
if(newspectatee_status != spectatee_status)
time = savetime;
if (!done)
{
- LOG_FATALF("CSQC_Ent_Update(%d) at %f with this=%i {.entnum=%d, .enttype=%d} t=%s (%d)\n", isnew, savetime, this, this.entnum, this.enttype, this.classname, t);
+ LOG_FATALF("CSQC_Ent_Update(%d) at %f with this=%i {.entnum=%d, .enttype=%d} t=%s (%d)", isnew, savetime, this, this.entnum, this.enttype, this.classname, t);
}
}
if (autocvar_developer_csqcentities) LOG_INFOF("CSQC_Ent_Remove() with this=%i {.entnum=%d, .enttype=%d}\n", this, this.entnum, this.enttype);
if (wasfreed(this))
{
- LOG_WARNING("CSQC_Ent_Remove called for already removed entity. Packet loss?\n");
+ LOG_WARN("CSQC_Ent_Remove called for already removed entity. Packet loss?");
return;
}
if (this.enttype) Ent_Remove(this);
- remove(this);
+ delete(this);
}
void Gamemode_Init()
NET_HANDLE(ENT_CLIENT_SCORES_INFO, bool isnew)
{
make_pure(this);
- gametype = ReadInt24_t();
+ gametype = ReadRegistered(Gametypes);
HUD_ModIcons_SetFunc();
- for (int i = 0; i < MAX_SCORE; ++i)
- {
- if (scores_label[i]) strunzone(scores_label[i]);
- scores_label[i] = strzone(ReadString());
- scores_flags[i] = ReadByte();
- }
+ FOREACH(Scores, true, {
+ if (scores_label(it)) strunzone(scores_label(it));
+ scores_label(it) = strzone(ReadString());
+ scores_flags(it) = ReadByte();
+ });
for (int i = 0; i < MAX_TEAMSCORE; ++i)
{
- if (teamscores_label[i]) strunzone(teamscores_label[i]);
- teamscores_label[i] = strzone(ReadString());
- teamscores_flags[i] = ReadByte();
+ if (teamscores_label(i)) strunzone(teamscores_label(i));
+ teamscores_label(i) = strzone(ReadString());
+ teamscores_flags(i) = ReadByte();
}
return = true;
- HUD_InitScores();
+ Scoreboard_InitScores();
Gamemode_Init();
}
}
}
-string getcommandkey(string text, string command)
+string _getcommandkey(string cmd_name, string command, bool forcename)
{
string keys;
float n, j, k, l = 0;
if (!autocvar_hud_showbinds)
- return text;
+ return cmd_name;
keys = db_get(binddb, command);
if (keys == "")
if (keys == "NO_KEY") {
if (autocvar_hud_showbinds > 1)
- return sprintf(_("%s (not bound)"), text);
+ return sprintf(_("%s (not bound)"), cmd_name);
else
- return text;
+ return cmd_name;
}
- else if (autocvar_hud_showbinds > 1)
- return sprintf("%s (%s)", text, keys);
+ else if (autocvar_hud_showbinds > 1 || forcename)
+ return sprintf("%s (%s)", cmd_name, keys);
else
return keys;
}
// General stuff
float postinit;
-float gametype;
+entity gametype;
//float sorted_players;
//float sorted_teams;
// --------------------------------------------------------------------------
// Scoreboard stuff
-const int MAX_HUD_FIELDS = 16;
-
-const int SP_END = -1;
-
-const int SP_PING = -2;
-const int SP_NAME = -3;
-const int SP_KDRATIO = -4;
-const int SP_CLRATIO = -5;
-const int SP_PL = -6;
-const int SP_FRAGS = -7;
-const int SP_SUM = -8;
-
-const int SP_SEPARATOR = -100;
-
-float hud_field[MAX_HUD_FIELDS + 1];
-float hud_size[MAX_HUD_FIELDS + 1];
-string hud_title[MAX_HUD_FIELDS + 1];
-int hud_num_fields;
-
-string scores_label[MAX_SCORE];
-int scores_flags[MAX_SCORE];
-string teamscores_label[MAX_SCORE];
-int teamscores_flags[MAX_SCORE];
-.int scores[MAX_SCORE];
-.float teamscores[MAX_TEAMSCORE];
-
-#define IS_INCREASING(x) ( (x)&SFL_LOWER_IS_BETTER )
-#define IS_DECREASING(x) ( !((x)&SFL_LOWER_IS_BETTER) )
+const int MAX_SBT_FIELDS = MAX_SCORE;
+PlayerScoreField sbt_field[MAX_SBT_FIELDS + 1];
+float sbt_field_size[MAX_SBT_FIELDS + 1];
+string sbt_field_title[MAX_SBT_FIELDS + 1];
+int sbt_num_fields;
vector hud_fontsize;
void Fog_Force();
-string getcommandkey(string text, string command);
+string _getcommandkey(string text, string command, bool forcename);
+#define getcommandkey(cmd_name, command) _getcommandkey(cmd_name, command, false)
+#define getcommandkey_forcename(cmd_name, command) _getcommandkey(cmd_name, command, true)
string vote_called_vote;
float ready_waiting;
float hud;
float view_quality;
+
+int num_spectators;
+const int MAX_SPECTATORS = 7;
+int spectatorlist[MAX_SPECTATORS];
+
int framecount;
.float health;
#include "mapvoting.qh"
#include "hud/all.qh"
-#include "scoreboard.qh"
+#include "hud/panel/scoreboard.qh"
#include <common/mapinfo.qh>
// Bounding box details
float rect_margin = hud_fontsize.y / 2;
- pos.x += rect_margin + autocvar_scoreboard_border_thickness;
- pos.y += rect_margin + autocvar_scoreboard_border_thickness;
- maxh -= 2 * (rect_margin + autocvar_scoreboard_border_thickness);
- tsize -= 2 * (rect_margin + autocvar_scoreboard_border_thickness);
+ pos.x += rect_margin + autocvar_hud_panel_mapvote_highlight_border;
+ pos.y += rect_margin + autocvar_hud_panel_mapvote_highlight_border;
+ maxh -= 2 * (rect_margin + autocvar_hud_panel_mapvote_highlight_border);
+ tsize -= 2 * (rect_margin + autocvar_hud_panel_mapvote_highlight_border);
vector rect_pos = pos - '0.5 0.5 0' * rect_margin;
vector rect_size = '1 1 0';
if(id == mv_ownvote)
{
drawfill(rect_pos, rect_size, rgb, 0.1*alpha, DRAWFLAG_NORMAL);
- drawborderlines(autocvar_scoreboard_border_thickness, rect_pos, rect_size, rgb, alpha, DRAWFLAG_NORMAL);
+ drawborderlines(autocvar_hud_panel_mapvote_highlight_border, rect_pos, rect_size, rgb, alpha, DRAWFLAG_NORMAL);
}
vector offset = pos;
drawstring(last.origin+offset, last.message, gtv_text_size_small, '1 1 1', alpha, DRAWFLAG_NORMAL);
next = last;
last = last.chain;
- remove(next);
+ delete(next);
}
// Cleanup
- remove(title);
+ delete(title);
}
void MapVote_DrawMapItem(vector pos, float isize, float tsize, string map, string pic, float _count, int id)
float rect_margin = hud_fontsize.y / 2;
- pos.x += rect_margin + autocvar_scoreboard_border_thickness;
- pos.y += rect_margin + autocvar_scoreboard_border_thickness;
- isize -= 2 * (rect_margin + autocvar_scoreboard_border_thickness);
- tsize -= 2 * (rect_margin + autocvar_scoreboard_border_thickness);
+ pos.x += rect_margin + autocvar_hud_panel_mapvote_highlight_border;
+ pos.y += rect_margin + autocvar_hud_panel_mapvote_highlight_border;
+ isize -= 2 * (rect_margin + autocvar_hud_panel_mapvote_highlight_border);
+ tsize -= 2 * (rect_margin + autocvar_hud_panel_mapvote_highlight_border);
vector rect_pos = pos - '0.5 0.5 0' * rect_margin;
vector rect_size = '1 1 0';
if(id == mv_ownvote)
{
drawfill(rect_pos, rect_size, rgb, 0.1*theAlpha, DRAWFLAG_NORMAL);
- drawborderlines(autocvar_scoreboard_border_thickness, rect_pos, rect_size, rgb, theAlpha, DRAWFLAG_NORMAL);
+ drawborderlines(autocvar_hud_panel_mapvote_highlight_border, rect_pos, rect_size, rgb, theAlpha, DRAWFLAG_NORMAL);
}
drawstring(text_pos, label, hud_fontsize, rgb, theAlpha, DRAWFLAG_NORMAL);
}
else
{
- int type = MapInfo_Type_FromString(gt);
+ Gametype type = MapInfo_Type_FromString(gt);
mv_pk3[i] = strzone(MapInfo_Type_ToText(type));
mv_desc[i] = MapInfo_Type_Description(type);
}
void Net_MapVote_Picture();
float mv_active;
+float xmin, xmax, ymin, ymax;
}
}
else
- LOG_TRACE("No model parameters for ", e.model, "\n");
+ LOG_TRACE("No model parameters for ", e.model);
//dprint(e.model, " uses ", ftos(e.bone_upperbody), " ", ftos(e.fixbone), "\n");
get_model_parameters(string_null, 0);
e.skeleton_info_modelindex = e.modelindex;
+++ /dev/null
-#include "scoreboard.qh"
-
-#include "hud/panel/quickmenu.qh"
-#include "hud/all.qh"
-
-#include <common/ent_cs.qh>
-#include <common/constants.qh>
-#include <common/mapinfo.qh>
-#include <common/minigames/cl_minigames.qh>
-#include <common/stats.qh>
-#include <common/teams.qh>
-
-float scoreboard_alpha_bg;
-float scoreboard_alpha_fg;
-float scoreboard_highlight;
-float scoreboard_highlight_alpha;
-float scoreboard_highlight_alpha_self;
-float scoreboard_alpha_name;
-float scoreboard_alpha_name_self;
-
-void drawstringright(vector, string, vector, vector, float, float);
-void drawstringcenter(vector, string, vector, vector, float, float);
-
-const float SCOREBOARD_OFFSET = 50;
-
-// wrapper to put all possible scores titles through gettext
-string TranslateScoresLabel(string l)
-{
- switch(l)
- {
- case "bckills": return CTX(_("SCO^bckills"));
- case "bctime": return CTX(_("SCO^bctime"));
- case "caps": return CTX(_("SCO^caps"));
- case "captime": return CTX(_("SCO^captime"));
- case "deaths": return CTX(_("SCO^deaths"));
- case "destroyed": return CTX(_("SCO^destroyed"));
- case "dmg": return CTX(_("SCO^dmg"));
- case "dmgtaken": return CTX(_("SCO^dmgtaken"));
- case "drops": return CTX(_("SCO^drops"));
- case "faults": return CTX(_("SCO^faults"));
- case "fckills": return CTX(_("SCO^fckills"));
- case "goals": return CTX(_("SCO^goals"));
- case "kckills": return CTX(_("SCO^kckills"));
- case "kdratio": return CTX(_("SCO^kdratio"));
- case "k/d": return CTX(_("SCO^k/d"));
- case "kd": return CTX(_("SCO^kd"));
- case "kdr": return CTX(_("SCO^kdr"));
- case "kills": return CTX(_("SCO^kills"));
- case "laps": return CTX(_("SCO^laps"));
- case "lives": return CTX(_("SCO^lives"));
- case "losses": return CTX(_("SCO^losses"));
- case "name": return CTX(_("SCO^name"));
- case "sum": return CTX(_("SCO^sum"));
- case "nick": return CTX(_("SCO^nick"));
- case "objectives": return CTX(_("SCO^objectives"));
- case "pickups": return CTX(_("SCO^pickups"));
- case "ping": return CTX(_("SCO^ping"));
- case "pl": return CTX(_("SCO^pl"));
- case "pushes": return CTX(_("SCO^pushes"));
- case "rank": return CTX(_("SCO^rank"));
- case "returns": return CTX(_("SCO^returns"));
- case "revivals": return CTX(_("SCO^revivals"));
- case "score": return CTX(_("SCO^score"));
- case "suicides": return CTX(_("SCO^suicides"));
- case "takes": return CTX(_("SCO^takes"));
- case "ticks": return CTX(_("SCO^ticks"));
- default: return l;
- }
-}
-
-void HUD_InitScores()
-{
- int i, f;
-
- ps_primary = ps_secondary = ts_primary = ts_secondary = -1;
- for(i = 0; i < MAX_SCORE; ++i)
- {
- f = (scores_flags[i] & SFL_SORT_PRIO_MASK);
- if(f == SFL_SORT_PRIO_PRIMARY)
- ps_primary = i;
- if(f == SFL_SORT_PRIO_SECONDARY)
- ps_secondary = i;
- }
- if(ps_secondary == -1)
- ps_secondary = ps_primary;
-
- for(i = 0; i < MAX_TEAMSCORE; ++i)
- {
- f = (teamscores_flags[i] & SFL_SORT_PRIO_MASK);
- if(f == SFL_SORT_PRIO_PRIMARY)
- ts_primary = i;
- if(f == SFL_SORT_PRIO_SECONDARY)
- ts_secondary = i;
- }
- if(ts_secondary == -1)
- ts_secondary = ts_primary;
-
- Cmd_HUD_SetFields(0);
-}
-
-float SetTeam(entity pl, float Team);
-//float lastpnum;
-void HUD_UpdatePlayerTeams()
-{
- float Team;
- entity pl, tmp;
- float num;
-
- num = 0;
- for(pl = players.sort_next; pl; pl = pl.sort_next)
- {
- num += 1;
- Team = entcs_GetScoreTeam(pl.sv_entnum);
- if(SetTeam(pl, Team))
- {
- tmp = pl.sort_prev;
- HUD_UpdatePlayerPos(pl);
- if(tmp)
- pl = tmp;
- else
- pl = players.sort_next;
- }
- }
- /*
- if(num != lastpnum)
- print(strcat("PNUM: ", ftos(num), "\n"));
- lastpnum = num;
- */
-}
-
-int HUD_CompareScore(int vl, int vr, int f)
-{
- TC(int, vl); TC(int, vr); TC(int, f);
- if(f & SFL_ZERO_IS_WORST)
- {
- if(vl == 0 && vr != 0)
- return 1;
- if(vl != 0 && vr == 0)
- return 0;
- }
- if(vl > vr)
- return IS_INCREASING(f);
- if(vl < vr)
- return IS_DECREASING(f);
- return -1;
-}
-
-float HUD_ComparePlayerScores(entity left, entity right)
-{
- float vl, vr, r;
- vl = entcs_GetTeam(left.sv_entnum);
- vr = entcs_GetTeam(right.sv_entnum);
-
- if(!left.gotscores)
- vl = NUM_SPECTATOR;
- if(!right.gotscores)
- vr = NUM_SPECTATOR;
-
- if(vl > vr)
- return true;
- if(vl < vr)
- return false;
-
- if(vl == NUM_SPECTATOR)
- {
- // FIRST the one with scores (spectators), THEN the ones without (downloaders)
- // no other sorting
- if(!left.gotscores && right.gotscores)
- return true;
- return false;
- }
-
- r = HUD_CompareScore(left.scores[ps_primary], right.scores[ps_primary], scores_flags[ps_primary]);
- if (r >= 0)
- return r;
-
- r = HUD_CompareScore(left.scores[ps_secondary], right.scores[ps_secondary], scores_flags[ps_secondary]);
- if (r >= 0)
- return r;
-
- int i;
- for(i = 0; i < MAX_SCORE; ++i)
- {
- r = HUD_CompareScore(left.scores[i], right.scores[i], scores_flags[i]);
- if (r >= 0)
- return r;
- }
-
- if (left.sv_entnum < right.sv_entnum)
- return true;
-
- return false;
-}
-
-void HUD_UpdatePlayerPos(entity player)
-{
- entity ent;
- for(ent = player.sort_next; ent && HUD_ComparePlayerScores(player, ent); ent = player.sort_next)
- {
- SORT_SWAP(player, ent);
- }
- for(ent = player.sort_prev; ent != players && HUD_ComparePlayerScores(ent, player); ent = player.sort_prev)
- {
- SORT_SWAP(ent, player);
- }
-}
-
-float HUD_CompareTeamScores(entity left, entity right)
-{
- int i, r;
-
- if(left.team == NUM_SPECTATOR)
- return 1;
- if(right.team == NUM_SPECTATOR)
- return 0;
-
- r = HUD_CompareScore(left.teamscores[ts_primary], right.teamscores[ts_primary], teamscores_flags[ts_primary]);
- if (r >= 0)
- return r;
-
- r = HUD_CompareScore(left.teamscores[ts_secondary], right.teamscores[ts_secondary], teamscores_flags[ts_secondary]);
- if (r >= 0)
- return r;
-
- for(i = 0; i < MAX_SCORE; ++i)
- {
- r = HUD_CompareScore(left.teamscores[i], right.teamscores[i], teamscores_flags[i]);
- if (r >= 0)
- return r;
- }
-
- if (left.team < right.team)
- return true;
-
- return false;
-}
-
-void HUD_UpdateTeamPos(entity Team)
-{
- entity ent;
- for(ent = Team.sort_next; ent && HUD_CompareTeamScores(Team, ent); ent = Team.sort_next)
- {
- SORT_SWAP(Team, ent);
- }
- for(ent = Team.sort_prev; ent != teams && HUD_CompareTeamScores(ent, Team); ent = Team.sort_prev)
- {
- SORT_SWAP(ent, Team);
- }
-}
-
-void Cmd_HUD_Help()
-{
- LOG_INFO(_("You can modify the scoreboard using the ^2scoreboard_columns_set command.\n"));
- LOG_INFO(_("^3|---------------------------------------------------------------|\n"));
- LOG_INFO(_("Usage:\n"));
- LOG_INFO(_("^2scoreboard_columns_set default\n"));
- LOG_INFO(_("^2scoreboard_columns_set ^7field1 field2 ...\n"));
- LOG_INFO(_("The following field names are recognized (case insensitive):\n"));
- LOG_INFO(_("You can use a ^3|^7 to start the right-aligned fields.\n\n"));
-
- LOG_INFO(_("^3name^7 or ^3nick^7 Name of a player\n"));
- LOG_INFO(_("^3ping^7 Ping time\n"));
- LOG_INFO(_("^3pl^7 Packet loss\n"));
- LOG_INFO(_("^3kills^7 Number of kills\n"));
- LOG_INFO(_("^3deaths^7 Number of deaths\n"));
- LOG_INFO(_("^3suicides^7 Number of suicides\n"));
- LOG_INFO(_("^3frags^7 kills - suicides\n"));
- LOG_INFO(_("^3kd^7 The kill-death ratio\n"));
- LOG_INFO(_("^3dmg^7 The total damage done\n"));
- LOG_INFO(_("^3dmgtaken^7 The total damage taken\n"));
- LOG_INFO(_("^3sum^7 frags - deaths\n"));
- LOG_INFO(_("^3caps^7 How often a flag (CTF) or a key (KeyHunt) was captured\n"));
- LOG_INFO(_("^3pickups^7 How often a flag (CTF) or a key (KeyHunt) or a ball (Keepaway) was picked up\n"));
- LOG_INFO(_("^3captime^7 Time of fastest cap (CTF)\n"));
- LOG_INFO(_("^3fckills^7 Number of flag carrier kills\n"));
- LOG_INFO(_("^3returns^7 Number of flag returns\n"));
- LOG_INFO(_("^3drops^7 Number of flag drops\n"));
- LOG_INFO(_("^3lives^7 Number of lives (LMS)\n"));
- LOG_INFO(_("^3rank^7 Player rank\n"));
- LOG_INFO(_("^3pushes^7 Number of players pushed into void\n"));
- LOG_INFO(_("^3destroyed^7 Number of keys destroyed by pushing them into void\n"));
- LOG_INFO(_("^3kckills^7 Number of keys carrier kills\n"));
- LOG_INFO(_("^3losses^7 Number of times a key was lost\n"));
- LOG_INFO(_("^3laps^7 Number of laps finished (race/cts)\n"));
- LOG_INFO(_("^3time^7 Total time raced (race/cts)\n"));
- LOG_INFO(_("^3fastest^7 Time of fastest lap (race/cts)\n"));
- LOG_INFO(_("^3ticks^7 Number of ticks (DOM)\n"));
- LOG_INFO(_("^3takes^7 Number of domination points taken (DOM)\n"));
- LOG_INFO(_("^3bckills^7 Number of ball carrier kills\n"));
- LOG_INFO(_("^3bctime^7 Total amount of time holding the ball in Keepaway\n"));
- LOG_INFO(_("^3score^7 Total score\n\n"));
-
- LOG_INFO(_("Before a field you can put a + or - sign, then a comma separated list\n"
- "of game types, then a slash, to make the field show up only in these\n"
- "or in all but these game types. You can also specify 'all' as a\n"
- "field to show all fields available for the current game mode.\n\n"));
-
- LOG_INFO(_("The special game type names 'teams' and 'noteams' can be used to\n"
- "include/exclude ALL teams/noteams game modes.\n\n"));
-
- LOG_INFO(_("Example: scoreboard_columns_set name ping pl | +ctf/field3 -dm/field4\n"));
- LOG_INFO(_("will display name, ping and pl aligned to the left, and the fields\n"
- "right of the vertical bar aligned to the right.\n"));
- LOG_INFO(_("'field3' will only be shown in CTF, and 'field4' will be shown in all\n"
- "other gamemodes except DM.\n"));
-}
-
-// NOTE: adding a gametype with ? to not warn for an optional field
-// make sure it's excluded in a previous exclusive rule, if any
-// otherwise the previous exclusive rule warns anyway
-// e.g. -teams,rc,cts,lms/kills ?+rc/kills
-#define SCOREBOARD_DEFAULT_COLUMNS \
-"ping pl name |" \
-" -teams,rc,cts,inv,lms/kills +ft,tdm/kills ?+rc,inv/kills" \
-" -teams,lms/deaths +ft,tdm/deaths" \
-" -teams,lms,rc,cts,inv,ka/suicides +ft,tdm/suicides ?+rc,inv/suicides" \
-" -cts,dm,tdm,ka,ft/frags" /* tdm already has this in "score" */ \
-" -rc,cts,nb/dmg -rc,cts,nb/dmgtaken" \
-" +ctf/caps +ctf/pickups +ctf/fckills +ctf/returns +ons/caps +ons/takes" \
-" +lms/lives +lms/rank" \
-" +kh/caps +kh/pushes +kh/destroyed" \
-" ?+rc/laps ?+rc/time +rc,cts/fastest" \
-" +as/objectives +nb/faults +nb/goals" \
-" +ka/pickups +ka/bckills +ka/bctime +ft/revivals" \
-" -lms,rc,cts,inv,nb/score"
-
-void Cmd_HUD_SetFields(int argc)
-{
- TC(int, argc);
- int i, j, slash;
- string str, pattern;
- float have_name = 0, have_primary = 0, have_secondary = 0, have_separator = 0;
- float missing;
-
- if(!gametype)
- {
- // set up a temporary scoreboard layout
- // no layout can be properly set up until score_info data haven't been received
- argc = tokenizebyseparator("0 1 ping pl name | score", " ");
- ps_primary = 0;
- scores_label[ps_primary] = strzone("score");
- scores_flags[ps_primary] = SFL_ALLOW_HIDE;
- }
-
- // TODO: re enable with gametype dependant cvars?
- if(argc < 3) // no arguments provided
- argc = tokenizebyseparator(strcat("0 1 ", autocvar_scoreboard_columns), " ");
-
- if(argc < 3)
- argc = tokenizebyseparator(strcat("0 1 ", SCOREBOARD_DEFAULT_COLUMNS), " ");
-
- if(argc == 3)
- {
- if(argv(2) == "default")
- argc = tokenizebyseparator(strcat("0 1 ", SCOREBOARD_DEFAULT_COLUMNS), " ");
- else if(argv(2) == "all")
- {
- string s;
- s = "ping pl name |";
- for(i = 0; i < MAX_SCORE; ++i)
- {
- if(i != ps_primary)
- if(i != ps_secondary)
- if(scores_label[i] != "")
- s = strcat(s, " ", scores_label[i]);
- }
- if(ps_secondary != ps_primary)
- s = strcat(s, " ", scores_label[ps_secondary]);
- s = strcat(s, " ", scores_label[ps_primary]);
- argc = tokenizebyseparator(strcat("0 1 ", s), " ");
- }
- }
-
-
- hud_num_fields = 0;
-
- hud_fontsize = HUD_GetFontsize("hud_fontsize");
-
- for(i = 1; i < argc - 1; ++i)
- {
- float nocomplain;
- str = argv(i+1);
-
- nocomplain = false;
- if(substring(str, 0, 1) == "?")
- {
- nocomplain = true;
- str = substring(str, 1, strlen(str) - 1);
- }
-
- slash = strstrofs(str, "/", 0);
- if(slash >= 0)
- {
- pattern = substring(str, 0, slash);
- str = substring(str, slash + 1, strlen(str) - (slash + 1));
-
- if (!isGametypeInFilter(gametype, teamplay, false, pattern))
- continue;
- }
-
- strunzone(hud_title[hud_num_fields]);
- hud_title[hud_num_fields] = strzone(TranslateScoresLabel(str));
- hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], false, hud_fontsize);
- str = strtolower(str);
-
- switch(str)
- {
- case "ping": hud_field[hud_num_fields] = SP_PING; break;
- case "pl": hud_field[hud_num_fields] = SP_PL; break;
- case "kd": case "kdr": case "kdratio": case "k/d": hud_field[hud_num_fields] = SP_KDRATIO; break;
- case "sum": case "diff": case "k-d": hud_field[hud_num_fields] = SP_SUM; break;
- case "name": case "nick": hud_field[hud_num_fields] = SP_NAME; have_name = true; break;
- case "|": hud_field[hud_num_fields] = SP_SEPARATOR; have_separator = true; break;
- case "dmg": hud_field[hud_num_fields] = SP_DMG; break;
- case "dmgtaken": hud_field[hud_num_fields] = SP_DMGTAKEN; break;
- default:
- {
- for(j = 0; j < MAX_SCORE; ++j)
- if(str == strtolower(scores_label[j]))
- goto found; // sorry, but otherwise fteqcc -O3 miscompiles this and warns about "unreachable code"
-
-LABEL(notfound)
- if(str == "frags")
- j = SP_FRAGS;
- else
- {
- if(!nocomplain)
- LOG_INFOF("^1Error:^7 Unknown score field: '%s'\n", str);
- continue;
- }
-LABEL(found)
- hud_field[hud_num_fields] = j;
- if(j == ps_primary)
- have_primary = 1;
- if(j == ps_secondary)
- have_secondary = 1;
-
- }
- }
- ++hud_num_fields;
- if(hud_num_fields >= MAX_HUD_FIELDS)
- break;
- }
-
- if(scores_flags[ps_primary] & SFL_ALLOW_HIDE)
- have_primary = 1;
- if(scores_flags[ps_secondary] & SFL_ALLOW_HIDE)
- have_secondary = 1;
- if(ps_primary == ps_secondary)
- have_secondary = 1;
- missing = (!have_primary) + (!have_secondary) + (!have_separator) + (!have_name);
-
- if(hud_num_fields+missing < MAX_HUD_FIELDS)
- {
- if(!have_name)
- {
- strunzone(hud_title[hud_num_fields]);
- for(i = hud_num_fields; i > 0; --i)
- {
- hud_title[i] = hud_title[i-1];
- hud_size[i] = hud_size[i-1];
- hud_field[i] = hud_field[i-1];
- }
- hud_title[0] = strzone(TranslateScoresLabel("name"));
- hud_field[0] = SP_NAME;
- ++hud_num_fields;
- LOG_INFO("fixed missing field 'name'\n");
-
- if(!have_separator)
- {
- strunzone(hud_title[hud_num_fields]);
- for(i = hud_num_fields; i > 1; --i)
- {
- hud_title[i] = hud_title[i-1];
- hud_size[i] = hud_size[i-1];
- hud_field[i] = hud_field[i-1];
- }
- hud_title[1] = strzone("|");
- hud_field[1] = SP_SEPARATOR;
- hud_size[1] = stringwidth("|", false, hud_fontsize);
- ++hud_num_fields;
- LOG_INFO("fixed missing field '|'\n");
- }
- }
- else if(!have_separator)
- {
- strunzone(hud_title[hud_num_fields]);
- hud_title[hud_num_fields] = strzone("|");
- hud_size[hud_num_fields] = stringwidth("|", false, hud_fontsize);
- hud_field[hud_num_fields] = SP_SEPARATOR;
- ++hud_num_fields;
- LOG_INFO("fixed missing field '|'\n");
- }
- if(!have_secondary)
- {
- strunzone(hud_title[hud_num_fields]);
- hud_title[hud_num_fields] = strzone(TranslateScoresLabel(scores_label[ps_secondary]));
- hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], false, hud_fontsize);
- hud_field[hud_num_fields] = ps_secondary;
- ++hud_num_fields;
- LOG_INFOF("fixed missing field '%s'\n", scores_label[ps_secondary]);
- }
- if(!have_primary)
- {
- strunzone(hud_title[hud_num_fields]);
- hud_title[hud_num_fields] = strzone(TranslateScoresLabel(scores_label[ps_primary]));
- hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], false, hud_fontsize);
- hud_field[hud_num_fields] = ps_primary;
- ++hud_num_fields;
- LOG_INFOF("fixed missing field '%s'\n", scores_label[ps_primary]);
- }
- }
-
- hud_field[hud_num_fields] = SP_END;
-}
-
-// MOVEUP::
-vector hud_field_rgb;
-string hud_field_icon0;
-string hud_field_icon1;
-string hud_field_icon2;
-vector hud_field_icon0_rgb;
-vector hud_field_icon1_rgb;
-vector hud_field_icon2_rgb;
-float hud_field_icon0_alpha;
-float hud_field_icon1_alpha;
-float hud_field_icon2_alpha;
-string HUD_GetField(entity pl, int field)
-{
- TC(int, field);
- float tmp, num, denom;
- int f;
- string str;
- hud_field_rgb = '1 1 1';
- hud_field_icon0 = "";
- hud_field_icon1 = "";
- hud_field_icon2 = "";
- hud_field_icon0_rgb = '1 1 1';
- hud_field_icon1_rgb = '1 1 1';
- hud_field_icon2_rgb = '1 1 1';
- hud_field_icon0_alpha = 1;
- hud_field_icon1_alpha = 1;
- hud_field_icon2_alpha = 1;
- switch(field)
- {
- case SP_PING:
- if (!pl.gotscores)
- return "\xE2\x96\xB6\xE2\x96\xB6\xE2\x96\xB6"; // >>> sign using U+25B6
- //str = getplayerkeyvalue(pl.sv_entnum, "ping");
- f = pl.ping;
- if(f == 0)
- return _("N/A");
- tmp = max(0, min(220, f-80)) / 220;
- hud_field_rgb = '1 1 1' - '0 1 1'*tmp;
- return ftos(f);
-
- case SP_PL:
- if (!pl.gotscores)
- return _("N/A");
- f = pl.ping_packetloss;
- tmp = pl.ping_movementloss;
- if(f == 0 && tmp == 0)
- return "";
- str = ftos(ceil(f * 100));
- if(tmp != 0)
- str = strcat(str, "~", ftos(ceil(tmp * 100)));
- tmp = bound(0, f / 0.2 + tmp / 0.04, 1); // 20% is REALLY BAD pl
- hud_field_rgb = '1 0.5 0.5' - '0 0.5 0.5'*tmp;
- return str;
-
- case SP_NAME:
- if(ready_waiting && pl.ready)
- {
- hud_field_icon0 = "gfx/scoreboard/player_ready";
- }
- else if(!teamplay)
- {
- f = stof(getplayerkeyvalue(pl.sv_entnum, "colors"));
- {
- hud_field_icon0 = "gfx/scoreboard/playercolor_base";
- hud_field_icon1 = "gfx/scoreboard/playercolor_shirt";
- hud_field_icon1_rgb = colormapPaletteColor(floor(f / 16), 0);
- hud_field_icon2 = "gfx/scoreboard/playercolor_pants";
- hud_field_icon2_rgb = colormapPaletteColor(f % 16, 1);
- }
- }
- return entcs_GetName(pl.sv_entnum);
-
- case SP_FRAGS:
- f = pl.(scores[SP_KILLS]);
- f -= pl.(scores[SP_SUICIDES]);
- return ftos(f);
-
- case SP_KDRATIO:
- num = pl.(scores[SP_KILLS]);
- denom = pl.(scores[SP_DEATHS]);
-
- if(denom == 0) {
- hud_field_rgb = '0 1 0';
- str = sprintf("%d", num);
- } else if(num <= 0) {
- hud_field_rgb = '1 0 0';
- str = sprintf("%.1f", num/denom);
- } else
- str = sprintf("%.1f", num/denom);
- return str;
-
- case SP_SUM:
- f = pl.(scores[SP_KILLS]);
- f -= pl.(scores[SP_DEATHS]);
-
- if(f > 0) {
- hud_field_rgb = '0 1 0';
- } else if(f == 0) {
- hud_field_rgb = '1 1 1';
- } else {
- hud_field_rgb = '1 0 0';
- }
- return ftos(f);
-
- case SP_DMG:
- num = pl.(scores[SP_DMG]);
- denom = 1000;
-
- str = sprintf("%.1f k", num/denom);
- return str;
-
- case SP_DMGTAKEN:
- num = pl.(scores[SP_DMGTAKEN]);
- denom = 1000;
-
- str = sprintf("%.1f k", num/denom);
- return str;
-
- default:
- tmp = pl.(scores[field]);
- f = scores_flags[field];
- if(field == ps_primary)
- hud_field_rgb = '1 1 0';
- else if(field == ps_secondary)
- hud_field_rgb = '0 1 1';
- else
- hud_field_rgb = '1 1 1';
- return ScoreString(f, tmp);
- }
- //return "error";
-}
-
-float hud_fixscoreboardcolumnwidth_len;
-float hud_fixscoreboardcolumnwidth_iconlen;
-float hud_fixscoreboardcolumnwidth_marginlen;
-
-string HUD_FixScoreboardColumnWidth(int i, string str)
-{
- TC(int, i);
- float field, f;
- vector sz;
- field = hud_field[i];
-
- hud_fixscoreboardcolumnwidth_iconlen = 0;
-
- if(hud_field_icon0 != "")
- {
- sz = draw_getimagesize(hud_field_icon0);
- f = sz.x / sz.y;
- if(hud_fixscoreboardcolumnwidth_iconlen < f)
- hud_fixscoreboardcolumnwidth_iconlen = f;
- }
-
- if(hud_field_icon1 != "")
- {
- sz = draw_getimagesize(hud_field_icon1);
- f = sz.x / sz.y;
- if(hud_fixscoreboardcolumnwidth_iconlen < f)
- hud_fixscoreboardcolumnwidth_iconlen = f;
- }
-
- if(hud_field_icon2 != "")
- {
- sz = draw_getimagesize(hud_field_icon2);
- f = sz.x / sz.y;
- if(hud_fixscoreboardcolumnwidth_iconlen < f)
- hud_fixscoreboardcolumnwidth_iconlen = f;
- }
-
- hud_fixscoreboardcolumnwidth_iconlen *= hud_fontsize.y / hud_fontsize.x; // fix icon aspect
-
- if(hud_fixscoreboardcolumnwidth_iconlen != 0)
- hud_fixscoreboardcolumnwidth_marginlen = stringwidth(" ", false, hud_fontsize);
- else
- hud_fixscoreboardcolumnwidth_marginlen = 0;
-
- if(field == SP_NAME) // name gets all remaining space
- {
- int j;
- float namesize;
- namesize = sbwidth;// / hud_fontsize_x;
- for(j = 0; j < hud_num_fields; ++j)
- if(j != i)
- if (hud_field[i] != SP_SEPARATOR)
- namesize -= hud_size[j] + hud_fontsize.x;
- namesize += hud_fontsize.x;
- hud_size[i] = namesize;
-
- if (hud_fixscoreboardcolumnwidth_iconlen != 0)
- namesize -= hud_fixscoreboardcolumnwidth_marginlen + hud_fixscoreboardcolumnwidth_iconlen;
- str = textShortenToWidth(str, namesize, hud_fontsize, stringwidth_colors);
- hud_fixscoreboardcolumnwidth_len = stringwidth(str, true, hud_fontsize);
- }
- else
- hud_fixscoreboardcolumnwidth_len = stringwidth(str, false, hud_fontsize);
-
- f = hud_fixscoreboardcolumnwidth_len + hud_fixscoreboardcolumnwidth_marginlen + hud_fixscoreboardcolumnwidth_iconlen;
- if(hud_size[i] < f)
- hud_size[i] = f;
-
- return str;
-}
-
-void HUD_PrintScoreboardItem(vector pos, vector item_size, entity pl, bool is_self, int pl_number)
-{
- TC(bool, is_self); TC(int, pl_number);
- vector tmp, rgb;
- rgb = Team_ColorRGB(pl.team);
- string str;
- int field;
- float is_spec;
- is_spec = (entcs_GetTeam(pl.sv_entnum) == NUM_SPECTATOR);
-
- if((rgb == '1 1 1') && (!is_spec)) {
- rgb.x = autocvar_scoreboard_color_bg_r + 0.5;
- rgb.y = autocvar_scoreboard_color_bg_g + 0.5;
- rgb.z = autocvar_scoreboard_color_bg_b + 0.5; }
-
- vector h_pos = pos - '1 1 0';
- vector h_size = item_size + '2 0 0';
- // alternated rows highlighting
- if(is_self)
- drawfill(h_pos, h_size, rgb, scoreboard_highlight_alpha_self, DRAWFLAG_NORMAL);
- else if((scoreboard_highlight) && (!(pl_number % 2)))
- drawfill(h_pos, h_size, rgb, scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
-
- tmp.x = item_size.x;
- tmp.y = 0;
- tmp.z = 0;
- int i;
- for(i = 0; i < hud_num_fields; ++i)
- {
- field = hud_field[i];
- if(field == SP_SEPARATOR)
- break;
-
- if(is_spec && field != SP_NAME && field != SP_PING) {
- pos.x += hud_size[i] + hud_fontsize.x;
- continue;
- }
- str = HUD_GetField(pl, field);
- str = HUD_FixScoreboardColumnWidth(i, str);
-
- pos.x += hud_size[i] + hud_fontsize.x;
-
- if(field == SP_NAME) {
- tmp.x = hud_size[i] - hud_fontsize.x*hud_fixscoreboardcolumnwidth_iconlen - hud_fixscoreboardcolumnwidth_marginlen + hud_fontsize.x;
- if (is_self)
- drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
- else
- drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name, DRAWFLAG_NORMAL);
- } else {
- tmp.x = hud_fixscoreboardcolumnwidth_len + hud_fontsize.x;
- if (is_self)
- drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
- else
- drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name, DRAWFLAG_NORMAL);
- }
-
- tmp.x = hud_size[i] + hud_fontsize.x;
- if(hud_field_icon0 != "")
- if (is_self)
- drawpic(pos - tmp, hud_field_icon0, '0 1 0' * hud_fontsize.y + '1 0 0' * hud_fontsize.x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon0_alpha * scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
- else
- drawpic(pos - tmp, hud_field_icon0, '0 1 0' * hud_fontsize.y + '1 0 0' * hud_fontsize.x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon0_alpha * scoreboard_alpha_name, DRAWFLAG_NORMAL);
- if(hud_field_icon1 != "")
- if (is_self)
- drawpic(pos - tmp, hud_field_icon1, '0 1 0' * hud_fontsize.y + '1 0 0' * hud_fontsize.x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon1_alpha * scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
- else
- drawpic(pos - tmp, hud_field_icon1, '0 1 0' * hud_fontsize.y + '1 0 0' * hud_fontsize.x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon1_alpha * scoreboard_alpha_name, DRAWFLAG_NORMAL);
- if(hud_field_icon2 != "")
- if (is_self)
- drawpic(pos - tmp, hud_field_icon2, '0 1 0' * hud_fontsize.y + '1 0 0' * hud_fontsize.x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon2_rgb, hud_field_icon2_alpha * scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
- else
- drawpic(pos - tmp, hud_field_icon2, '0 1 0' * hud_fontsize.y + '1 0 0' * hud_fontsize.x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon2_rgb, hud_field_icon2_alpha * scoreboard_alpha_name, DRAWFLAG_NORMAL);
- }
-
- if(hud_field[i] == SP_SEPARATOR)
- {
- pos.x = xmax;
- for(i = hud_num_fields-1; i > 0; --i)
- {
- field = hud_field[i];
- if(field == SP_SEPARATOR)
- break;
-
- if(is_spec && field != SP_NAME && field != SP_PING) {
- pos.x -= hud_size[i] + hud_fontsize.x;
- continue;
- }
-
- str = HUD_GetField(pl, field);
- str = HUD_FixScoreboardColumnWidth(i, str);
-
- if(field == SP_NAME) {
- tmp.x = hud_fixscoreboardcolumnwidth_len; // left or right aligned? let's put it right...
- if(is_self)
- drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
- else
- drawcolorcodedstring(pos - tmp, str, hud_fontsize, scoreboard_alpha_name, DRAWFLAG_NORMAL);
- } else {
- tmp.x = hud_fixscoreboardcolumnwidth_len;
- if(is_self)
- drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
- else
- drawstring(pos - tmp, str, hud_fontsize, hud_field_rgb, scoreboard_alpha_name, DRAWFLAG_NORMAL);
- }
-
- tmp.x = hud_size[i];
- if(hud_field_icon0 != "")
- if (is_self)
- drawpic(pos - tmp, hud_field_icon0, '0 1 0' * hud_fontsize.y + '1 0 0' * hud_fontsize.x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon0_alpha * scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
- else
- drawpic(pos - tmp, hud_field_icon0, '0 1 0' * hud_fontsize.y + '1 0 0' * hud_fontsize.x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon0_alpha * scoreboard_alpha_name, DRAWFLAG_NORMAL);
- if(hud_field_icon1 != "")
- if (is_self)
- drawpic(pos - tmp, hud_field_icon1, '0 1 0' * hud_fontsize.y + '1 0 0' * hud_fontsize.x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon1_alpha * scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
- else
- drawpic(pos - tmp, hud_field_icon1, '0 1 0' * hud_fontsize.y + '1 0 0' * hud_fontsize.x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon1_rgb, hud_field_icon1_alpha * scoreboard_alpha_name, DRAWFLAG_NORMAL);
- if(hud_field_icon2 != "")
- if (is_self)
- drawpic(pos - tmp, hud_field_icon2, '0 1 0' * hud_fontsize.y + '1 0 0' * hud_fontsize.x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon2_rgb, hud_field_icon2_alpha * scoreboard_alpha_name_self, DRAWFLAG_NORMAL);
- else
- drawpic(pos - tmp, hud_field_icon2, '0 1 0' * hud_fontsize.y + '1 0 0' * hud_fontsize.x * hud_fixscoreboardcolumnwidth_iconlen, hud_field_icon2_rgb, hud_field_icon2_alpha * scoreboard_alpha_name, DRAWFLAG_NORMAL);
- pos.x -= hud_size[i] + hud_fontsize.x;
- }
- }
-
- if(pl.eliminated)
- drawfill(h_pos, h_size, '0 0 0', 0.5, DRAWFLAG_NORMAL);
-}
-
-/*
- * HUD_Scoreboard_MakeTable
- *
- * Makes a table for a team (for all playing players in DM) and fills it
- */
-
-vector HUD_Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_size)
-{
- float body_table_height;
- vector tmp = '0 0 0', column_dim = '0 0 0';
- entity pl;
-
- body_table_height = 1.25 * hud_fontsize.y * max(1, tm.team_size); // no player? show 1 empty line
-
- pos.y += autocvar_scoreboard_border_thickness;
- pos -= '1 1 0';
-
- tmp.x = sbwidth + 2;
- tmp.y = 1.25 * hud_fontsize.y;
-
- // rounded header
- if (teamplay)
- drawpic(pos, "gfx/scoreboard/scoreboard_tableheader", tmp, (rgb * autocvar_scoreboard_color_bg_team) + '0.5 0.5 0.5', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
- else
- drawpic(pos, "gfx/scoreboard/scoreboard_tableheader", tmp, rgb + '0.5 0.5 0.5', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
-
- // table border
- tmp.y += autocvar_scoreboard_border_thickness;
- tmp.y += body_table_height;
- drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg, DRAWFLAG_NORMAL); // more transparency for the scoreboard
-
- // separator header/table
- pos.y += 1.25 * hud_fontsize.y;
- tmp.y = autocvar_scoreboard_border_thickness;
- drawfill(pos, tmp, '0 0 0', scoreboard_alpha_bg, DRAWFLAG_NORMAL);
-
- pos.y += autocvar_scoreboard_border_thickness;
-
- // table background
- tmp.y = body_table_height;
- if (teamplay)
- drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
- else
- drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
-
- // anyway, apply some color
- //drawfill(pos, tmp + '2 0 0', rgb, 0.1, DRAWFLAG_NORMAL);
-
- // go back to the top to make alternated columns highlighting and to print the strings
- pos.y -= 1.25 * hud_fontsize.y;
- pos.y -= autocvar_scoreboard_border_thickness;
-
- pos += '1 1 0';
-
- if (scoreboard_highlight)
- {
- column_dim.y = 1.25 * hud_fontsize.y; // header
- column_dim.y += autocvar_scoreboard_border_thickness;
- column_dim.y += body_table_height;
- }
-
- // print the strings of the columns headers and draw the columns
- int i;
- for(i = 0; i < hud_num_fields; ++i)
- {
- if(hud_field[i] == SP_SEPARATOR)
- break;
- column_dim.x = hud_size[i] + hud_fontsize.x;
- if (scoreboard_highlight)
- {
- if (i % 2)
- drawfill(pos - '0 1 0' - hud_fontsize.x / 2 * '1 0 0', column_dim, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
- }
- drawstring(pos, hud_title[i], hud_fontsize, rgb * 1.5, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
- pos.x += column_dim.x;
- }
- if(hud_field[i] == SP_SEPARATOR)
- {
- pos.x = xmax;
- tmp.y = 0;
- for(i = hud_num_fields-1; i > 0; --i)
- {
- if(hud_field[i] == SP_SEPARATOR)
- break;
-
- pos.x -= hud_size[i];
-
- if (scoreboard_highlight)
- {
- if (!(i % 2))
- {
- if (i == hud_num_fields-1)
- column_dim.x = hud_size[i] + hud_fontsize.x / 2 + 1;
- else
- column_dim.x = hud_size[i] + hud_fontsize.x;
- drawfill(pos - '0 1 0' - hud_fontsize.x / 2 * '1 0 0', column_dim, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
- }
- }
-
- tmp.x = stringwidth(hud_title[i], false, hud_fontsize);
- tmp.x = (hud_size[i] - tmp.x);
- drawstring(pos + tmp, hud_title[i], hud_fontsize, rgb * 1.5, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
- pos.x -= hud_fontsize.x;
- }
- }
-
- pos.x = xmin;
- pos.y += 1.25 * hud_fontsize.y; // skip the header
- pos.y += autocvar_scoreboard_border_thickness;
-
- // item size
- tmp.x = sbwidth;
- tmp.y = hud_fontsize.y * 1.25;
-
- // fill the table and draw the rows
- i = 0;
- if (teamplay)
- for(pl = players.sort_next; pl; pl = pl.sort_next)
- {
- if(pl.team != tm.team)
- continue;
- HUD_PrintScoreboardItem(pos, tmp, pl, (pl.sv_entnum == player_localnum), i);
- pos.y += 1.25 * hud_fontsize.y;
- ++i;
- }
- else
- for(pl = players.sort_next; pl; pl = pl.sort_next)
- {
- if(pl.team == NUM_SPECTATOR)
- continue;
- HUD_PrintScoreboardItem(pos, tmp, pl, (pl.sv_entnum == player_localnum), i);
- pos.y += 1.25 * hud_fontsize.y;
- ++i;
- }
-
- if (i == 0)
- pos.y += 1.25 * hud_fontsize.y; // move to the end of the table
- pos.y += 1.25 * hud_fontsize.y; // move empty row (out of the table)
-
- return pos;
-}
-
-float HUD_WouldDrawScoreboard() {
- if (autocvar__hud_configure)
- return 0;
- else if (QuickMenu_IsOpened())
- return 0;
- else if (HUD_Radar_Clickable())
- return 0;
- else if (scoreboard_showscores)
- return 1;
- else if (intermission == 1)
- return 1;
- else if (intermission == 2)
- return 0;
- else if (spectatee_status != -1 && STAT(HEALTH) <= 0 && autocvar_cl_deathscoreboard && gametype != MAPINFO_TYPE_CTS && !active_minigame)
- return 1;
- else if (scoreboard_showscores_force)
- return 1;
- return 0;
-}
-
-float average_accuracy;
-vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
-{
- WepSet weapons_stat = WepSet_GetFromStat();
- WepSet weapons_inmap = WepSet_GetFromStat_InMap();
- float initial_posx = pos.x;
- int disownedcnt = 0;
- FOREACH(Weapons, it != WEP_Null, {
- int weapon_stats = weapon_accuracy[i - WEP_FIRST];
-
- WepSet set = it.m_wepset;
- if (weapon_stats < 0 && !(weapons_stat & set || weapons_inmap & set))
- ++disownedcnt;
- });
-
- int weapon_cnt = (Weapons_COUNT - 1) - disownedcnt;
- if (weapon_cnt <= 0) return pos;
-
- int rows = 1;
- if (autocvar_scoreboard_accuracy_doublerows && weapon_cnt >= floor((Weapons_COUNT - 1) * 0.5))
- rows = 2;
- int columnns = ceil(weapon_cnt / rows);
-
- float height = 40;
- float fontsize = height * 1/3;
- float weapon_height = height * 2/3;
- float weapon_width = sbwidth / columnns / rows;
-
- drawstring(pos, sprintf(_("Accuracy stats (average %d%%)"), average_accuracy), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
- pos.y += 1.25 * hud_fontsize.y + autocvar_scoreboard_border_thickness;
- vector tmp = '0 0 0';
- tmp.x = sbwidth;
- tmp.y = height * rows;
-
- if (teamplay)
- drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
- else
- drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
- drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
-
- // column highlighting
- for (int i = 0; i < columnns; ++i)
- {
- if ((i % 2) == 0)
- drawfill(pos + '1 0 0' * weapon_width * rows * i, '0 1 0' * height * rows + '1 0 0' * weapon_width * rows, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
- }
-
- // row highlighting
- for (int i = 0; i < rows; ++i)
- {
- drawfill(pos + '0 1 0' * weapon_height + '0 1 0' * height * i, '1 0 0' * sbwidth + '0 1 0' * fontsize, '1 1 1', scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
- }
-
- average_accuracy = 0;
- int weapons_with_stats = 0;
- if (rows == 2)
- pos.x += weapon_width / 2;
-
- if (autocvar_scoreboard_accuracy_nocolors)
- rgb = '1 1 1';
- else
- Accuracy_LoadColors();
-
- float oldposx = pos.x;
- vector tmpos = pos;
-
- int column = 0;
- FOREACH(Weapons, it != WEP_Null, {
- int weapon_stats = weapon_accuracy[i - WEP_FIRST];
-
- WepSet set = it.m_wepset;
- if (weapon_stats < 0 && !(weapons_stat & set || weapons_inmap & set))
- continue;
-
- float weapon_alpha;
- if (weapon_stats >= 0)
- weapon_alpha = scoreboard_alpha_fg;
- else
- weapon_alpha = 0.2 * scoreboard_alpha_fg;
-
- // weapon icon
- drawpic_aspect_skin(tmpos, it.model2, '1 0 0' * weapon_width + '0 1 0' * weapon_height, '1 1 1', weapon_alpha, DRAWFLAG_NORMAL);
- // the accuracy
- if (weapon_stats >= 0) {
- weapons_with_stats += 1;
- average_accuracy += weapon_stats; // store sum of all accuracies in average_accuracy
-
- string s;
- s = sprintf("%d%%", weapon_stats*100);
-
- float padding;
- padding = (weapon_width - stringwidth(s, false, '1 0 0' * fontsize)) / 2; // center the accuracy value
-
- if(!autocvar_scoreboard_accuracy_nocolors)
- rgb = Accuracy_GetColor(weapon_stats);
-
- drawstring(tmpos + '1 0 0' * padding + '0 1 0' * weapon_height, s, '1 1 0' * fontsize, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
- }
- tmpos.x += weapon_width * rows;
- pos.x += weapon_width * rows;
- if (rows == 2 && column == columnns - 1) {
- tmpos.x = oldposx;
- tmpos.y += height;
- pos.y += height;
- }
- ++column;
- });
-
- if (weapons_with_stats)
- average_accuracy = floor((average_accuracy * 100 / weapons_with_stats) + 0.5);
-
- pos.y += height;
- pos.y += 1.25 * hud_fontsize.y;
- pos.x = initial_posx;
- return pos;
-}
-
-vector HUD_DrawKeyValue(vector pos, string key, string value) {
- float px = pos.x;
- pos.x += hud_fontsize.x * 0.25;
- drawstring(pos, key, hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
- pos.x = xmax - stringwidth(value, false, hud_fontsize) - hud_fontsize.x * 0.25;
- drawstring(pos, value, hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
- pos.x = px;
- pos.y+= hud_fontsize.y;
-
- return pos;
-}
-
-vector HUD_DrawMapStats(vector pos, vector rgb, vector bg_size) {
- float stat_secrets_found, stat_secrets_total;
- float stat_monsters_killed, stat_monsters_total;
- float rows = 0;
- string val;
-
- // get monster stats
- stat_monsters_killed = STAT(MONSTERS_KILLED);
- stat_monsters_total = STAT(MONSTERS_TOTAL);
-
- // get secrets stats
- stat_secrets_found = STAT(SECRETS_FOUND);
- stat_secrets_total = STAT(SECRETS_TOTAL);
-
- // get number of rows
- if(stat_secrets_total)
- rows += 1;
- if(stat_monsters_total)
- rows += 1;
-
- // if no rows, return
- if (!rows)
- return pos;
-
- // draw table header
- drawstring(pos, _("Map stats:"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
- pos.y += 1.25 * hud_fontsize.y + autocvar_scoreboard_border_thickness;
-
- // draw table
- vector tmp = '0 0 0';
- tmp.x = sbwidth;
- tmp.y = hud_fontsize.y * rows;
-
- if (teamplay)
- drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
- else
- drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
- drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
-
- // draw monsters
- if(stat_monsters_total)
- {
- val = sprintf("%d/%d", stat_monsters_killed, stat_monsters_total);
- pos = HUD_DrawKeyValue(pos, _("Monsters killed:"), val);
- }
-
- // draw secrets
- if(stat_secrets_total)
- {
- val = sprintf("%d/%d", stat_secrets_found, stat_secrets_total);
- pos = HUD_DrawKeyValue(pos, _("Secrets found:"), val);
- }
-
- // update position
- pos.y += 1.25 * hud_fontsize.y;
- return pos;
-}
-
-
-vector HUD_DrawScoreboardRankings(vector pos, entity pl, vector rgb, vector bg_size)
-{
- int i;
- RANKINGS_RECEIVED_CNT = 0;
- for (i=RANKINGS_CNT-1; i>=0; --i)
- if (grecordtime[i])
- ++RANKINGS_RECEIVED_CNT;
-
- if (RANKINGS_RECEIVED_CNT == 0)
- return pos;
-
- float is_spec;
- is_spec = (entcs_GetTeam(pl.sv_entnum) == NUM_SPECTATOR);
- vector hl_rgb;
- hl_rgb.x = autocvar_scoreboard_color_bg_r + 0.5;
- hl_rgb.y = autocvar_scoreboard_color_bg_g + 0.5;
- hl_rgb.z = autocvar_scoreboard_color_bg_b + 0.5;
-
- pos.y += hud_fontsize.y;
- drawstring(pos, _("Rankings"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
- pos.y += hud_fontsize.y + autocvar_scoreboard_border_thickness;
- vector tmp = '0 0 0';
- tmp.x = sbwidth;
- tmp.y = 1.25 * hud_fontsize.y * RANKINGS_RECEIVED_CNT;
-
- if (teamplay)
- drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
- else
- drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
- drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
-
- // row highlighting
- for(i = 0; i<RANKINGS_RECEIVED_CNT; ++i)
- {
- string n, p;
- float t;
- t = grecordtime[i];
- if (t == 0)
- continue;
- n = grecordholder[i];
- p = count_ordinal(i+1);
- if(grecordholder[i] == entcs_GetName(player_localnum))
- drawfill(pos, '1 0 0' * sbwidth + '0 1.25 0' * hud_fontsize.y, hl_rgb, scoreboard_highlight_alpha_self, DRAWFLAG_NORMAL);
- else if(!(i % 2) && scoreboard_highlight)
- drawfill(pos, '1 0 0' * sbwidth + '0 1.25 0' * hud_fontsize.y, hl_rgb, scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
- drawstring(pos, p, '1 1 0' * hud_fontsize.y, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
- drawstring(pos + '3 0 0' * hud_fontsize.y, TIME_ENCODED_TOSTRING(t), '1 1 0' * hud_fontsize.y, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
- drawcolorcodedstring(pos + '8 0 0' * hud_fontsize.y, n, '1 1 0' * hud_fontsize.y, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
- pos.y += 1.25 * hud_fontsize.y;
- }
- pos.y += autocvar_scoreboard_border_thickness;
-
- return pos;
-}
-
-float hud_woulddrawscoreboard_prev;
-float hud_woulddrawscoreboard_change; // "time" at which HUD_WouldDrawScoreboard() changed
-void HUD_DrawScoreboard()
-{
- float hud_woulddrawscoreboard;
- hud_woulddrawscoreboard = scoreboard_active;
- if(hud_woulddrawscoreboard != hud_woulddrawscoreboard_prev) {
- hud_woulddrawscoreboard_change = time;
- hud_woulddrawscoreboard_prev = hud_woulddrawscoreboard;
- }
-
- if(hud_woulddrawscoreboard) {
- float scoreboard_fadeinspeed = autocvar_scoreboard_fadeinspeed;
- if (scoreboard_fadeinspeed)
- scoreboard_fade_alpha = bound (0, (time - hud_woulddrawscoreboard_change) * scoreboard_fadeinspeed, 1);
- else
- scoreboard_fade_alpha = 1;
- }
- else {
- float scoreboard_fadeoutspeed = autocvar_scoreboard_fadeoutspeed;
- if (scoreboard_fadeoutspeed)
- scoreboard_fade_alpha = bound (0, (1/scoreboard_fadeoutspeed - (time - hud_woulddrawscoreboard_change)) * scoreboard_fadeoutspeed, 1);
- else
- scoreboard_fade_alpha = 0;
- }
-
- if (!scoreboard_fade_alpha)
- return;
-
- if (autocvar_scoreboard_dynamichud)
- HUD_Scale_Enable();
- else
- HUD_Scale_Disable();
-
- HUD_UpdatePlayerTeams();
-
- scoreboard_alpha_bg = autocvar_scoreboard_alpha_bg * scoreboard_fade_alpha * (1 - autocvar__menu_alpha);
- scoreboard_alpha_fg = autocvar_scoreboard_alpha_fg * scoreboard_fade_alpha * (1 - autocvar__menu_alpha);
- scoreboard_highlight = autocvar_scoreboard_highlight;
- scoreboard_highlight_alpha = autocvar_scoreboard_highlight_alpha * scoreboard_alpha_fg;
- scoreboard_highlight_alpha_self = autocvar_scoreboard_highlight_alpha_self * scoreboard_alpha_fg;
- scoreboard_alpha_name = autocvar_scoreboard_alpha_name * scoreboard_alpha_fg;
- scoreboard_alpha_name_self = autocvar_scoreboard_alpha_name_self * scoreboard_alpha_fg;
-
- vector rgb, pos, tmp;
- entity pl, tm;
- string str;
-
- xmin = (autocvar_scoreboard_offset_left * vid_conwidth);
- ymin = max((autocvar_con_notify * autocvar_con_notifysize), (autocvar_scoreboard_offset_vertical * vid_conwidth));
-
- xmax = ((1 - autocvar_scoreboard_offset_right) * vid_conwidth);
- ymax = (vid_conheight - ymin);
-
- sbwidth = xmax - xmin;
-
- // Initializes position
- pos.x = xmin;
- pos.y = ymin;
- pos.z = 0;
-
- // Heading
- vector sb_heading_fontsize;
- sb_heading_fontsize = hud_fontsize * 2;
- draw_beginBoldFont();
- drawstring(pos, _("Scoreboard"), sb_heading_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
- draw_endBoldFont();
-
- pos.y += sb_heading_fontsize.y + hud_fontsize.y * 0.25;
-
- // Draw the scoreboard
- vector bg_size = draw_getimagesize("gfx/scoreboard/scoreboard_bg") * ((autocvar_scoreboard_bg_scale > 0) ? autocvar_scoreboard_bg_scale : 0.25);
-
- if(teamplay)
- {
- vector team_score_baseoffset;
- team_score_baseoffset = eY * (2 * autocvar_scoreboard_border_thickness + hud_fontsize.y) - eX * (autocvar_scoreboard_border_thickness + hud_fontsize.x * 0.25);
- for(tm = teams.sort_next; tm; tm = tm.sort_next)
- {
- if(tm.team == NUM_SPECTATOR)
- continue;
- if(!tm.team && teamplay)
- continue;
-
- draw_beginBoldFont();
- rgb = Team_ColorRGB(tm.team);
- str = ftos(tm.(teamscores[ts_primary]));
- drawstring(pos + team_score_baseoffset - eX * stringwidth(str, false, hud_fontsize * 1.5), str, hud_fontsize * 1.5, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
-
- if(ts_primary != ts_secondary)
- {
- str = ftos(tm.(teamscores[ts_secondary]));
- drawstring(pos + team_score_baseoffset - eX * stringwidth(str, false, hud_fontsize) + eY * hud_fontsize.y * 1.5, str, hud_fontsize, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
- }
- draw_endBoldFont();
-
- pos = HUD_Scoreboard_MakeTable(pos, tm, rgb, bg_size);
- }
- rgb.x = autocvar_scoreboard_color_bg_r;
- rgb.y = autocvar_scoreboard_color_bg_g;
- rgb.z = autocvar_scoreboard_color_bg_b;
- }
- else
- {
- rgb.x = autocvar_scoreboard_color_bg_r;
- rgb.y = autocvar_scoreboard_color_bg_g;
- rgb.z = autocvar_scoreboard_color_bg_b;
-
- for(tm = teams.sort_next; tm; tm = tm.sort_next)
- {
- if(tm.team == NUM_SPECTATOR)
- continue;
- if(!tm.team && teamplay)
- continue;
-
- pos = HUD_Scoreboard_MakeTable(pos, tm, rgb, bg_size);
- }
- }
-
- if(gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE) {
- if(race_speedaward) {
- drawcolorcodedstring(pos, sprintf(_("Speed award: %d%s ^7(%s^7)"), race_speedaward, race_speedaward_unit, race_speedaward_holder), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
- pos.y += 1.25 * hud_fontsize.y;
- }
- if(race_speedaward_alltimebest) {
- drawcolorcodedstring(pos, sprintf(_("All-time fastest: %d%s ^7(%s^7)"), race_speedaward_alltimebest, race_speedaward_alltimebest_unit, race_speedaward_alltimebest_holder), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
- pos.y += 1.25 * hud_fontsize.y;
- }
- pos = HUD_DrawScoreboardRankings(pos, playerslots[player_localnum], rgb, bg_size);
- }
- else if (autocvar_scoreboard_accuracy && !warmup_stage && gametype != MAPINFO_TYPE_NEXBALL) {
- if(teamplay)
- pos = HUD_DrawScoreboardAccuracyStats(pos, Team_ColorRGB(myteam), bg_size);
- else
- pos = HUD_DrawScoreboardAccuracyStats(pos, rgb, bg_size);
- }
-
-
- if(teamplay)
- pos = HUD_DrawMapStats(pos, Team_ColorRGB(myteam), bg_size);
- else
- pos = HUD_DrawMapStats(pos, rgb, bg_size);
-
- // List spectators
- float specs;
- specs = 0;
- tmp = pos;
- vector item_size;
- item_size.x = sbwidth;
- item_size.y = hud_fontsize.y * 1.25;
- item_size.z = 0;
- for(pl = players.sort_next; pl; pl = pl.sort_next)
- {
- if(pl.team != NUM_SPECTATOR)
- continue;
- pos.y += 1.25 * hud_fontsize.y;
- HUD_PrintScoreboardItem(pos, item_size, pl, (pl.sv_entnum == player_localnum), specs);
- ++specs;
- }
-
- if(specs)
- {
- draw_beginBoldFont();
- drawstring(tmp, _("Spectators"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
- draw_endBoldFont();
- pos.y += 1.25 * hud_fontsize.y;
- }
-
- // Print info string
- float tl, fl, ll;
- str = sprintf(_("playing ^3%s^7 on ^2%s^7"), MapInfo_Type_ToText(gametype), shortmapname);
- tl = STAT(TIMELIMIT);
- fl = STAT(FRAGLIMIT);
- ll = STAT(LEADLIMIT);
- if(gametype == MAPINFO_TYPE_LMS)
- {
- if(tl > 0)
- str = strcat(str, sprintf(_(" for up to ^1%1.0f minutes^7"), tl));
- }
- else
- {
- if(tl > 0)
- str = strcat(str, sprintf(_(" for up to ^1%1.0f minutes^7"), tl));
- if(fl > 0)
- {
- if(tl > 0)
- str = strcat(str, _(" or"));
- if(teamplay)
- {
- str = strcat(str, sprintf(_(" until ^3%s %s^7"), ScoreString(teamscores_flags[ts_primary], fl),
- (teamscores_label[ts_primary] == "score") ? CTX(_("SCO^points")) :
- (teamscores_label[ts_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
- TranslateScoresLabel(teamscores_label[ts_primary])));
- }
- else
- {
- str = strcat(str, sprintf(_(" until ^3%s %s^7"), ScoreString(scores_flags[ps_primary], fl),
- (scores_label[ps_primary] == "score") ? CTX(_("SCO^points")) :
- (scores_label[ps_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
- TranslateScoresLabel(scores_label[ps_primary])));
- }
- }
- if(ll > 0)
- {
- if(tl > 0 || fl > 0)
- str = strcat(str, _(" or"));
- if(teamplay)
- {
- str = strcat(str, sprintf(_(" until a lead of ^3%s %s^7"), ScoreString(teamscores_flags[ts_primary], ll),
- (teamscores_label[ts_primary] == "score") ? CTX(_("SCO^points")) :
- (teamscores_label[ts_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
- TranslateScoresLabel(teamscores_label[ts_primary])));
- }
- else
- {
- str = strcat(str, sprintf(_(" until a lead of ^3%s %s^7"), ScoreString(scores_flags[ps_primary], ll),
- (scores_label[ps_primary] == "score") ? CTX(_("SCO^points")) :
- (scores_label[ps_primary] == "fastest") ? CTX(_("SCO^is beaten")) :
- TranslateScoresLabel(scores_label[ps_primary])));
- }
- }
- }
-
- pos.y += 1.2 * hud_fontsize.y;
- drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, true, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
-
- // print information about respawn status
- float respawn_time = STAT(RESPAWN_TIME);
- if(!intermission)
- if(respawn_time)
- {
- if(respawn_time < 0)
- {
- // a negative number means we are awaiting respawn, time value is still the same
- respawn_time *= -1; // remove mark now that we checked it
- respawn_time = max(time, respawn_time); // don't show a negative value while the server is respawning the player (lag)
-
- str = sprintf(_("^1Respawning in ^3%s^1..."),
- (autocvar_scoreboard_respawntime_decimals ?
- count_seconds_decs(respawn_time - time, autocvar_scoreboard_respawntime_decimals)
- :
- count_seconds(respawn_time - time)
- )
- );
- }
- else if(time < respawn_time)
- {
- str = sprintf(_("You are dead, wait ^3%s^7 before respawning"),
- (autocvar_scoreboard_respawntime_decimals ?
- count_seconds_decs(respawn_time - time, autocvar_scoreboard_respawntime_decimals)
- :
- count_seconds(respawn_time - time)
- )
- );
- }
- else if(time >= respawn_time)
- str = sprintf(_("You are dead, press ^2%s^7 to respawn"), getcommandkey("jump", "+jump"));
-
- pos.y += 1.2 * hud_fontsize.y;
- drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, true, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
- }
-
- scoreboard_bottom = pos.y + 2 * hud_fontsize.y;
-}
+++ /dev/null
-#pragma once
-
-float xmin, xmax, ymin, ymax, sbwidth;
-
-float scoreboard_active;
-float scoreboard_fade_alpha;
-
-void Cmd_HUD_SetFields(float argc);
-void HUD_DrawScoreboard();
-void HUD_InitScores();
-void HUD_UpdatePlayerPos(entity pl);
-void HUD_UpdateTeamPos(entity Team);
-float HUD_WouldDrawScoreboard();
#include "announcer.qh"
#include "hud/all.qh"
#include "mapvoting.qh"
-#include "scoreboard.qh"
#include "shownames.qh"
+#include "hud/panel/scoreboard.qh"
#include "hud/panel/quickmenu.qh"
#include "mutators/events.qh"
void PostInit();
void CSQC_Demo_Camera();
-float HUD_WouldDrawScoreboard();
+float Scoreboard_WouldDraw();
float camera_mode;
const float CAMERA_FREE = 1;
const float CAMERA_CHASE = 2;
if (damage_dealt_time != damage_dealt_time_prev)
{
unaccounted_damage += unaccounted_damage_new;
- LOG_TRACE("dmg total: ", ftos(unaccounted_damage), " (+", ftos(unaccounted_damage_new), ")", "\n");
+ LOG_TRACE("dmg total: ", ftos(unaccounted_damage), " (+", ftos(unaccounted_damage_new), ")");
}
damage_dealt_time_prev = damage_dealt_time;
pitch_shift = mirror_value + (mirror_value - pitch_shift);
}
- LOG_TRACE("dmg total (dmg): ", ftos(unaccounted_damage), " , pitch shift: ", ftos(pitch_shift), "\n");
+ LOG_TRACE("dmg total (dmg): ", ftos(unaccounted_damage), " , pitch shift: ", ftos(pitch_shift));
// todo: avoid very long and very short sounds from wave stretching using different sound files? seems unnecessary
// todo: normalize sound pressure levels? seems unnecessary
Accuracy_LoadLevels();
HUD_Main();
- HUD_DrawScoreboard();
HUD_Scale_Disable();
}
else
view_quality = 1;
- // this needs to be updated manually now due to the destruction of engine physics stats
- if(!isdemo() && autocvar_slowmo != STAT(MOVEVARS_TIMESCALE))
- cvar_set("slowmo", ftos(STAT(MOVEVARS_TIMESCALE)));
-
button_attack2 = PHYS_INPUT_BUTTON_ATCK2(this);
button_zoom = PHYS_INPUT_BUTTON_ZOOM(this);
if(f != teamplay)
{
teamplay = f;
- HUD_InitScores();
+ Scoreboard_InitScores();
}
if(last_switchweapon != switchweapon)
Draw_ShowNames_All();
Debug_Draw();
- scoreboard_active = HUD_WouldDrawScoreboard();
+ scoreboard_active = Scoreboard_WouldDraw();
HUD_Draw(this); // this parameter for deep vehicle function
void SUB_Stop(entity this, entity toucher)
{
this.velocity = this.avelocity = '0 0 0';
- this.move_movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
}
void Projectile_ResetTrail(entity this, vector to)
this.maxs = '0 0 0';
this.colormod = '0 0 0';
settouch(this, SUB_Stop);
- this.move_movetype = MOVETYPE_TOSS;
+ set_movetype(this, MOVETYPE_TOSS);
this.alphamod = 1;
switch (this.cnt)
loopsound(this, CH_SHOTS_SINGLE, SND(ELECTRO_FLY), VOL_BASE, ATTEN_NORM);
this.mins = '-4 -4 -4';
this.maxs = '4 4 4';
- this.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(this, MOVETYPE_BOUNCE);
settouch(this, func_null);
this.bouncefactor = WEP_CVAR_SEC(electro, bouncefactor);
this.bouncestop = WEP_CVAR_SEC(electro, bouncestop);
case PROJECTILE_GRENADE_BOUNCING:
this.mins = '-3 -3 -3';
this.maxs = '3 3 3';
- this.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(this, MOVETYPE_BOUNCE);
settouch(this, func_null);
this.bouncefactor = WEP_CVAR(mortar, bouncefactor);
this.bouncestop = WEP_CVAR(mortar, bouncestop);
case PROJECTILE_PORTO_RED:
this.colormod = '2 1 1';
this.alphamod = 0.5;
- this.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(this, MOVETYPE_BOUNCE);
settouch(this, func_null);
break;
case PROJECTILE_PORTO_BLUE:
this.colormod = '1 1 2';
this.alphamod = 0.5;
- this.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(this, MOVETYPE_BOUNCE);
settouch(this, func_null);
break;
case PROJECTILE_HAGAR_BOUNCING:
- this.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(this, MOVETYPE_BOUNCE);
settouch(this, func_null);
break;
case PROJECTILE_CRYLINK_BOUNCING:
- this.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(this, MOVETYPE_BOUNCE);
settouch(this, func_null);
break;
case PROJECTILE_FIREBALL:
break;
case PROJECTILE_FIREMINE:
loopsound(this, CH_SHOTS_SINGLE, SND(FIREBALL_FLY), VOL_BASE, ATTEN_NORM);
- this.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(this, MOVETYPE_BOUNCE);
settouch(this, func_null);
this.mins = '-4 -4 -4';
this.maxs = '4 4 4';
if (this.gravity)
{
if (this.move_movetype == MOVETYPE_FLY)
- this.move_movetype = MOVETYPE_TOSS;
+ set_movetype(this, MOVETYPE_TOSS);
if (this.move_movetype == MOVETYPE_BOUNCEMISSILE)
- this.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(this, MOVETYPE_BOUNCE);
}
else
{
if (this.move_movetype == MOVETYPE_TOSS)
- this.move_movetype = MOVETYPE_FLY;
+ set_movetype(this, MOVETYPE_FLY);
if (this.move_movetype == MOVETYPE_BOUNCE)
- this.move_movetype = MOVETYPE_BOUNCEMISSILE;
+ set_movetype(this, MOVETYPE_BOUNCEMISSILE);
}
if (!(this.count & 0x80))
-#ifndef ANIM_H
-#define ANIM_H
+#pragma once
// begin engine fields
#define setanim(...) anim_set(__VA_ARGS__)
void anim_update(entity e);
#define updateanim(...) anim_update(__VA_ARGS__)
-
-#endif
-#ifndef ANIMDECIDE_H
-#define ANIMDECIDE_H
+#pragma once
// must be called at least once to initialize, or when modelindex is changed
void animdecide_load_if_needed(entity e);
void animdecide_setframes(entity e, bool support_blending, .int fld_frame, .int fld_frame1time, .int fld_frame2, .int fld_frame2time);
CLASS(Animation, Object)
- ATTRIB(Animation, m_framenames, string, string_null)
+ ATTRIB(Animation, m_framenames, string);
STATIC_METHOD(Animation, getframe, int(Animation this, int mdlidx))
{
FOREACH_WORD(this.m_framenames, true, {
if (f != -1) return f;
});
#ifdef CSQC
- LOG_DEBUGF("Missing animation for %s: %s\n", modelnameforindex(mdlidx), this.registered_id);
+ LOG_DEBUGF("Missing animation for %s: %s", modelnameforindex(mdlidx), this.registered_id);
#endif
return -1;
}
const int ANIMACTION_SHOOT = 4; // shoot
const int ANIMACTION_TAUNT = 5; // taunt
const int ANIMACTION_MELEE = 6; // melee
-#endif
-#ifndef CAMPAIGN_COMMON_H
-#define CAMPAIGN_COMMON_H
+#pragma once
#ifndef CAMPAIGN_MAX_ENTRIES
#define CAMPAIGN_MAX_ENTRIES 64
// Sets up the campaign for the n-th array item (meaning: campaign_offset+nth
// level) using localcmd()
void CampaignSetup(float n);
-#endif
-#ifndef COMMON_COMMANDS_ALL_H
-#define COMMON_COMMANDS_ALL_H
+#pragma once
#include "command.qh"
REGISTRY(GENERIC_COMMANDS, BITS(7))
#include "generic.qh"
#include "markup.qh"
#include "rpn.qh"
-
-#endif
-#ifndef COMMAND_H
-#define COMMAND_H
+#pragma once
const int CMD_REQUEST_COMMAND = 1;
const int CMD_REQUEST_USAGE = 2;
CLASS(Command, Object)
- ATTRIB(Command, m_name, string, string_null);
- ATTRIB(Command, m_description, string, string_null);
+ ATTRIB(Command, m_name, string);
+ ATTRIB(Command, m_description, string);
METHOD(Command, m_invokecmd, void(Command this, int request, entity caller, int arguments, string command))
{
TC(Command, this);
}
ENDCLASS(Command)
-
-#endif
string do_cvar = curl_uri_get_cvar[i];
if(status != 0)
{
- LOG_TRACEF("error: status is %d\n", status);
+ LOG_TRACEF("error: status is %d", status);
if(do_cvar)
strunzone(do_cvar);
return;
{
float f = cvar_settemp(argv(1), argv(2));
if(f == 1)
- LOG_TRACE("Creating new settemp tracker for ", argv(1), " and setting it to \"", argv(2), "\" temporarily.\n");
+ LOG_TRACE("Creating new settemp tracker for ", argv(1), " and setting it to \"", argv(2), "\" temporarily.");
else if(f == -1)
- LOG_TRACE("Already had a tracker for ", argv(1), ", updating it to \"", argv(2), "\".\n");
+ LOG_TRACE("Already had a tracker for ", argv(1), ", updating it to \"", argv(2), "\".");
// else cvar_settemp itself errors out
return;
float i = cvar_settemp_restore();
if(i)
- LOG_TRACE("Restored ", ftos(i), " temporary cvar settings to their original values.\n");
+ LOG_TRACE("Restored ", ftos(i), " temporary cvar settings to their original values.");
else
- LOG_TRACE("Nothing to restore.\n");
+ LOG_TRACE("Nothing to restore.");
return;
}
-#ifndef COMMAND_GENERIC_H
-#define COMMAND_GENERIC_H
+#pragma once
#include <common/constants.qh>
int curl_uri_get_pos;
float curl_uri_get_exec[URI_GET_CURL_END - URI_GET_CURL + 1];
string curl_uri_get_cvar[URI_GET_CURL_END - URI_GET_CURL + 1];
-#endif
markup_from[i] = "&.."; markup_to[i] = "\x9e"; ++i;
markup_from[i] = "&.)"; markup_to[i] = "\x9f"; ++i;
markup_from[i] = "&<|"; markup_to[i] = "\xff"; ++i;
- unused_float = i;
}
string GenericCommand_markup(string s2)
-#ifndef COMMAND_MARKUP_H
-#define COMMAND_MARKUP_H
+#pragma once
// ==========================================================
// Declarations for markup command code, reworked by Samual
string markup_to[NUM_MARKUPS];
string GenericCommand_markup(string s2);
-#endif
-#ifndef COMMAND_RPN_H
-#define COMMAND_RPN_H
+#pragma once
// =========================================================
// Declarations for RPN command code, written by divVerent
string rpn_stack[MAX_RPN_STACK];
void GenericCommand_rpn(float request, float argc, string command);
-
-#endif
-#ifndef CONSTANTS_H
-#define CONSTANTS_H
+#pragma once
REGISTER_NET_TEMP(TE_CSQC_PICTURE)
REGISTER_NET_TEMP(TE_CSQC_RACE)
const int SFL_SORT_PRIO_PRIMARY = 8;
const int SFL_SORT_PRIO_MASK = 12;
-/**
+/*
* Score indices
*/
-#define MAX_SCORE 12
+
+#ifndef MENUQC
+
+#define IS_INCREASING(x) ( (x) & SFL_LOWER_IS_BETTER )
+#define IS_DECREASING(x) ( !((x) & SFL_LOWER_IS_BETTER) )
+
+
+#define MAX_SCORE 64
+
+#define REGISTER_SP(id) REGISTER(Scores, SP, id, m_id, new_pure(PlayerScoreField))
+REGISTRY(Scores, MAX_SCORE);
+#define Scores_from(i) _Scores_from(i, NULL)
+REGISTER_REGISTRY(Scores)
+REGISTRY_SORT(Scores);
+REGISTRY_CHECK(Scores);
+STATIC_INIT(Scores_renumber) { FOREACH(Scores, true, it.m_id = i); }
+
+USING(PlayerScoreField, entity);
+.int _scores[MAX_SCORE];
+.string m_name;
+.int m_flags;
+
+#define scores(this) _scores[(this).m_id]
+#define scores_label(this) ((this).m_name)
+#define scores_flags(this) ((this).m_flags)
+
+REGISTER_SP(END);
+
+REGISTER_SP(PING);
+REGISTER_SP(NAME);
+REGISTER_SP(KDRATIO);
+REGISTER_SP(CLRATIO);
+REGISTER_SP(PL);
+REGISTER_SP(SUM);
+
+REGISTER_SP(SEPARATOR);
+
+REGISTER_SP(SCORE);
+
+REGISTER_SP(DMG);
+REGISTER_SP(DMGTAKEN);
+
+REGISTER_SP(KILLS);
+REGISTER_SP(DEATHS);
+REGISTER_SP(SUICIDES);
+REGISTER_SP(FRAGS);
+
+REGISTER_SP(ELO);
+
+// TODO: move to common mutators
+
+REGISTER_SP(RACE_TIME);
+REGISTER_SP(RACE_LAPS);
+REGISTER_SP(RACE_FASTEST);
+
+REGISTER_SP(CTS_TIME);
+REGISTER_SP(CTS_LAPS);
+REGISTER_SP(CTS_FASTEST);
+
+REGISTER_SP(ASSAULT_OBJECTIVES);
+
+REGISTER_SP(CTF_PICKUPS);
+REGISTER_SP(CTF_FCKILLS);
+REGISTER_SP(CTF_RETURNS);
+REGISTER_SP(CTF_CAPS);
+REGISTER_SP(CTF_CAPTIME);
+REGISTER_SP(CTF_DROPS);
+
+REGISTER_SP(DOM_TAKES);
+REGISTER_SP(DOM_TICKS);
+
+REGISTER_SP(FREEZETAG_REVIVALS);
+
+REGISTER_SP(KEEPAWAY_PICKUPS);
+REGISTER_SP(KEEPAWAY_BCTIME);
+REGISTER_SP(KEEPAWAY_CARRIERKILLS);
+
+REGISTER_SP(KH_PICKUPS);
+REGISTER_SP(KH_CAPS);
+REGISTER_SP(KH_KCKILLS);
+REGISTER_SP(KH_PUSHES);
+REGISTER_SP(KH_DESTROYS);
+REGISTER_SP(KH_LOSSES);
+
+REGISTER_SP(LMS_RANK);
+REGISTER_SP(LMS_LIVES);
+
+REGISTER_SP(NEXBALL_GOALS);
+REGISTER_SP(NEXBALL_FAULTS);
+
+REGISTER_SP(ONS_TAKES);
+REGISTER_SP(ONS_CAPS);
+
#define MAX_TEAMSCORE 2
+USING(ScoreTeam, string);
+.int _teamscores[MAX_TEAMSCORE];
+#define teamscores(i) _teamscores[i]
+string _teamscores_label[MAX_TEAMSCORE];
+#define teamscores_label(i) _teamscores_label[i]
+int _teamscores_flags[MAX_TEAMSCORE];
+#define teamscores_flags(i) _teamscores_flags[i]
+
+#endif
const int ST_SCORE = 0;
-const int SP_KILLS = 0;
-const int SP_DEATHS = 1;
-const int SP_SUICIDES = 2;
-const int SP_SCORE = 3;
-const int SP_DMG = 10;
-const int SP_DMGTAKEN = 11;
+
// game mode specific indices are not in common/, but in server/scores_rules.qc!
// WEAPONTODO: move this into separate/new projectile handling code // this sets sounds and other properties of the projectiles in csqc
const int GTV_FORBIDDEN = 0; // Cannot be voted
const int GTV_AVAILABLE = 1; // Can be voted
const int GTV_CUSTOM = 2; // Custom entry
-#endif
-#ifndef CSQCMODEL_SETTINGS_H
-#define CSQCMODEL_SETTINGS_H
+#pragma once
// define this if svqc code wants to use .frame2 and .lerpfrac
//#define CSQCMODEL_HAVE_TWO_FRAMES
#endif
#define CSQCMODEL_EF_RESPAWNGHOST EF_SELECTABLE
-#endif
-#ifndef DEATHTYPES_ALL_H
-#define DEATHTYPES_ALL_H
+#pragma once
#include <common/notifications/all.qh>
string Deathtype_Name(int deathtype);
#include "all.inc"
-
-#endif
net_eff.eent_eff_trail = eff.eent_eff_trail;
FOREACH_CLIENT(IS_REAL_CLIENT(it), Net_Write_Effect(net_eff, it, 0));
- remove(net_eff);
+ delete(net_eff);
}
void Send_Effect_(string eff_name, vector eff_loc, vector eff_vel, int eff_cnt)
-#ifndef EFFECTS_ALL_H
-#define EFFECTS_ALL_H
+#pragma once
#include "effect.qh"
EFFECT(0, Null, string_null)
#include "all.inc"
-
-#endif
-#ifndef EFFECT_H
-#define EFFECT_H
+#pragma once
#define particleeffectnum(e) \
_particleeffectnum(e.eent_eff_name)
this.eent_eff_trail = eff_trail;
return this;
}
-
-#endif
/**/
CLASS(EffectInfo, Object)
- ATTRIB(EffectInfo, effectinfo_name, string, string_null)
+ ATTRIB(EffectInfo, effectinfo_name, string);
CONSTRUCTOR(EffectInfo, string s) {
CONSTRUCT(EffectInfo);
this.effectinfo_name = s;
MY(velocityoffset, vector, '0 0 0') \
/**/
- #define MY(f, type, val) ATTRIB(EffectInfo, effectinfo_##f, type, val)
+ #define MY(f, type, val) ATTRIB(EffectInfo, effectinfo_##f, type, val);
FIELDS(MY)
#undef MY
ENDCLASS(EffectInfo)
CLASS(EffectInfoGroup, Object)
- ATTRIBARRAY(EffectInfoGroup, children, EffectInfo, 16)
- ATTRIB(EffectInfoGroup, children_count, int, 0)
+ ATTRIBARRAY(EffectInfoGroup, children, EffectInfo, 16);
+ ATTRIB(EffectInfoGroup, children_count, int, 0);
ENDCLASS(EffectInfoGroup)
void effectinfo_read()
#undef p
#undef MY
default:
- LOG_WARNINGF("Unknown property '%s'\n", k);
+ LOG_WARNF("Unknown property '%s'", k);
break;
}
}
LOG_INFOF("Reload with ^2cl_particles_reloadeffects data/%s^7.\n", filename);
fclose(fh);
} else {
- LOG_WARNINGF("Could not open file '%s'!\n", filename);
+ LOG_WARNF("Could not open file '%s'!", filename);
}
return;
}
-#ifndef EFFECTS_QC
-#define EFFECTS_QC
+#pragma once
+
#include "all.inc"
-#endif
#ifdef SVQC
-void SpawnCasing(vector vel, float randomvel, vector ang, vector avel, float randomavel, int casingtype, entity casingowner);
+void SpawnCasing(vector vel, float randomvel, vector ang, vector avel, float randomavel, int casingtype, entity casingowner, .entity weaponentity);
#endif
#ifdef IMPLEMENTATION
REGISTER_NET_TEMP(casings)
#ifdef SVQC
-void SpawnCasing(vector vel, float randomvel, vector ang, vector avel, float randomavel, int casingtype, entity casingowner)
+void SpawnCasing(vector vel, float randomvel, vector ang, vector avel, float randomavel, int casingtype, entity casingowner, .entity weaponentity)
{
- .entity weaponentity = weaponentities[0]; // TODO: parameter
entity wep = casingowner.(weaponentity);
vector org = casingowner.origin + casingowner.view_ofs + wep.spawnorigin.x * v_forward - wep.spawnorigin.y * v_right + wep.spawnorigin.z * v_up;
void Casing_Delete(entity this)
{
- remove(this);
+ delete(this);
}
void Casing_Draw(entity this)
if (isNew) IL_PUSH(g_drawables, casing);
casing.velocity = casing.velocity + 2 * prandomvec();
casing.avelocity = '0 250 0' + 100 * prandomvec();
- casing.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(casing, MOVETYPE_BOUNCE);
settouch(casing, Casing_Touch);
casing.move_time = time;
casing.event_damage = Casing_Damage;
{
// time is up or the player got gibbed / disconnected
this.owner.total_damages = max(0, this.owner.total_damages - 1);
- remove(this);
+ delete(this);
return;
}
if(this.state && !this.owner.csqcmodel_isdead)
// if the player was dead but is now alive, it means he respawned
// if so, clear his damage effects, or damages from his dead body will be copied back
this.owner.total_damages = max(0, this.owner.total_damages - 1);
- remove(this);
+ delete(this);
return;
}
this.state = this.owner.csqcmodel_isdead;
e.oldorigin_x = compressShortVector(e.velocity);
FOREACH_CLIENT(IS_REAL_CLIENT(it), Violence_GibSplash_SendEntity(e, it, 0));
- remove(e);
+ delete(e);
}
void Violence_GibSplash(entity source, float type, float amount, entity attacker)
void Gib_Delete(entity this)
{
- remove(this);
+ delete(this);
}
string species_prefix(int specnum);
// TODO remove some gibs according to cl_nogibs
gib = RubbleNew("gib");
- gib.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(gib, MOVETYPE_BOUNCE);
gib.gravity = 1;
gib.solid = SOLID_CORPSE;
gib.cnt = specnum;
// no gibs in gentle mode, sorry
break;
}
- remove(this);
+ delete(this);
}
#endif
else
{
// Can this happen?
- LOG_WARNINGF("Missing entcs data for player %d\n", who);
+ LOG_WARNF("Missing entcs data for player %d", who);
sound8(e, o, chan, sample, vol, atten, 0, 0);
}
return true;
else
{
// Can this happen?
- LOG_WARNINGF("Missing entcs data for player %d\n", who);
+ LOG_WARNF("Missing entcs data for player %d", who);
sound8(e, o, chan, sample, vol, atten, 0, 0);
}
return true;
int fh = fopen(f, FILE_READ);
if (fh < 0)
{
- LOG_WARNINGF("Player sound file not found: %s\n", f);
+ LOG_WARNF("Player sound file not found: %s", f);
return;
}
for (string s; (s = fgets(fh)); )
int n = tokenize_console(s);
if (n != 3)
{
- if (n != 0) LOG_WARNINGF("Invalid sound info line: %s\n", s);
+ if (n != 0) LOG_WARNF("Invalid sound info line: %s", s);
continue;
}
string file = argv(1);
int fh = fopen(f, FILE_READ);
if (fh < 0)
{
- if (strict) LOG_WARNINGF("Player sound file not found: %s\n", f);
+ if (strict) LOG_WARNF("Player sound file not found: %s", f);
return false;
}
for (string s; (s = fgets(fh)); )
int n = tokenize_console(s);
if (n != 3)
{
- if (n != 0) LOG_WARNINGF("Invalid sound info line: %s\n", s);
+ if (n != 0) LOG_WARNF("Invalid sound info line: %s", s);
continue;
}
string key = argv(0);
if (GetPlayerSoundSampleField_notFound) field = GetVoiceMessageSampleField(key);
if (GetPlayerSoundSampleField_notFound)
{
- LOG_TRACEF("Invalid sound info field: %s\n", key);
+ LOG_TRACEF("Invalid sound info field: %s", key);
continue;
}
string file = argv(1);
-#ifndef GLOBALSOUND_H
-#define GLOBALSOUND_H
+#pragma once
#ifdef SVQC
/** Use new sound handling. TODO: use when sounds play correctly on clients */
FOREACH(PlayerSounds, it.instanceOfVoiceMessage, allvoicesamples = strcat(allvoicesamples, " ", it.m_playersoundstr));
allvoicesamples = strzone(substring(allvoicesamples, 1, -1));
}
-
-#endif
this.alpha = this.cnt * bound(0, 1 - (time - this.lifetime) / this.fadetime, 1);
if(this.alpha < ALPHA_MIN_VISIBLE)
{
- remove(this);
+ delete(this);
return;
}
this.drawmask = MASK_NORMAL;
e.draw = ModelEffect_Draw;
if (isnew) IL_PUSH(g_drawables, e);
- if (!isnew) remove(e); // yes, this IS stupid, but I don't need to duplicate all the read* stuff then
+ if (!isnew) delete(e); // yes, this IS stupid, but I don't need to duplicate all the read* stuff then
return true;
}
#endif
-#ifndef RUBBLE_H
-#define RUBBLE_H
+#pragma once
#ifdef CSQC
}
#endif
-
-#endif
void entcs_detach(entity player)
{
if (!player.entcs) return;
- remove(player.entcs);
+ delete(player.entcs);
player.entcs = NULL;
}
int n = this.sv_entnum;
entity e = entcs_receiver(n);
entcs_receiver(n, NULL);
- if (e != this) remove(e);
+ if (e != this) delete(e);
}
void entcs_think(entity this)
-#ifndef ENT_CS_H
-#define ENT_CS_H
+#pragma once
REGISTER_NET_LINKED(ENT_CLIENT_ENTCS)
REGISTER_NET_TEMP(CLIENT_ENTCS)
}
#endif
-
-#endif
}
const float ST_NEXBALL_GOALS = 1;
-const float SP_NEXBALL_GOALS = 4;
-const float SP_NEXBALL_FAULTS = 5;
void nb_ScoreRules(int teams)
{
ScoreRules_basics(teams, 0, 0, true);
{
if(!g_nexball)
{
- remove(this);
+ delete(this);
return;
}
this.team = this.cnt + 1;
void nb_spawnteam(string teamname, float teamcolor)
{
- LOG_TRACE("^2spawned team ", teamname, "\n");
+ LOG_TRACE("^2spawned team ", teamname);
entity e = new(nexball_team);
e.netname = teamname;
e.cnt = teamcolor;
void SpawnBall(entity this)
{
- if(!g_nexball) { remove(this); return; }
+ if(!g_nexball) { delete(this); return; }
// balls += 4; // using the remaining bits to count balls will leave more than the max edict count, so it's fine
void SpawnGoal(entity this)
{
- if(!g_nexball) { remove(this); return; }
+ if(!g_nexball) { delete(this); return; }
EXACTTRIGGER_INIT;
GiveBall(attacker, toucher.ballcarried);
}
}
- remove(this);
+ delete(this);
}
-void W_Nexball_Attack(entity actor, float t)
+void W_Nexball_Attack(entity actor, .entity weaponentity, float t)
{
entity ball;
float mul, mi, ma;
if(!(ball = actor.ballcarried))
return;
- W_SetupShot(actor, false, 4, SND_NB_SHOOT1, CH_WEAPON_A, 0);
+ W_SetupShot(actor, weaponentity, false, 4, SND_NB_SHOOT1, CH_WEAPON_A, 0);
tracebox(w_shotorg, BALL_MINS, BALL_MAXS, w_shotorg, MOVE_WORLDONLY, NULL);
if(trace_startsolid)
{
vector trigger_push_calculatevelocity(vector org, entity tgt, float ht);
-void W_Nexball_Attack2(entity actor)
+void W_Nexball_Attack2(entity actor, .entity weaponentity)
{
if(actor.ballcarried.enemy)
{
entity _ball = actor.ballcarried;
- W_SetupShot(actor, false, 4, SND_NB_SHOOT1, CH_WEAPON_A, 0);
+ W_SetupShot(actor, weaponentity, false, 4, SND_NB_SHOOT1, CH_WEAPON_A, 0);
DropBall(_ball, w_shotorg, trigger_push_calculatevelocity(_ball.origin, _ball.enemy, 32));
setthink(_ball, W_Nexball_Think);
_ball.nextthink = time;
if(!autocvar_g_nexball_tackling)
return;
- W_SetupShot(actor, false, 2, SND_NB_SHOOT2, CH_WEAPON_A, 0);
+ W_SetupShot(actor, weaponentity, false, 2, SND_NB_SHOOT2, CH_WEAPON_A, 0);
entity missile = new(ballstealer);
missile.owner = actor;
missile.effects = EF_BRIGHTFIELD | EF_LOWPRECISION;
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
CSQCProjectile(missile, true, PROJECTILE_ELECTRO, true);
}
}
else
{
- W_Nexball_Attack(actor, -1);
+ W_Nexball_Attack(actor, weaponentity, -1);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
}
if(fire & 2)
if(weapon_prepareattack(thiswep, actor, weaponentity, true, autocvar_g_balance_nexball_secondary_refire))
{
- W_Nexball_Attack2(actor);
+ W_Nexball_Attack2(actor, weaponentity);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, autocvar_g_balance_nexball_secondary_animtime, w_ready);
}
if(!(fire & 1) && actor.metertime && actor.ballcarried)
{
- W_Nexball_Attack(actor, time - actor.metertime);
+ W_Nexball_Attack(actor, weaponentity, time - actor.metertime);
// DropBall or stealing will set metertime back to 0
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
}
setmodel(this.icon_realmodel, MDL_Null);
setorigin(this.icon_realmodel, this.origin);
setsize(this.icon_realmodel, CPICON_MIN, CPICON_MAX);
- this.icon_realmodel.move_movetype = MOVETYPE_NOCLIP;
+ set_movetype(this.icon_realmodel, MOVETYPE_NOCLIP);
this.icon_realmodel.solid = SOLID_NOT;
}
if(this.iscaptured) { this.icon_realmodel.solid = SOLID_BBOX; }
- this.move_movetype = MOVETYPE_NOCLIP;
+ set_movetype(this, MOVETYPE_NOCLIP);
this.solid = SOLID_NOT;
- this.move_movetype = MOVETYPE_NOCLIP;
+ set_movetype(this, MOVETYPE_NOCLIP);
this.move_time = time;
this.drawmask = MASK_NORMAL;
this.alpha = 1;
if(this.count > 10)
{
- remove(this);
+ delete(this);
return;
}
setmodel(e, MDL_ONS_RAY);
setorigin(e, org);
e.angles = randomvec() * 360;
- e.move_movetype = MOVETYPE_NONE;
+ set_movetype(e, MOVETYPE_NONE);
e.alpha = 0;
e.scale = random() * 5 + 8;
e.move_time = time + 0.05;
setmodel(this, MDL_ONS_GEN);
setsize(this, GENERATOR_MIN, GENERATOR_MAX);
- this.move_movetype = MOVETYPE_NOCLIP;
+ set_movetype(this, MOVETYPE_NOCLIP);
this.solid = SOLID_BBOX;
- this.move_movetype = MOVETYPE_NOCLIP;
+ set_movetype(this, MOVETYPE_NOCLIP);
this.move_time = time;
this.drawmask = MASK_NORMAL;
this.alpha = 1;
// score rule declarations
const int ST_ONS_CAPS = 1;
-const int SP_ONS_CAPS = 4;
-const int SP_ONS_TAKES = 6;
#endif
#endif
{
entity l;
// first check if the game has ended
- LOG_DEBUG("--- updatelinks ---\n");
+ LOG_DEBUG("--- updatelinks ---");
// mark generators as being shielded and networked
for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
{
if (l.iscaptured)
- LOG_DEBUG(strcat(etos(l), " (generator) belongs to team ", ftos(l.team), "\n"));
+ LOG_DEBUG(etos(l), " (generator) belongs to team ", ftos(l.team));
else
- LOG_DEBUG(strcat(etos(l), " (generator) is destroyed\n"));
+ LOG_DEBUG(etos(l), " (generator) is destroyed");
l.islinked = l.iscaptured;
l.isshielded = l.iscaptured;
l.sprite.SendFlags |= 16;
l.isshielded = true;
int i;
for(i = 0; i < 17; ++i) { l.isgenneighbor[i] = false; l.iscpneighbor[i] = false; }
- LOG_DEBUG(strcat(etos(l), " (point) belongs to team ", ftos(l.team), "\n"));
+ LOG_DEBUG(etos(l), " (point) belongs to team ", ftos(l.team));
l.sprite.SendFlags |= 16;
}
// flow power outward from the generators through the network
{
stop = false;
l.goalentity.islinked = true;
- LOG_DEBUG(strcat(etos(l), " (link) is marking ", etos(l.goalentity), " (point) because its team matches ", etos(l.enemy), " (point)\n"));
+ LOG_DEBUG(etos(l), " (link) is marking ", etos(l.goalentity), " (point) because its team matches ", etos(l.enemy), " (point)");
}
else if (!l.enemy.islinked)
{
stop = false;
l.enemy.islinked = true;
- LOG_DEBUG(strcat(etos(l), " (link) is marking ", etos(l.enemy), " (point) because its team matches ", etos(l.goalentity), " (point)\n"));
+ LOG_DEBUG(etos(l), " (link) is marking ", etos(l.enemy), " (point) because its team matches ", etos(l.goalentity), " (point)");
}
}
}
{
if(DIFF_TEAM(l.goalentity, l.enemy))
{
- LOG_DEBUG(strcat(etos(l), " (link) is unshielding ", etos(l.enemy), " (point) because its team does not match ", etos(l.goalentity), " (point)\n"));
+ LOG_DEBUG(etos(l), " (link) is unshielding ", etos(l.enemy), " (point) because its team does not match ", etos(l.goalentity), " (point)");
l.enemy.isshielded = false;
}
if(l.goalentity.classname == "onslaught_generator")
{
if(DIFF_TEAM(l.goalentity, l.enemy))
{
- LOG_DEBUG(strcat(etos(l), " (link) is unshielding ", etos(l.goalentity), " (point) because its team does not match ", etos(l.enemy), " (point)\n"));
+ LOG_DEBUG(etos(l), " (link) is unshielding ", etos(l.goalentity), " (point) because its team does not match ", etos(l.enemy), " (point)");
l.goalentity.isshielded = false;
}
if(l.enemy.classname == "onslaught_generator")
{
if (l.isshielded)
{
- LOG_DEBUG(strcat(etos(l), " (generator) is shielded\n"));
+ LOG_DEBUG(etos(l), " (generator) is shielded");
l.takedamage = DAMAGE_NO;
l.bot_attack = false;
}
else
{
- LOG_DEBUG(strcat(etos(l), " (generator) is not shielded\n"));
+ LOG_DEBUG(etos(l), " (generator) is not shielded");
l.takedamage = DAMAGE_AIM;
l.bot_attack = true;
}
{
if (l.isshielded)
{
- LOG_DEBUG(strcat(etos(l), " (point) is shielded\n"));
+ LOG_DEBUG(etos(l), " (point) is shielded");
if (l.goalentity)
{
l.goalentity.takedamage = DAMAGE_NO;
}
else
{
- LOG_DEBUG(strcat(etos(l), " (point) is not shielded\n"));
+ LOG_DEBUG(etos(l), " (point) is not shielded");
if (l.goalentity)
{
l.goalentity.takedamage = DAMAGE_AIM;
if(!this.goalentity) { objerror(this, "can not find target\n"); }
if(!this.enemy) { objerror(this, "can not find target2\n"); }
- LOG_DEBUG(strcat(etos(this.goalentity), " linked with ", etos(this.enemy), "\n"));
+ LOG_DEBUG(etos(this.goalentity), " linked with ", etos(this.enemy));
this.SendFlags |= 3;
setthink(this, ons_Link_CheckUpdate);
this.nextthink = time;
setmodel_fixsize(this.owner, MDL_ONS_CP_PAD1);
//setsize(this, '-32 -32 0', '32 32 8');
- remove(this);
+ delete(this);
}
this.SendFlags |= CPSF_STATUS;
void ons_ControlPoint_Reset(entity this)
{
if(this.goalentity)
- remove(this.goalentity);
+ delete(this.goalentity);
this.goalentity = NULL;
this.team = 0;
if(!needweapons && !needarmor)
return;
- LOG_DEBUG(strcat(this.netname, " needs weapons ", ftos(needweapons) , "\n"));
- LOG_DEBUG(strcat(this.netname, " needs armor ", ftos(needarmor) , "\n"));
+ LOG_DEBUG(this.netname, " needs weapons ", ftos(needweapons));
+ LOG_DEBUG(this.netname, " needs armor ", ftos(needarmor));
// See what is around
FOREACH_ENTITY_FLOAT(bot_pickup, true,
void havocbot_role_ons_setrole(entity this, int role)
{
- LOG_DEBUG(strcat(this.netname," switched to "));
+ LOG_DEBUG(this.netname," switched to ");
switch(role)
{
case HAVOCBOT_ONS_ROLE_DEFENSE:
this.havocbot_role_timeout = 0;
break;
}
- LOG_DEBUG("\n");
+ LOG_DEBUG("");
}
void havocbot_goalrating_ons_controlpoints_attack(entity this, float ratingscale)
if (!cp)
return;
- LOG_DEBUG(strcat(this.netname, " chose cp ranked ", ftos(bestvalue), "\n"));
+ LOG_DEBUG(this.netname, " chose cp ranked ", ftos(bestvalue));
if(cp.goalentity)
{
{
navigation_routerating(this, cp, ratingscale, 10000);
}
- LOG_DEBUG(strcat(this.netname, " found an attackable controlpoint at ", vtos(cp.origin) ,"\n"));
+ LOG_DEBUG(this.netname, " found an attackable controlpoint at ", vtos(cp.origin));
}
else
{
// Should be touched
- LOG_DEBUG(strcat(this.netname, " found a touchable controlpoint at ", vtos(cp.origin) ,"\n"));
+ LOG_DEBUG(this.netname, " found a touchable controlpoint at ", vtos(cp.origin));
found = false;
// Look for auto generated waypoint
if(bestwp)
{
- LOG_DEBUG("waypoints found around generator\n");
+ LOG_DEBUG("waypoints found around generator");
navigation_routerating(this, bestwp, ratingscale, 10000);
bestwp.cnt += 1;
}
else
{
- LOG_DEBUG("generator found without waypoints around\n");
+ LOG_DEBUG("generator found without waypoints around");
// if there aren't waypoints near the generator go straight to it
navigation_routerating(this, g, ratingscale, 10000);
this.havocbot_attack_time = 0;
{
entity own = this.owner;
- if(!own) { remove(this); return; }
+ if(!own) { delete(this); return; }
if(own.targetname)
{
}
}
- remove(this);
+ delete(this);
}
MUTATOR_HOOKFUNCTION(ons, MonsterSpawn)
{
entity own = this.owner;
- if(!own) { remove(this); return; }
+ if(!own) { delete(this); return; }
if(own.targetname)
{
}
}
- remove(this);
+ delete(this);
}
MUTATOR_HOOKFUNCTION(ons, TurretSpawn)
*/
spawnfunc(onslaught_link)
{
- if(!g_onslaught) { remove(this); return; }
+ if(!g_onslaught) { delete(this); return; }
if (this.target == "" || this.target2 == "")
objerror(this, "target and target2 must be set\n");
spawnfunc(onslaught_controlpoint)
{
- if(!g_onslaught) { remove(this); return; }
+ if(!g_onslaught) { delete(this); return; }
ons_ControlPoint_Setup(this);
}
*/
spawnfunc(onslaught_generator)
{
- if(!g_onslaught) { remove(this); return; }
+ if(!g_onslaught) { delete(this); return; }
if(!this.team) { objerror(this, "team must be set"); }
ons_GeneratorSetup(this);
if(c4 >= 0) teams |= BIT(3);
ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, 0, true);
ScoreInfo_SetLabel_TeamScore (ST_ONS_CAPS, "destroyed", SFL_SORT_PRIO_PRIMARY);
- ScoreInfo_SetLabel_PlayerScore(SP_ONS_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
+ ScoreInfo_SetLabel_PlayerScore(SP_ONS_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
ScoreInfo_SetLabel_PlayerScore(SP_ONS_TAKES, "takes", 0);
ScoreRules_basics_end();
}
-#ifndef IMPULSES_ALL_H
-#define IMPULSES_ALL_H
+#pragma once
REGISTRY(IMPULSES, 255)
REGISTER_REGISTRY(IMPULSES)
CHIMPULSE(CLONE_STANDING, 142)
CHIMPULSE(TELEPORT, 143)
CHIMPULSE(R00T, 148)
-
-#endif
-#ifndef ITEMS_ALL_H
-#define ITEMS_ALL_H
+#pragma once
#include <common/command/all.qh>
#ifndef MENUQC
string Item_Model(string item_mdl);
#endif
-
-#endif
-#ifndef INVENTORY_H
-#define INVENTORY_H
+#pragma once
#include "all.qh"
#include "item/pickup.qh"
CLASS(Inventory, Object)
/** Stores counts of items, the id being the index */
- ATTRIBARRAY(Inventory, inv_items, int, Items_MAX)
+ ATTRIBARRAY(Inventory, inv_items, int, Items_MAX);
/** Previous state */
- ATTRIB(Inventory, inventory, Inventory, NULL)
+ ATTRIB(Inventory, inventory, Inventory);
ENDCLASS(Inventory)
/** Player inventory */
.int fld = inv_items[it.m_id];
int prev = this.(fld);
int next = this.(fld) = ReadByte();
- LOG_TRACEF("%s: %.0f -> %.0f\n", it.m_name, prev, next);
+ LOG_TRACEF("%s: %.0f -> %.0f", it.m_name, prev, next);
});
return true;
}
inv.drawonlytoclient = e;
Net_LinkEntity((inv.owner = e).inventory = inv, false, 0, Inventory_Send);
}
-void Inventory_delete(entity e) { remove(e.inventory.inventory); remove(e.inventory); }
+void Inventory_delete(entity e) { delete(e.inventory.inventory); delete(e.inventory); }
void Inventory_update(entity e) { e.inventory.SendFlags = 0xFFFFFF; }
#endif
-
-#endif
-#ifndef GAMEITEM_H
-#define GAMEITEM_H
+#pragma once
const int IT_UNLIMITED_WEAPON_AMMO = BIT(0); // when this bit is set, using a weapon does not reduce ammo. Checkpoints can give this powerup.
const int IT_UNLIMITED_SUPERWEAPONS = BIT(1); // when this bit is set, superweapons don't expire. Checkpoints can give this powerup.
#define ITEM_HANDLE(signal, ...) __Item_Send_##signal(__VA_ARGS__)
CLASS(GameItem, Object)
- ATTRIB(GameItem, m_id, int, 0)
- ATTRIB(GameItem, m_name, string, string_null)
- ATTRIB(GameItem, m_icon, string, string_null)
- ATTRIB(GameItem, m_color, vector, '1 1 1')
- ATTRIB(GameItem, m_waypoint, string, string_null)
- ATTRIB(GameItem, m_waypointblink, int, 1)
+ ATTRIB(GameItem, m_id, int, 0);
+ ATTRIB(GameItem, m_name, string);
+ ATTRIB(GameItem, m_icon, string);
+ ATTRIB(GameItem, m_color, vector, '1 1 1');
+ ATTRIB(GameItem, m_waypoint, string);
+ ATTRIB(GameItem, m_waypointblink, int, 1);
METHOD(GameItem, display, void(GameItem this, void(string name, string icon) returns))
{
TC(GameItem, this);
}
void ITEM_HANDLE(Show, GameItem this) { this.show(this); }
ENDCLASS(GameItem)
-
-#endif
-#ifndef AMMO_H
-#define AMMO_H
+#pragma once
+
#include "pickup.qh"
CLASS(Ammo, Pickup)
#ifdef SVQC
- ATTRIB(Ammo, m_pickupevalfunc, float(entity player, entity item), commodity_pickupevalfunc)
- ATTRIB(Ammo, m_respawntime, float(), GET(g_pickup_respawntime_ammo))
- ATTRIB(Ammo, m_respawntimejitter, float(), GET(g_pickup_respawntimejitter_ammo))
+ ATTRIB(Ammo, m_pickupevalfunc, float(entity player, entity item), commodity_pickupevalfunc);
+ ATTRIB(Ammo, m_respawntime, float(), GET(g_pickup_respawntime_ammo));
+ ATTRIB(Ammo, m_respawntimejitter, float(), GET(g_pickup_respawntimejitter_ammo));
#endif
ENDCLASS(Ammo)
-#endif
-#ifndef ARMOR_H
-#define ARMOR_H
+#pragma once
+
#include "pickup.qh"
CLASS(Armor, Pickup)
#ifdef SVQC
- ATTRIB(Armor, m_mins, vector, '-16 -16 0')
- ATTRIB(Armor, m_maxs, vector, '16 16 48')
- ATTRIB(Armor, m_pickupevalfunc, float(entity player, entity item), commodity_pickupevalfunc)
+ ATTRIB(Armor, m_mins, vector, '-16 -16 0');
+ ATTRIB(Armor, m_maxs, vector, '16 16 48');
+ ATTRIB(Armor, m_pickupevalfunc, float(entity player, entity item), commodity_pickupevalfunc);
#endif
ENDCLASS(Armor)
-#endif
-#ifndef HEALTH_H
-#define HEALTH_H
+#pragma once
+
#include "pickup.qh"
CLASS(Health, Pickup)
#ifdef SVQC
- ATTRIB(Health, m_mins, vector, '-16 -16 0')
- ATTRIB(Health, m_maxs, vector, '16 16 48')
- ATTRIB(Health, m_pickupevalfunc, float(entity player, entity item), commodity_pickupevalfunc)
+ ATTRIB(Health, m_mins, vector, '-16 -16 0');
+ ATTRIB(Health, m_maxs, vector, '16 16 48');
+ ATTRIB(Health, m_pickupevalfunc, float(entity player, entity item), commodity_pickupevalfunc);
#endif
ENDCLASS(Health)
-#endif
-#ifndef PICKUP_H
-#define PICKUP_H
+#pragma once
+
#include <common/items/inventory.qh>
#include <common/items/item.qh>
CLASS(Pickup, GameItem)
#ifndef MENUQC
- ATTRIB(Pickup, m_model, Model, NULL)
- ATTRIB(Pickup, m_sound, Sound, SND_ITEMPICKUP)
+ ATTRIB(Pickup, m_model, Model);
+ ATTRIB(Pickup, m_sound, Sound, SND_ITEMPICKUP);
#endif
- ATTRIB(Pickup, m_name, string, string_null)
+ ATTRIB(Pickup, m_name, string);
METHOD(Pickup, show, void(Pickup this))
{
TC(Pickup, this);
LOG_INFOF("%s: %s\n", etos(this), this.m_name);
}
#ifdef SVQC
- ATTRIB(Pickup, m_mins, vector, '-16 -16 0')
- ATTRIB(Pickup, m_maxs, vector, '16 16 32')
- ATTRIB(Pickup, m_botvalue, int, 0)
- ATTRIB(Pickup, m_itemflags, int, 0)
- ATTRIB(Pickup, m_itemid, int, 0)
+ ATTRIB(Pickup, m_mins, vector, '-16 -16 0');
+ ATTRIB(Pickup, m_maxs, vector, '16 16 32');
+ ATTRIB(Pickup, m_botvalue, int, 0);
+ ATTRIB(Pickup, m_itemflags, int, 0);
+ ATTRIB(Pickup, m_itemid, int, 0);
float generic_pickupevalfunc(entity player, entity item);
- ATTRIB(Pickup, m_pickupevalfunc, float(entity player, entity item), generic_pickupevalfunc)
- ATTRIB(Pickup, m_respawntime, float(), func_null)
- ATTRIB(Pickup, m_respawntimejitter, float(), func_null)
+ ATTRIB(Pickup, m_pickupevalfunc, float(entity player, entity item), generic_pickupevalfunc);
+ ATTRIB(Pickup, m_respawntime, float());
+ ATTRIB(Pickup, m_respawntimejitter, float());
float Item_GiveTo(entity item, entity player);
METHOD(Pickup, giveTo, bool(Pickup this, entity item, entity player))
{
TC(Pickup, this);
bool b = Item_GiveTo(item, player);
if (b) {
- LOG_DEBUGF("entity %i picked up %s\n", player, this.m_name);
+ LOG_DEBUGF("entity %i picked up %s", player, this.m_name);
player.inventory.inv_items[this.m_id]++;
Inventory_update(player);
}
bool ITEM_HANDLE(Pickup, Pickup this, entity item, entity player);
#endif
ENDCLASS(Pickup)
-
-#endif
#include "pickup.qh"
CLASS(Powerup, Pickup)
#ifdef SVQC
- ATTRIB(Powerup, m_mins, vector, '-16 -16 0')
- ATTRIB(Powerup, m_maxs, vector, '16 16 48')
- ATTRIB(Powerup, m_botvalue, int, 100000)
- ATTRIB(Powerup, m_itemflags, int, FL_POWERUP)
- ATTRIB(Powerup, m_respawntime, float(), GET(g_pickup_respawntime_powerup))
- ATTRIB(Powerup, m_respawntimejitter, float(), GET(g_pickup_respawntimejitter_powerup))
+ ATTRIB(Powerup, m_mins, vector, '-16 -16 0');
+ ATTRIB(Powerup, m_maxs, vector, '16 16 48');
+ ATTRIB(Powerup, m_botvalue, int, 100000);
+ ATTRIB(Powerup, m_itemflags, int, FL_POWERUP);
+ ATTRIB(Powerup, m_respawntime, float(), GET(g_pickup_respawntime_powerup));
+ ATTRIB(Powerup, m_respawntimejitter, float(), GET(g_pickup_respawntimejitter_powerup));
#endif
ENDCLASS(Powerup)
return strcasecmp(a, b);
}
-float MapInfo_FilterGametype(int pGametype, int pFeatures, int pFlagsRequired, int pFlagsForbidden, bool pAbortOnGenerate)
+float MapInfo_FilterGametype(Gametype pGametype, int pFeatures, int pFlagsRequired, int pFlagsForbidden, bool pAbortOnGenerate)
+{
+ return _MapInfo_FilterGametype(pGametype.m_flags, pFeatures, pFlagsRequired, pFlagsForbidden, pAbortOnGenerate);
+}
+float _MapInfo_FilterGametype(int pGametype, int pFeatures, int pFlagsRequired, int pFlagsForbidden, bool pAbortOnGenerate)
{
float i, j;
if (!_MapInfo_filtered_allocated)
MapInfo_count = 0;
for(i = 0, j = -1; i < _MapInfo_globcount; ++i)
{
- if(MapInfo_Get_ByName(_MapInfo_GlobItem(i), 1, 0) == 2) // if we generated one... BAIL OUT and let the caller continue in the next frame.
+ if(MapInfo_Get_ByName(_MapInfo_GlobItem(i), 1, NULL) == 2) // if we generated one... BAIL OUT and let the caller continue in the next frame.
if(pAbortOnGenerate)
{
- LOG_TRACE("Autogenerated a .mapinfo, doing the rest later.\n");
+ LOG_TRACE("Autogenerated a .mapinfo, doing the rest later.");
MapInfo_progress = i / _MapInfo_globcount;
return 0;
}
float MapInfo_Get_ByID(float i)
{
- if(MapInfo_Get_ByName(MapInfo_BSPName_ByID(i), 0, 0))
+ if(MapInfo_Get_ByName(MapInfo_BSPName_ByID(i), 0, NULL))
return 1;
return 0;
}
float i;
float inWorldspawn;
float r;
- float twoBaseModes;
float diameter, spawnpoints;
float spawnplaces;
}
else if(k == "classname")
{
- if(v == "dom_controlpoint")
- MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_DOMINATION;
- else if(v == "item_flag_team2")
- MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CTF;
- else if(v == "team_CTF_blueflag")
- MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CTF;
- else if(v == "invasion_spawnpoint")
- MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_INVASION;
- else if(v == "target_assault_roundend")
- MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_ASSAULT;
- else if(v == "onslaught_generator")
- MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_ONSLAUGHT;
- else if(substring(v, 0, 8) == "nexball_" || substring(v, 0, 4) == "ball")
- MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_NEXBALL;
- else if(v == "info_player_team1")
+ if(v == "info_player_team1")
++spawnpoints;
else if(v == "info_player_team2")
++spawnpoints;
++spawnpoints;
else if(v == "info_player_deathmatch")
++spawnpoints;
- else if(v == "trigger_race_checkpoint")
- MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_RACE;
- else if(v == "target_startTimer")
- MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CTS;
else if(v == "weapon_nex")
{ }
else if(v == "weapon_railgun")
MapInfo_Map_supportedFeatures |= MAPINFO_FEATURE_MONSTERS;
else if(v == "target_music" || v == "trigger_music")
_MapInfo_Map_worldspawn_music = string_null; // don't use regular BGM
+ else
+ FOREACH(Gametypes, true, it.m_generate_mapinfo(it, v));
}
}
}
}
diameter = vlen(mapMaxs - mapMins);
- twoBaseModes = MapInfo_Map_supportedGametypes & (MAPINFO_TYPE_CTF | MAPINFO_TYPE_ASSAULT | MAPINFO_TYPE_RACE | MAPINFO_TYPE_NEXBALL);
- if(twoBaseModes && (MapInfo_Map_supportedGametypes == twoBaseModes))
+ int twoBaseModes = 0;
+ FOREACH(Gametypes, it.m_isTwoBaseMode(), twoBaseModes |= it.m_flags);
+ if(twoBaseModes && (twoBaseModes &= MapInfo_Map_supportedGametypes))
{
- // we have a CTF-only or Assault-only map. Don't add other modes then,
- // as the map is too symmetric for them.
+ // we have a symmetrical map, don't add the modes without bases
}
else
{
- MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_DEATHMATCH; // DM always works
- MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_LMS; // LMS always works
- MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_KEEPAWAY; // Keepaway always works
-
- if(spawnpoints >= 8 && diameter > 4096) {
- MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_TEAM_DEATHMATCH;
- MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_FREEZETAG;
- MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CA;
- }
- if(spawnpoints >= 12 && diameter > 5120)
- MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_KEYHUNT;
+ FOREACH(Gametypes, it.m_isAlwaysSupported(it, spawnpoints, diameter), MapInfo_Map_supportedGametypes |= it.m_flags);
}
- if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_RACE)
+ if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_RACE.m_flags)
if(!spawnplaces)
{
- MapInfo_Map_supportedGametypes &= ~MAPINFO_TYPE_RACE;
- MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CTS;
+ MapInfo_Map_supportedGametypes &= ~MAPINFO_TYPE_RACE.m_flags;
+ MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CTS.m_flags;
}
LOG_TRACE("-> diameter ", ftos(diameter));
LOG_TRACE("; spawnpoints ", ftos(spawnpoints));
- LOG_TRACE("; modes ", ftos(MapInfo_Map_supportedGametypes), "\n");
+ LOG_TRACE("; modes ", ftos(MapInfo_Map_supportedGametypes));
fclose(fh);
MapInfo_Map_maxs = '0 0 0';
}
-string _MapInfo_GetDefault(float t)
+string _MapInfo_GetDefault(Gametype t)
{
switch(t)
{
}
}
-void _MapInfo_Map_ApplyGametype(string s, int pWantedType, int pThisType, int load_default)
+void _MapInfo_Map_ApplyGametype(string s, Gametype pWantedType, Gametype pThisType, int load_default)
{
string sa;
- MapInfo_Map_supportedGametypes |= pThisType;
- if(!(pThisType & pWantedType))
+ MapInfo_Map_supportedGametypes |= pThisType.m_flags;
+ if(!(pThisType.m_flags & pWantedType.m_flags))
return;
if(load_default)
cvar_set("timelimit", sa);
s = cdr(s);
- if(pWantedType == MAPINFO_TYPE_TEAM_DEATHMATCH)
- {
- sa = car(s);
- if(sa != "")
- cvar_set("g_tdm_teams", sa);
- s = cdr(s);
- }
-
- if(pWantedType == MAPINFO_TYPE_KEYHUNT)
- {
- sa = car(s);
- if(sa != "")
- cvar_set("g_keyhunt_teams", sa);
- s = cdr(s);
- }
-
- if(pWantedType == MAPINFO_TYPE_CA)
- {
- sa = car(s);
- if(sa != "")
- cvar_set("g_ca_teams", sa);
- s = cdr(s);
- }
-
- if(pWantedType == MAPINFO_TYPE_FREEZETAG)
- {
- sa = car(s);
- if(sa != "")
- cvar_set("g_freezetag_teams", sa);
- s = cdr(s);
- }
-
- if(pWantedType == MAPINFO_TYPE_CTF)
- {
- sa = car(s);
- if(sa != "")
- cvar_set("fraglimit", sa);
- s = cdr(s);
- }
-
- /* keepaway wuz here
- if(pWantedType == MAPINFO_TYPE_KEEPAWAY)
+ if(pWantedType.m_setTeams)
{
sa = car(s);
if(sa != "")
- cvar_set("fraglimit", sa);
+ pWantedType.m_setTeams(sa);
s = cdr(s);
}
- */
// rc = timelimit timelimit_qualification laps laps_teamplay
if(pWantedType == MAPINFO_TYPE_RACE)
s = cdr(s);
}
- if(pWantedType == MAPINFO_TYPE_CTS)
- {
- sa = car(s);
-
- // this is the skill of the map
- // not parsed by anything yet
- // for map databases
- //if(sa != "")
- // cvar_set("fraglimit", sa);
-
- s = cdr(s);
- }
-
if(pWantedType == MAPINFO_TYPE_ASSAULT || pWantedType == MAPINFO_TYPE_ONSLAUGHT || pWantedType == MAPINFO_TYPE_CTS) // these modes don't use fraglimit
{
cvar_set("leadlimit", "0");
}
}
-string _MapInfo_GetDefaultEx(float t)
+string _MapInfo_GetDefaultEx(Gametype t)
{
- FOREACH(Gametypes, it.items == t, return it.model2);
- return "";
+ return t ? t.model2 : "";
}
-float _MapInfo_GetTeamPlayBool(float t)
+float _MapInfo_GetTeamPlayBool(Gametype t)
{
- FOREACH(Gametypes, it.items == t, return it.team);
- return false;
+ return t ? t.team : false;
}
-void _MapInfo_Map_ApplyGametypeEx(string s, int pWantedType, int pThisType)
+void _MapInfo_Map_ApplyGametypeEx(string s, Gametype pWantedType, Gametype pThisType)
{
- MapInfo_Map_supportedGametypes |= pThisType;
- if (!(pThisType & pWantedType))
+ MapInfo_Map_supportedGametypes |= pThisType.m_flags;
+ if (!(pThisType.m_flags & pWantedType.m_flags))
return;
// reset all the cvars to their defaults
}
}
-Gametype MapInfo_Type(int t)
-{
- FOREACH(Gametypes, it.items == t, return it);
- return NULL;
-}
-
-int MapInfo_Type_FromString(string t)
+Gametype MapInfo_Type_FromString(string t)
{
#define deprecate(from, to) MACRO_BEGIN { \
if (t == #from) { \
deprecate(invasion, inv);
deprecate(assault, as);
deprecate(race, rc);
- if (t == "all") return MAPINFO_TYPE_ALL;
- FOREACH(Gametypes, it.mdl == t, return it.items);
- return 0;
+ FOREACH(Gametypes, it.mdl == t, return it);
+ return NULL;
#undef deprecate
}
-string MapInfo_Type_Description(float t)
+string MapInfo_Type_Description(Gametype t)
{
- FOREACH(Gametypes, it.items == t, return it.gametype_description);
- return "";
+ return t ? t.gametype_description : "";
}
-string MapInfo_Type_ToString(float t)
+string MapInfo_Type_ToString(Gametype t)
{
- if(t == MAPINFO_TYPE_ALL)
- return "all";
- FOREACH(Gametypes, it.items == t, return it.mdl);
- return "";
+ return t ? t.mdl : "";
}
-string MapInfo_Type_ToText(float t)
+string MapInfo_Type_ToText(Gametype t)
{
- FOREACH(Gametypes, it.items == t, return it.message);
/* xgettext:no-c-format */
- return _("@!#%'n Tuba Throwing");
+ return t ? t.message : _("@!#%'n Tuba Throwing");
}
void _MapInfo_Parse_Settemp(string pFilename, string acl, float type, string s, float recurse)
{
if(type == 0) // server set
{
- LOG_TRACE("Applying temporary setting ", t, " := ", s, "\n");
+ LOG_TRACE("Applying temporary setting ", t, " := ", s);
if(cvar("g_campaign"))
cvar_set(t, s); // this is a wrapper and is always temporary anyway; no need to backup old values then
else
}
else
{
- LOG_TRACE("Applying temporary client setting ", t, " := ", s, "\n");
+ LOG_TRACE("Applying temporary client setting ", t, " := ", s);
MapInfo_Map_clientstuff = strcat(
MapInfo_Map_clientstuff, "cl_cmd settemp \"", t, "\" \"", s, "\"\n"
);
}
// load info about a map by name into the MapInfo_Map_* globals
-float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, int pGametypeToSet)
+float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, Gametype pGametypeToSet)
{
string fn;
string s, t;
return 0;
}
- if(pGametypeToSet == 0)
+ if(pGametypeToSet == NULL)
if(MapInfo_Cache_Retrieve(pFilename))
return 1;
if(MapInfo_Map_flags & MAPINFO_FLAG_FRUSTRATING)
fputs(fh, "frustrating\n");
- for(i = 1; i <= MapInfo_Map_supportedGametypes; i *= 2)
- if(MapInfo_Map_supportedGametypes & i)
- fputs(fh, sprintf("gametype %s // defaults: %s\n", MapInfo_Type_ToString(i), _MapInfo_GetDefaultEx(i)));
+ FOREACH(Gametypes, MapInfo_Map_supportedGametypes & it.m_flags, {
+ fputs(fh, sprintf("gametype %s // defaults: %s\n", MapInfo_Type_ToString(it), _MapInfo_GetDefaultEx(it)));
+ });
if(fexists(strcat("scripts/", pFilename, ".arena")))
fputs(fh, "settemp_for_type all sv_q3acompat_machineshotgunswap 1\n");
else if(t == "type")
{
t = car(s); s = cdr(s);
- f = MapInfo_Type_FromString(t);
+ Gametype f = MapInfo_Type_FromString(t);
LOG_MAPWARN("Map ", pFilename, " contains the legacy 'type' keyword which is deprecated and will be removed in the future. Please migrate the mapinfo file to 'gametype'.\n");
if(f)
_MapInfo_Map_ApplyGametype (s, pGametypeToSet, f, true);
else if(t == "gametype")
{
t = car(s); s = cdr(s);
- f = MapInfo_Type_FromString(t);
+ Gametype f = MapInfo_Type_FromString(t);
if(f)
_MapInfo_Map_ApplyGametypeEx (s, pGametypeToSet, f);
else
else if(t == "settemp_for_type")
{
t = car(s); s = cdr(s);
+ Gametype f;
if((f = MapInfo_Type_FromString(t)))
{
- if(f & pGametypeToSet)
+ if(f.m_flags & pGametypeToSet.m_flags)
{
_MapInfo_Parse_Settemp(pFilename, acl, 0, s, 1);
}
else if(t == "clientsettemp_for_type")
{
t = car(s); s = cdr(s);
+ Gametype f;
if((f = MapInfo_Type_FromString(t)))
{
- if(f & pGametypeToSet)
+ if(f.m_flags & pGametypeToSet.m_flags)
{
_MapInfo_Parse_Settemp(pFilename, acl, 1, s, 1);
}
LOG_MAPWARN("Map ", pFilename, " supports no game types, ignored\n");
return 0;
}
-float MapInfo_Get_ByName(string pFilename, float pAllowGenerate, int pGametypeToSet)
+int MapInfo_Get_ByName(string pFilename, float pAllowGenerate, Gametype pGametypeToSet)
{
- float r = MapInfo_Get_ByName_NoFallbacks(pFilename, pAllowGenerate, pGametypeToSet);
+ int r = MapInfo_Get_ByName_NoFallbacks(pFilename, pAllowGenerate, pGametypeToSet);
if(cvar("g_tdm_on_dm_maps"))
{
// if this is set, all DM maps support TDM too
- if (!(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_TEAM_DEATHMATCH))
- if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_DEATHMATCH)
+ if (!(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_TEAM_DEATHMATCH.m_flags))
+ if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_DEATHMATCH.m_flags)
_MapInfo_Map_ApplyGametypeEx ("", pGametypeToSet, MAPINFO_TYPE_TEAM_DEATHMATCH);
}
if(pGametypeToSet)
{
- if(!(MapInfo_Map_supportedGametypes & pGametypeToSet))
+ if(!(MapInfo_Map_supportedGametypes & pGametypeToSet.m_flags))
{
error("Can't select the requested game type. This should never happen as the caller should prevent it!\n");
//_MapInfo_Map_ApplyGametypeEx("", pGametypeToSet, MAPINFO_TYPE_DEATHMATCH);
return req;
}
-int MapInfo_CurrentGametype()
+Gametype MapInfo_CurrentGametype()
{
- int prev = cvar("gamecfg");
- FOREACH(Gametypes, cvar(it.netname) && it.items != prev, return it.items);
- if (prev) return prev;
- return MAPINFO_TYPE_DEATHMATCH;
+ Gametype prev = Gametypes_from(cvar("gamecfg"));
+ FOREACH(Gametypes, cvar(it.netname) && it != prev, return it);
+ return prev ? prev : MAPINFO_TYPE_DEATHMATCH;
}
float _MapInfo_CheckMap(string s) // returns 0 if the map can't be played with the current settings, 1 otherwise
{
- if(!MapInfo_Get_ByName(s, 1, 0))
+ if(!MapInfo_Get_ByName(s, 1, NULL))
return 0;
- if((MapInfo_Map_supportedGametypes & MapInfo_CurrentGametype()) == 0)
+ if((MapInfo_Map_supportedGametypes & MapInfo_CurrentGametype().m_flags) == 0)
return 0;
if((MapInfo_Map_supportedFeatures & MapInfo_CurrentFeatures()) != MapInfo_CurrentFeatures())
return 0;
return r;
}
-void MapInfo_SwitchGameType(int t)
+void MapInfo_SwitchGameType(Gametype t)
{
- FOREACH(Gametypes, true, cvar_set(it.netname, (it.items == t) ? "1" : "0"));
+ FOREACH(Gametypes, true, cvar_set(it.netname, (it == t) ? "1" : "0"));
}
void MapInfo_LoadMap(string s, float reinit)
//if(!MapInfo_CheckMap(s))
//{
// print("EMERGENCY: can't play the selected map in the given game mode. Falling back to DM.\n");
- // MapInfo_SwitchGameType(MAPINFO_TYPE_DEATHMATCH);
+ // MapInfo_SwitchGameType(MAPINFO_TYPE_DEATHMATCH.m_flags);
//}
cvar_settemp_restore();
localcmd(strcat("\nchangelevel ", s, "\n"));
}
-string MapInfo_ListAllowedMaps(float type, float pRequiredFlags, float pForbiddenFlags)
+string MapInfo_ListAllowedMaps(Gametype type, float pRequiredFlags, float pForbiddenFlags)
{
string out;
float i;
// to make absolutely sure:
MapInfo_Enumerate();
- MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, pRequiredFlags, pForbiddenFlags, 0);
+ _MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, pRequiredFlags, pForbiddenFlags, 0);
out = "";
for(i = 0; i < MapInfo_count; ++i)
return substring(out, 1, strlen(out) - 1);
}
-void MapInfo_LoadMapSettings_SaveGameType(float t)
+void MapInfo_LoadMapSettings_SaveGameType(Gametype t)
{
MapInfo_SwitchGameType(t);
- cvar_set("gamecfg", ftos(t));
+ cvar_set("gamecfg", ftos(t.m_id));
MapInfo_LoadedGametype = t;
}
void MapInfo_LoadMapSettings(string s) // to be called from worldspawn
{
- float t;
-
- t = MapInfo_CurrentGametype();
+ Gametype t = MapInfo_CurrentGametype();
MapInfo_LoadMapSettings_SaveGameType(t);
if(!_MapInfo_CheckMap(s)) // with underscore, it keeps temps
{
if(cvar("g_mapinfo_allow_unsupported_modes_and_let_stuff_break"))
{
- LOG_SEVERE("can't play the selected map in the given game mode. Working with only the override settings.\n");
+ LOG_SEVERE("can't play the selected map in the given game mode. Working with only the override settings.");
_MapInfo_Map_ApplyGametypeEx("", t, t);
return; // do not call Get_ByName!
}
if(MapInfo_Map_supportedGametypes == 0)
{
- LOG_SEVERE("Mapinfo system is not functional at all. Assuming deathmatch.\n");
- MapInfo_Map_supportedGametypes = MAPINFO_TYPE_DEATHMATCH;
+ LOG_SEVERE("Mapinfo system is not functional at all. Assuming deathmatch.");
+ MapInfo_Map_supportedGametypes = MAPINFO_TYPE_DEATHMATCH.m_flags;
MapInfo_LoadMapSettings_SaveGameType(MAPINFO_TYPE_DEATHMATCH);
_MapInfo_Map_ApplyGametypeEx("", MAPINFO_TYPE_DEATHMATCH, MAPINFO_TYPE_DEATHMATCH);
return; // do not call Get_ByName!
}
- t = 1;
+ int _t = 1;
while(!(MapInfo_Map_supportedGametypes & 1))
{
- t *= 2;
- MapInfo_Map_supportedGametypes = floor(MapInfo_Map_supportedGametypes / 2);
+ _t <<= 1;
+ MapInfo_Map_supportedGametypes = floor(MapInfo_Map_supportedGametypes >> 1);
}
+ FOREACH(Gametypes, it.m_flags == _t, { t = it; break; });
// t is now a supported mode!
- LOG_WARNING("can't play the selected map in the given game mode. Falling back to a supported mode.\n");
+ LOG_WARN("can't play the selected map in the given game mode. Falling back to a supported mode.");
MapInfo_LoadMapSettings_SaveGameType(t);
}
MapInfo_Get_ByName(s, 1, t);
-#ifndef MAPINFO_H
-#define MAPINFO_H
+#pragma once
bool autocvar_developer_mapper;
-#define LOG_MAPWARN(...) MACRO_BEGIN { if (autocvar_developer_mapper) LOG_WARNING(__VA_ARGS__); } MACRO_END
-#define LOG_MAPWARNF(...) MACRO_BEGIN { if (autocvar_developer_mapper) LOG_WARNINGF(__VA_ARGS__); } MACRO_END
+#define LOG_MAPWARN(...) MACRO_BEGIN { if (autocvar_developer_mapper) LOG_WARN(__VA_ARGS__); } MACRO_END
+#define LOG_MAPWARNF(...) MACRO_BEGIN { if (autocvar_developer_mapper) LOG_WARNF(__VA_ARGS__); } MACRO_END
#include "util.qh"
+// info about a map that MapInfo loads
+string MapInfo_Map_bspname;
+string MapInfo_Map_title;
+string MapInfo_Map_titlestring; // either bspname: title or just title, depending on whether bspname is redundant
+string MapInfo_Map_description;
+string MapInfo_Map_author;
+string MapInfo_Map_clientstuff; // not in cache, only for map load
+string MapInfo_Map_fog; // not in cache, only for map load
+int MapInfo_Map_supportedGametypes;
+int MapInfo_Map_supportedFeatures;
+int MapInfo_Map_flags;
+vector MapInfo_Map_mins; // these are '0 0 0' if not supported!
+vector MapInfo_Map_maxs; // these are '0 0 0' if not specified!
+
+int MAPINFO_TYPE_ALL;
+.int m_flags;
+
CLASS(Gametype, Object)
- ATTRIB(Gametype, m_id, int, 0)
+ ATTRIB(Gametype, m_id, int, 0);
/** game type ID */
- ATTRIB(Gametype, items, int, 0)
+ ATTRIB(Gametype, items, int, 0);
/** game type name as in cvar (with g_ prefix) */
- ATTRIB(Gametype, netname, string, string_null)
+ ATTRIB(Gametype, netname, string);
/** game type short name */
- ATTRIB(Gametype, mdl, string, string_null)
+ ATTRIB(Gametype, mdl, string);
/** human readable name */
- ATTRIB(Gametype, message, string, string_null)
+ ATTRIB(Gametype, message, string);
/** does this gametype support teamplay? */
- ATTRIB(Gametype, team, bool, false)
+ ATTRIB(Gametype, team, bool, false);
/** game type defaults */
- ATTRIB(Gametype, model2, string, string_null)
+ ATTRIB(Gametype, model2, string);
/** game type description */
- ATTRIB(Gametype, gametype_description, string, string_null)
+ ATTRIB(Gametype, gametype_description, string);
+#ifdef CSQC
+ ATTRIB(Gametype, m_modicons, void(vector pos, vector mySize));
+ ATTRIB(Gametype, m_modicons_reset, void());
+#endif
- ATTRIB(Gametype, m_mutators, string, string_null)
- ATTRIB(Gametype, m_parse_mapinfo, bool(string k, string v), func_null)
+ ATTRIB(Gametype, m_mutators, string);
+ METHOD(Gametype, m_parse_mapinfo, bool(string k, string v))
+ {
+ return false;
+ }
+ METHOD(Gametype, m_generate_mapinfo, void(Gametype this, string v))
+ {
+ TC(Gametype, this);
+ }
+ METHOD(Gametype, m_isTwoBaseMode, bool())
+ {
+ return false;
+ }
+ METHOD(Gametype, m_isAlwaysSupported, bool(Gametype this, int spawnpoints, float diameter))
+ {
+ return false;
+ }
METHOD(Gametype, describe, string(Gametype this))
{
returns(this.message, strcat("gametype_", this.mdl));
}
- CONSTRUCTOR(Gametype, string hname, string sname, string g_name, bool gteamplay, string mutators, string defaults, string gdescription)
+ METHOD(Gametype, gametype_init, void(Gametype this, string hname, string sname, string g_name, bool gteamplay, string mutators, string defaults, string gdescription))
{
- CONSTRUCT(Gametype);
this.netname = g_name;
this.mdl = sname;
this.message = hname;
this.team = gteamplay;
- this.m_mutators = mutators;
+ this.m_mutators = cons(sname, mutators);
this.model2 = defaults;
this.gametype_description = gdescription;
+
+ // same as `1 << m_id`
+ MAPINFO_TYPE_ALL |= this.items = this.m_flags = (MAPINFO_TYPE_ALL + 1);
}
ENDCLASS(Gametype)
-REGISTRY(Gametypes, BITS(4))
+REGISTRY(Gametypes, 24)
#define Gametypes_from(i) _Gametypes_from(i, NULL)
REGISTER_REGISTRY(Gametypes)
REGISTRY_CHECK(Gametypes)
-int MAPINFO_TYPE_ALL;
-#define REGISTER_GAMETYPE(hname, sname, g_name, NAME, gteamplay, mutators, defaults, gdescription) \
- int MAPINFO_TYPE_##NAME; \
- bool NAME##_mapinfo(string k, string v) { return = false; } \
- REGISTER(Gametypes, MAPINFO_TYPE, g_name, m_id, \
- NEW(Gametype, hname, #sname, #g_name, gteamplay, #sname " " mutators, defaults, gdescription) \
- ) { \
- /* same as `1 << m_id` */ \
- MAPINFO_TYPE_##NAME = MAPINFO_TYPE_ALL + 1; MAPINFO_TYPE_ALL |= MAPINFO_TYPE_##NAME; \
- this.items = MAPINFO_TYPE_##NAME; \
- this.m_parse_mapinfo = NAME##_mapinfo; \
- } \
- [[accumulate]] bool NAME##_mapinfo(string k, string v)
-
-#define IS_GAMETYPE(NAME) \
- (MapInfo_LoadedGametype == MAPINFO_TYPE_##NAME)
-
-REGISTER_GAMETYPE(_("Deathmatch"),dm,g_dm,DEATHMATCH,false,"","timelimit=20 pointlimit=30 leadlimit=0",_("Score as many frags as you can"));
-
-REGISTER_GAMETYPE(_("Last Man Standing"),lms,g_lms,LMS,false,"","timelimit=20 lives=9 leadlimit=0",_("Survive and kill until the enemies have no lives left"));
-
-REGISTER_GAMETYPE(_("Race"),rc,g_race,RACE,false,"","timelimit=20 qualifying_timelimit=5 laplimit=7 teamlaplimit=15 leadlimit=0",_("Race against other players to the finish line"))
-{
- if (!k) {
- cvar_set("g_race_qualifying_timelimit", cvar_defstring("g_race_qualifying_timelimit"));
+#define REGISTER_GAMETYPE(NAME, inst) REGISTER(Gametypes, MAPINFO_TYPE, NAME, m_id, inst)
+
+#define IS_GAMETYPE(NAME) (MapInfo_LoadedGametype == MAPINFO_TYPE_##NAME)
+
+CLASS(Deathmatch, Gametype)
+ INIT(Deathmatch)
+ {
+ this.gametype_init(this, _("Deathmatch"),"dm","g_dm",false,"","timelimit=20 pointlimit=30 leadlimit=0",_("Score as many frags as you can"));
+ }
+ METHOD(Deathmatch, m_isAlwaysSupported, bool(Gametype this, int spawnpoints, float diameter))
+ {
+ return true;
+ }
+ENDCLASS(Deathmatch)
+REGISTER_GAMETYPE(DEATHMATCH, NEW(Deathmatch));
+
+CLASS(LastManStanding, Gametype)
+ INIT(LastManStanding)
+ {
+ this.gametype_init(this, _("Last Man Standing"),"lms","g_lms",false,"","timelimit=20 lives=9 leadlimit=0",_("Survive and kill until the enemies have no lives left"));
+ }
+ METHOD(LastManStanding, m_isAlwaysSupported, bool(Gametype this, int spawnpoints, float diameter))
+ {
return true;
}
- switch (k) {
- case "qualifying_timelimit":
- cvar_set("g_race_qualifying_timelimit", v);
+ENDCLASS(LastManStanding)
+REGISTER_GAMETYPE(LMS, NEW(LastManStanding));
+
+#ifdef CSQC
+void HUD_Mod_Race(vector pos, vector mySize);
+#endif
+CLASS(Race, Gametype)
+ INIT(Race)
+ {
+ this.gametype_init(this, _("Race"),"rc","g_race",false,"","timelimit=20 qualifying_timelimit=5 laplimit=7 teamlaplimit=15 leadlimit=0",_("Race against other players to the finish line"));
+ }
+ METHOD(Race, m_parse_mapinfo, bool(string k, string v))
+ {
+ if (!k) {
+ cvar_set("g_race_qualifying_timelimit", cvar_defstring("g_race_qualifying_timelimit"));
return true;
+ }
+ switch (k) {
+ case "qualifying_timelimit":
+ cvar_set("g_race_qualifying_timelimit", v);
+ return true;
+ }
+ return false;
+ }
+ METHOD(Race, m_generate_mapinfo, void(Gametype this, string v))
+ {
+ if(v == "trigger_race_checkpoint")
+ MapInfo_Map_supportedGametypes |= this.m_flags;
}
-}
+ METHOD(Race, m_isTwoBaseMode, bool())
+ {
+ return true;
+ }
+#ifdef CSQC
+ ATTRIB(Race, m_modicons, void(vector pos, vector mySize), HUD_Mod_Race);
+#endif
+ENDCLASS(Race)
+REGISTER_GAMETYPE(RACE, NEW(Race));
#define g_race IS_GAMETYPE(RACE)
-REGISTER_GAMETYPE(_("Race CTS"),cts,g_cts,CTS,false,"cloaked","timelimit=20",_("Race for fastest time."));
+CLASS(RaceCTS, Gametype)
+ INIT(RaceCTS)
+ {
+ this.gametype_init(this, _("Race CTS"),"cts","g_cts",false,"cloaked","timelimit=20",_("Race for fastest time."));
+ }
+ METHOD(RaceCTS, m_generate_mapinfo, void(Gametype this, string v))
+ {
+ if(v == "target_startTimer")
+ MapInfo_Map_supportedGametypes |= this.m_flags;
+ }
+ METHOD(RaceCTS, m_setTeams, void(string sa))
+ {
+ // this is the skill of the map
+ // not parsed by anything yet
+ // for map databases
+ // cvar_set("fraglimit", sa);
+ }
+#ifdef CSQC
+ ATTRIB(RaceCTS, m_modicons, void(vector pos, vector mySize), HUD_Mod_Race);
+#endif
+ENDCLASS(RaceCTS)
+REGISTER_GAMETYPE(CTS, NEW(RaceCTS));
#define g_cts IS_GAMETYPE(CTS)
-REGISTER_GAMETYPE(_("Team Deathmatch"),tdm,g_tdm,TEAM_DEATHMATCH,true,"","timelimit=20 pointlimit=50 teams=2 leadlimit=0",_("Help your team score the most frags against the enemy team"))
-{
- if (!k) {
- cvar_set("g_tdm_teams", cvar_defstring("g_tdm_teams"));
- return true;
+CLASS(TeamDeathmatch, Gametype)
+ INIT(TeamDeathmatch)
+ {
+ this.gametype_init(this, _("Team Deathmatch"),"tdm","g_tdm",true,"","timelimit=20 pointlimit=50 teams=2 leadlimit=0",_("Help your team score the most frags against the enemy team"));
+ }
+ METHOD(TeamDeathmatch, m_parse_mapinfo, bool(string k, string v))
+ {
+ if (!k) {
+ cvar_set("g_tdm_teams", cvar_defstring("g_tdm_teams"));
+ return true;
+ }
+ switch (k) {
+ case "teams":
+ cvar_set("g_tdm_teams", v);
+ return true;
+ }
+ return false;
}
- switch (k) {
- case "teams":
- cvar_set("g_tdm_teams", v);
+ METHOD(TeamDeathmatch, m_isAlwaysSupported, bool(Gametype this, int spawnpoints, float diameter))
+ {
+ if(spawnpoints >= 8 && diameter > 4096)
return true;
+ return false;
+ }
+ METHOD(TeamDeathmatch, m_setTeams, void(string sa))
+ {
+ cvar_set("g_tdm_teams", sa);
}
-}
+ENDCLASS(TeamDeathmatch)
+REGISTER_GAMETYPE(TEAM_DEATHMATCH, NEW(TeamDeathmatch));
#define g_tdm IS_GAMETYPE(TEAM_DEATHMATCH)
-REGISTER_GAMETYPE(_("Capture the Flag"),ctf,g_ctf,CTF,true,"","timelimit=20 caplimit=10 leadlimit=6",_("Find and bring the enemy flag to your base to capture it, defend your base from the other team"));
+#ifdef CSQC
+void HUD_Mod_CTF(vector pos, vector mySize);
+void HUD_Mod_CTF_Reset();
+#endif
+CLASS(CaptureTheFlag, Gametype)
+ INIT(CaptureTheFlag)
+ {
+ this.gametype_init(this, _("Capture the Flag"),"ctf","g_ctf",true,"","timelimit=20 caplimit=10 leadlimit=6",_("Find and bring the enemy flag to your base to capture it, defend your base from the other team"));
+ }
+ METHOD(CaptureTheFlag, m_generate_mapinfo, void(Gametype this, string v))
+ {
+ if(v == "item_flag_team2" || v == "team_CTF_blueflag")
+ MapInfo_Map_supportedGametypes |= this.m_flags;
+ }
+ METHOD(CaptureTheFlag, m_isTwoBaseMode, bool())
+ {
+ return true;
+ }
+ METHOD(CaptureTheFlag, m_setTeams, void(string sa))
+ {
+ cvar_set("fraglimit", sa);
+ }
+#ifdef CSQC
+ ATTRIB(CaptureTheFlag, m_modicons, void(vector pos, vector mySize), HUD_Mod_CTF);
+ ATTRIB(CaptureTheFlag, m_modicons_reset, void(), HUD_Mod_CTF_Reset);
+#endif
+ENDCLASS(CaptureTheFlag)
+REGISTER_GAMETYPE(CTF, NEW(CaptureTheFlag));
#define g_ctf IS_GAMETYPE(CTF)
-REGISTER_GAMETYPE(_("Clan Arena"),ca,g_ca,CA,true,"","timelimit=20 pointlimit=10 teams=2 leadlimit=0",_("Kill all enemy teammates to win the round"))
-{
- if (!k) {
- cvar_set("g_ca_teams", cvar_defstring("g_ca_teams"));
- return true;
+#ifdef CSQC
+void HUD_Mod_CA(vector pos, vector mySize);
+#endif
+CLASS(ClanArena, Gametype)
+ INIT(ClanArena)
+ {
+ this.gametype_init(this, _("Clan Arena"),"ca","g_ca",true,"","timelimit=20 pointlimit=10 teams=2 leadlimit=0",_("Kill all enemy teammates to win the round"));
}
- switch (k) {
- case "teams":
- cvar_set("g_ca_teams", v);
+ METHOD(ClanArena, m_parse_mapinfo, bool(string k, string v))
+ {
+ if (!k) {
+ cvar_set("g_ca_teams", cvar_defstring("g_ca_teams"));
return true;
+ }
+ switch (k) {
+ case "teams":
+ cvar_set("g_ca_teams", v);
+ return true;
+ }
+ return false;
}
-}
+ METHOD(ClanArena, m_isAlwaysSupported, bool(Gametype this, int spawnpoints, float diameter))
+ {
+ if(spawnpoints >= 8 && diameter > 4096)
+ return true;
+ return false;
+ }
+ METHOD(ClanArena, m_setTeams, void(string sa))
+ {
+ cvar_set("g_ca_teams", sa);
+ }
+#ifdef CSQC
+ ATTRIB(ClanArena, m_modicons, void(vector pos, vector mySize), HUD_Mod_CA);
+#endif
+ENDCLASS(ClanArena)
+REGISTER_GAMETYPE(CA, NEW(ClanArena));
#define g_ca IS_GAMETYPE(CA)
-REGISTER_GAMETYPE(_("Domination"),dom,g_domination,DOMINATION,true,"","timelimit=20 pointlimit=200 teams=2 leadlimit=0",_("Capture and defend all the control points to win"))
-{
- if (!k) {
- cvar_set("g_domination_default_teams", cvar_defstring("g_domination_default_teams"));
- return true;
+#ifdef CSQC
+void HUD_Mod_Dom(vector pos, vector mySize);
+#endif
+CLASS(Domination, Gametype)
+ INIT(Domination)
+ {
+ this.gametype_init(this, _("Domination"),"dom","g_domination",true,"","timelimit=20 pointlimit=200 teams=2 leadlimit=0",_("Capture and defend all the control points to win"));
}
- switch (k) {
- case "teams":
- cvar_set("g_domination_default_teams", v);
+ METHOD(Domination, m_parse_mapinfo, bool(string k, string v))
+ {
+ if (!k) {
+ cvar_set("g_domination_default_teams", cvar_defstring("g_domination_default_teams"));
return true;
+ }
+ switch (k) {
+ case "teams":
+ cvar_set("g_domination_default_teams", v);
+ return true;
+ }
+ return false;
}
-}
+ METHOD(Domination, m_generate_mapinfo, void(Gametype this, string v))
+ {
+ if(v == "dom_controlpoint")
+ MapInfo_Map_supportedGametypes |= this.m_flags;
+ }
+#ifdef CSQC
+ ATTRIB(Domination, m_modicons, void(vector pos, vector mySize), HUD_Mod_Dom);
+#endif
+ENDCLASS(Domination)
+REGISTER_GAMETYPE(DOMINATION, NEW(Domination));
-REGISTER_GAMETYPE(_("Key Hunt"),kh,g_keyhunt,KEYHUNT,true,"","timelimit=20 pointlimit=1000 teams=3 leadlimit=0",_("Gather all the keys to win the round"))
-{
- if (!k) {
- cvar_set("g_keyhunt_teams", cvar_defstring("g_keyhunt_teams"));
- return true;
+#ifdef CSQC
+void HUD_Mod_KH(vector pos, vector mySize);
+#endif
+CLASS(KeyHunt, Gametype)
+ INIT(KeyHunt)
+ {
+ this.gametype_init(this, _("Key Hunt"),"kh","g_keyhunt",true,"","timelimit=20 pointlimit=1000 teams=3 leadlimit=0",_("Gather all the keys to win the round"));
}
- switch (k) {
- case "teams":
- cvar_set("g_keyhunt_teams", v);
+ METHOD(KeyHunt, m_parse_mapinfo, bool(string k, string v))
+ {
+ if (!k) {
+ cvar_set("g_keyhunt_teams", cvar_defstring("g_keyhunt_teams"));
return true;
+ }
+ switch (k) {
+ case "teams":
+ cvar_set("g_keyhunt_teams", v);
+ return true;
+ }
+ return false;
+ }
+ METHOD(KeyHunt, m_isAlwaysSupported, bool(Gametype this, int spawnpoints, float diameter))
+ {
+ if(spawnpoints >= 12 && diameter > 5120)
+ return true;
+ return false;
+ }
+ METHOD(KeyHunt, m_setTeams, void(string sa))
+ {
+ cvar_set("g_keyhunt_teams", sa);
}
-}
+#ifdef CSQC
+ ATTRIB(KeyHunt, m_modicons, void(vector pos, vector mySize), HUD_Mod_KH);
+#endif
+ENDCLASS(KeyHunt)
+REGISTER_GAMETYPE(KEYHUNT, NEW(KeyHunt));
-REGISTER_GAMETYPE(_("Assault"),as,g_assault,ASSAULT,true,"","timelimit=20",_("Destroy obstacles to find and destroy the enemy power core before time runs out"));
+CLASS(Assault, Gametype)
+ INIT(Assault)
+ {
+ this.gametype_init(this, _("Assault"),"as","g_assault",true,"","timelimit=20",_("Destroy obstacles to find and destroy the enemy power core before time runs out"));
+ }
+ METHOD(Assault, m_generate_mapinfo, void(Gametype this, string v))
+ {
+ if(v == "target_assault_roundend")
+ MapInfo_Map_supportedGametypes |= this.m_flags;
+ }
+ METHOD(Assault, m_isTwoBaseMode, bool())
+ {
+ return true;
+ }
+ENDCLASS(Assault)
+REGISTER_GAMETYPE(ASSAULT, NEW(Assault));
#define g_assault IS_GAMETYPE(ASSAULT)
-REGISTER_GAMETYPE(_("Onslaught"),ons,g_onslaught,ONSLAUGHT,true,"","pointlimit=1 timelimit=20",_("Capture control points to reach and destroy the enemy generator"));
+CLASS(Onslaught, Gametype)
+ INIT(Onslaught)
+ {
+ this.gametype_init(this, _("Onslaught"),"ons","g_onslaught",true,"","pointlimit=1 timelimit=20",_("Capture control points to reach and destroy the enemy generator"));
+ }
+ METHOD(Onslaught, m_generate_mapinfo, void(Gametype this, string v))
+ {
+ if(v == "onslaught_generator")
+ MapInfo_Map_supportedGametypes |= this.m_flags;
+ }
+ENDCLASS(Onslaught)
+REGISTER_GAMETYPE(ONSLAUGHT, NEW(Onslaught));
-REGISTER_GAMETYPE(_("Nexball"),nb,g_nexball,NEXBALL,true,"","timelimit=20 pointlimit=5 leadlimit=0",_("Shoot and kick the ball into the enemies goal, keep your goal clean"));
+#ifdef CSQC
+void HUD_Mod_NexBall(vector pos, vector mySize);
+#endif
+CLASS(NexBall, Gametype)
+ INIT(NexBall)
+ {
+ this.gametype_init(this, _("Nexball"),"nb","g_nexball",true,"","timelimit=20 pointlimit=5 leadlimit=0",_("Shoot and kick the ball into the enemies goal, keep your goal clean"));
+ }
+ METHOD(NexBall, m_generate_mapinfo, void(Gametype this, string v))
+ {
+ if(substring(v, 0, 8) == "nexball_" || substring(v, 0, 4) == "ball")
+ MapInfo_Map_supportedGametypes |= this.m_flags;
+ }
+ METHOD(NexBall, m_isTwoBaseMode, bool())
+ {
+ return true;
+ }
+#ifdef CSQC
+ ATTRIB(NexBall, m_modicons, void(vector pos, vector mySize), HUD_Mod_NexBall);
+#endif
+ENDCLASS(NexBall)
+REGISTER_GAMETYPE(NEXBALL, NEW(NexBall));
#define g_nexball IS_GAMETYPE(NEXBALL)
-REGISTER_GAMETYPE(_("Freeze Tag"),ft,g_freezetag,FREEZETAG,true,"","timelimit=20 pointlimit=10 teams=2 leadlimit=0",_("Kill enemies to freeze them, stand next to teammates to revive them, freeze the most enemies to win"))
-{
- if (!k) {
- cvar_set("g_freezetag_teams", cvar_defstring("g_freezetag_teams"));
- return true;
+CLASS(FreezeTag, Gametype)
+ INIT(FreezeTag)
+ {
+ this.gametype_init(this, _("Freeze Tag"),"ft","g_freezetag",true,"","timelimit=20 pointlimit=10 teams=2 leadlimit=0",_("Kill enemies to freeze them, stand next to teammates to revive them, freeze the most enemies to win"));
+ }
+ METHOD(FreezeTag, m_parse_mapinfo, bool(string k, string v))
+ {
+ if (!k) {
+ cvar_set("g_freezetag_teams", cvar_defstring("g_freezetag_teams"));
+ return true;
+ }
+ switch (k) {
+ case "teams":
+ cvar_set("g_freezetag_teams", v);
+ return true;
+ }
+ return false;
}
- switch (k) {
- case "teams":
- cvar_set("g_freezetag_teams", v);
+ METHOD(FreezeTag, m_isAlwaysSupported, bool(Gametype this, int spawnpoints, float diameter))
+ {
+ if(spawnpoints >= 8 && diameter > 4096)
return true;
+ return false;
+ }
+ METHOD(FreezeTag, m_setTeams, void(string sa))
+ {
+ cvar_set("g_freezetag_teams", sa);
}
-}
+#ifdef CSQC
+ ATTRIB(FreezeTag, m_modicons, void(vector pos, vector mySize), HUD_Mod_CA);
+#endif
+ENDCLASS(FreezeTag)
+REGISTER_GAMETYPE(FREEZETAG, NEW(FreezeTag));
#define g_freezetag IS_GAMETYPE(FREEZETAG)
-REGISTER_GAMETYPE(_("Keepaway"),ka,g_keepaway,KEEPAWAY,true,"","timelimit=20 pointlimit=30",_("Hold the ball to get points for kills"));
+#ifdef CSQC
+void HUD_Mod_Keepaway(vector pos, vector mySize);
+#endif
+CLASS(Keepaway, Gametype)
+ INIT(Keepaway)
+ {
+ this.gametype_init(this, _("Keepaway"),"ka","g_keepaway",true,"","timelimit=20 pointlimit=30",_("Hold the ball to get points for kills"));
+ }
+ METHOD(Keepaway, m_isAlwaysSupported, bool(Gametype this, int spawnpoints, float diameter))
+ {
+ return true;
+ }
+#ifdef CSQC
+ ATTRIB(Keepaway, m_modicons, void(vector pos, vector mySize), HUD_Mod_Keepaway);
+#endif
+ENDCLASS(Keepaway)
+REGISTER_GAMETYPE(KEEPAWAY, NEW(Keepaway));
-REGISTER_GAMETYPE(_("Invasion"),inv,g_invasion,INVASION,false,"","pointlimit=50 teams=0",_("Survive against waves of monsters"))
-{
- switch (k) {
- case "teams":
- cvar_set("g_invasion_teams", v);
- return true;
+CLASS(Invasion, Gametype)
+ INIT(Invasion)
+ {
+ this.gametype_init(this, _("Invasion"),"inv","g_invasion",false,"","pointlimit=50 teams=0",_("Survive against waves of monsters"));
}
-}
+ METHOD(Invasion, m_parse_mapinfo, bool(string k, string v))
+ {
+ switch (k) {
+ case "teams":
+ cvar_set("g_invasion_teams", v);
+ return true;
+ }
+ return false;
+ }
+ METHOD(Invasion, m_generate_mapinfo, void(Gametype this, string v))
+ {
+ if(v == "invasion_spawnpoint")
+ MapInfo_Map_supportedGametypes |= this.m_flags;
+ }
+ENDCLASS(Invasion)
+REGISTER_GAMETYPE(INVASION, NEW(Invasion));
const int MAPINFO_FEATURE_WEAPONS = 1; // not defined for instagib-only maps
const int MAPINFO_FEATURE_VEHICLES = 2;
float MapInfo_count;
-// info about a map that MapInfo loads
-string MapInfo_Map_bspname;
-string MapInfo_Map_title;
-string MapInfo_Map_titlestring; // either bspname: title or just title, depending on whether bspname is redundant
-string MapInfo_Map_description;
-string MapInfo_Map_author;
-string MapInfo_Map_clientstuff; // not in cache, only for map load
-string MapInfo_Map_fog; // not in cache, only for map load
-int MapInfo_Map_supportedGametypes;
-int MapInfo_Map_supportedFeatures;
-int MapInfo_Map_flags;
-vector MapInfo_Map_mins; // these are '0 0 0' if not supported!
-vector MapInfo_Map_maxs; // these are '0 0 0' if not specified!
-
// load MapInfo_count; generate mapinfo for maps that miss them, and clear the
// cache; you need to call MapInfo_FilterGametype afterwards!
void MapInfo_Enumerate();
// filter the info by game type mask (updates MapInfo_count)
float MapInfo_progress;
-float MapInfo_FilterGametype(float gametype, float features, float pFlagsRequired, float pFlagsForbidden, float pAbortOnGenerate); // 1 on success, 0 on temporary failure (call it again next frame then; use MapInfo_progress as progress indicator)
+float MapInfo_FilterGametype(Gametype gametypeFlags, float features, float pFlagsRequired, float pFlagsForbidden, float pAbortOnGenerate); // 1 on success, 0 on temporary failure (call it again next frame then; use MapInfo_progress as progress indicator)
+float _MapInfo_FilterGametype(int gametypeFlags, float features, float pFlagsRequired, float pFlagsForbidden, float pAbortOnGenerate); // 1 on success, 0 on temporary failure (call it again next frame then; use MapInfo_progress as progress indicator)
void MapInfo_FilterString(string sf); // filter _MapInfo_filtered (created by MapInfo_FilterGametype) with keyword
int MapInfo_CurrentFeatures(); // retrieves currently required features from cvars
-int MapInfo_CurrentGametype(); // retrieves current gametype from cvars
+Gametype MapInfo_CurrentGametype(); // retrieves current gametype from cvars
int MapInfo_ForbiddenFlags(); // retrieves current flags from cvars
int MapInfo_RequiredFlags(); // retrieves current flags from cvars
string MapInfo_BSPName_ByID(float i);
// load info about a map by name into the MapInfo_Map_* globals
-float MapInfo_Get_ByName(string s, float allowGenerate, float gametypeToSet); // 1 on success, 0 on failure, 2 if it autogenerated a mapinfo file
+int MapInfo_Get_ByName(string s, float allowGenerate, Gametype gametypeToSet); // 1 on success, 0 on failure, 2 if it autogenerated a mapinfo file
// look for a map by a prefix, returns the actual map name on success, string_null on failure or ambigous match
string MapInfo_FindName_match; // the name of the map that was found
void MapInfo_LoadMap(string s, float reinit);
// list all maps for the current game type
-string MapInfo_ListAllowedMaps(float type, float pFlagsRequired, float pFlagsForbidden);
+string MapInfo_ListAllowedMaps(Gametype type, float pFlagsRequired, float pFlagsForbidden);
// list all allowed maps (for any game type)
string MapInfo_ListAllAllowedMaps(float pFlagsRequired, float pFlagsForbidden);
// gets a gametype from a string
-string _MapInfo_GetDefaultEx(float t);
-float _MapInfo_GetTeamPlayBool(float t);
-Gametype MapInfo_Type(int t);
-float MapInfo_Type_FromString(string t);
-string MapInfo_Type_Description(float t);
-string MapInfo_Type_ToString(float t);
-string MapInfo_Type_ToText(float t);
-void MapInfo_SwitchGameType(int t);
+string _MapInfo_GetDefaultEx(Gametype t);
+float _MapInfo_GetTeamPlayBool(Gametype t);
+Gametype MapInfo_Type_FromString(string t);
+string MapInfo_Type_Description(Gametype t);
+string MapInfo_Type_ToString(Gametype t);
+string MapInfo_Type_ToText(Gametype t);
+void MapInfo_SwitchGameType(Gametype t);
// to be called from worldspawn to set up cvars
void MapInfo_LoadMapSettings(string s);
-float MapInfo_LoadedGametype; // game type that was active during map load
+Gametype MapInfo_LoadedGametype; // game type that was active during map load
void MapInfo_Cache_Destroy(); // disable caching
void MapInfo_Cache_Create(); // enable caching
#define MAPINFO_SETTEMP_ACL_USER cvar_string("g_mapinfo_settemp_acl")
#define MAPINFO_SETTEMP_ACL_SYSTEM "-g_mapinfo_* -rcon_* -_* -g_ban* +*"
-#endif
void minigame_autoclean_entity(entity e)
{
- LOG_DEBUG("CL Auto-cleaned: ",ftos(etof(e)), " (",e.classname,")\n");
- remove(e);
+ LOG_DEBUG("CL Auto-cleaned: ",ftos(etof(e)), " (",e.classname,")");
+ delete(e);
}
void HUD_MinigameMenu_CurrentButton();
if ( !minigame.descriptor || minigame.classname != "minigame" )
{
- LOG_TRACE("Trying to activate unregistered minigame ",minigame.netname," in client\n");
+ LOG_TRACE("Trying to activate unregistered minigame ",minigame.netname," in client");
return;
}
this.owner = find(this.owner,netname,owner_name);
while ( this.owner && this.owner.classname != "minigame" );
if ( !this.owner )
- LOG_TRACE("Got a minigame entity without a minigame!\n");
+ LOG_TRACE("Got a minigame entity without a minigame!");
}
NET_HANDLE(ENT_CLIENT_MINIGAME, bool isnew)
{
this.entremove = minigame_entremove;
this.descriptor = minigame_get_descriptor(ReadString_Raw());
if ( !this.descriptor )
- LOG_TRACE("Got a minigame without a client-side descriptor!\n");
+ LOG_TRACE("Got a minigame without a client-side descriptor!");
else
this.minigame_event = this.descriptor.minigame_event;
}
minigame_read_owner(this);
float ent = ReadLong();
this.minigame_playerslot = ent;
- LOG_DEBUG("Player: ",entcs_GetName(ent-1),"\n");
+ LOG_DEBUG("Player: ",entcs_GetName(ent-1));
activate = (ent == player_localnum+1 && this.owner && this.owner != active_minigame);
{
LOG_DEBUG("CL Reading entity: ",ftos(etof(this)),
" classname:",this.classname," enttype:",ftos(this.enttype) );
- LOG_DEBUG(" sf:",ftos(sf)," netname:",this.netname,"\n\n");
+ LOG_DEBUG(" sf:",ftos(sf)," netname:",this.netname);
}
return true;
}
-#ifndef CL_MINIGAMES_H
-#define CL_MINIGAMES_H
+#pragma once
// Get a square in the center of the avaliable area
// \note macro to pass by reference pos and mySize
this.minigame_event = name##_client_event; \
} \
REGISTER_INIT(MINIGAME_##name)
-
-#endif
if ( HUD_MinigameMenu_activeitem == e )
HUD_MinigameMenu_activeitem = NULL;
- remove(e);
+ delete(e);
}
// Minigame menu options: create entry
if ( e.flags & 2 )
HUD_MinigameMenu_Click(e);
this.list_next = e.list_next;
- remove(e);
+ delete(e);
}
if ( this.list_next )
this.list_next.list_prev = this;
for ( e = HUD_MinigameMenu_entries; e != NULL; e = p )
{
p = e.list_next;
- remove(e);
+ delete(e);
}
HUD_MinigameMenu_entries = NULL;
HUD_MinigameMenu_last_entry = NULL;
-#ifndef CL_MINIGAMES_HUD_H
-#define CL_MINIGAMES_HUD_H
+#pragma once
float HUD_Minigame_InputEvent(float bInputType, float nPrimary, float nSecondary);
void HUD_Minigame_Mouse();
-
-#endif
return; // how?!
if(piece.netname) { strunzone(piece.netname); }
- remove(piece);
+ delete(piece);
minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
return;
}
if(targ && thetype == targ.bd_tiletype)
{
if(targ.netname) { strunzone(targ.netname); }
- remove(targ);
+ delete(targ);
}
else if(piece && thetype == piece.bd_tiletype)
{
if(piece.netname) { strunzone(piece.netname); }
- remove(piece);
+ delete(piece);
}
else return;
if(e.classname == "minigame_board_piece")
{
if(e.netname) { strunzone(e.netname); }
- remove(e);
+ delete(e);
}
bd_load_level(minigame);
if(e.classname == "minigame_board_piece")
{
if(e.netname) { strunzone(e.netname); }
- remove(e);
+ delete(e);
}
if(minigame.bd_nextlevel) { strunzone(minigame.bd_nextlevel); }
if(e.classname == "minigame_board_piece")
{
if(e.netname) { strunzone(e.netname); }
- remove(e);
+ delete(e);
}
return false;
}
strunzone(e.netname);
strunzone(e.nmm_tile_hmill);
strunzone(e.nmm_tile_vmill);
- remove(e);
+ delete(e);
}
}
minigame.SendFlags |= MINIG_SF_UPDATE;
}
else
- LOG_TRACE("Invalid move: ",...(2,string),"\n");
+ LOG_TRACE("Invalid move: ", ...(2, string));
return 1;
}
}
paddle.realowner.classname == "pong_ai" )
{
minigame.pong_paddles[i] = NULL;
- remove(paddle.realowner);
- remove(paddle);
+ delete(paddle.realowner);
+ delete(paddle);
return true;
}
}
if(existing)
{
if(existing.netname) { strunzone(existing.netname); }
- remove(existing);
+ delete(existing);
}
entity piece = msle_spawn(minigame,"minigame_board_piece");
entity e = NULL;
while ( ( e = findentity(e,owner,minigame) ) )
if ( e.classname == "minigame_board_piece" )
- remove(e);
+ delete(e);
minigame.pp_team1_score = 0;
minigame.pp_team2_score = 0;
if(e.classname == "minigame_board_piece")
{
if(e.netname) { strunzone(e.netname); }
- remove(e);
+ delete(e);
}
return false;
}
return false;
if(middle.netname) { strunzone(middle.netname); }
- remove(middle);
+ delete(middle);
if(piece.netname) { strunzone(piece.netname); }
piece.netname = strzone(pos);
if(e.classname == "minigame_board_piece")
{
if(e.netname) { strunzone(e.netname); }
- remove(e);
+ delete(e);
}
return false;
}
if ( e.classname == "minigame_board_piece" && e.cnt && e.team == pteam )
{
if(e.netname) { strunzone(e.netname); }
- remove(e);
+ delete(e);
}
if(minigame.snake_lives[pteam] <= 0)
if(ate_mouse)
{
if(hit.netname) { strunzone(hit.netname); }
- remove(hit);
+ delete(hit);
snake_new_mouse(minigame);
}
if(e.classname == "minigame_board_piece")
{
if(e.netname) { strunzone(e.netname); }
- remove(e);
+ delete(e);
}
return false;
}
entity e = NULL;
while ( ( e = findentity(e,owner,minigame) ) )
if ( e.classname == "minigame_board_piece" )
- remove(e);
+ delete(e);
}
}
if(e.classname == "minigame_board_piece")
{
if(e.netname) { strunzone(e.netname); }
- remove(e);
+ delete(e);
}
return false;
}
f <<= 1;
}
- LOG_TRACE(sprintf("TTT AI: selected %x from %x\n",
+ LOG_TRACE(sprintf("TTT AI: selected %x from %x",
RandomSelection_chosen_float, piecemask) );
return RandomSelection_chosen_float;
}
r |= ttt_ai_1of3(piecemask,TTT_AI_POSFLAG_A3,TTT_AI_POSFLAG_B3,TTT_AI_POSFLAG_C3);
r |= ttt_ai_1of3(piecemask,TTT_AI_POSFLAG_A1,TTT_AI_POSFLAG_B2,TTT_AI_POSFLAG_C3);
r |= ttt_ai_1of3(piecemask,TTT_AI_POSFLAG_A3,TTT_AI_POSFLAG_B2,TTT_AI_POSFLAG_C1);
- LOG_TRACE(sprintf("TTT AI: possible 3 in a rows in %x: %x (%x)\n",piecemask,r, r&piecemask_free));
+ LOG_TRACE(sprintf("TTT AI: possible 3 in a rows in %x: %x (%x)",piecemask,r, r&piecemask_free));
r &= piecemask_free;
return ttt_ai_random(r);
}
{
int move = 0;
- LOG_TRACE("TTT AI: checking winning move\n");
+ LOG_TRACE("TTT AI: checking winning move");
if (( move = ttt_ai_block3(piecemask_self,piecemask_free) ))
return ttt_ai_piece_flag2pos(move); // place winning move
- LOG_TRACE("TTT AI: checking opponent's winning move\n");
+ LOG_TRACE("TTT AI: checking opponent's winning move");
if (( move = ttt_ai_block3(piecemask_opponent,piecemask_free) ))
return ttt_ai_piece_flag2pos(move); // block opponent
- LOG_TRACE("TTT AI: random move\n");
+ LOG_TRACE("TTT AI: random move");
return ttt_ai_piece_flag2pos(ttt_ai_random(piecemask_free));
}
}
// TODO multiple AI difficulties
- LOG_TRACE(sprintf("TTT AI: self: %x opponent: %x free: %x\n",
+ LOG_TRACE(sprintf("TTT AI: self: %x opponent: %x free: %x",
piecemask_self, piecemask_opponent, piecemask_free));
pos = ttt_ai_choose_simple(piecemask_self, piecemask_opponent, piecemask_free);
- LOG_TRACE("TTT AI: chosen move: ",pos,"\n\n");
+ LOG_TRACE("TTT AI: chosen move: ", pos);
if ( !pos )
- LOG_TRACE("Tic Tac Toe AI has derped!\n");
+ LOG_TRACE("Tic Tac Toe AI has derped!");
else
ttt_move(minigame,aiplayer,pos);
}
-#ifndef MINIGAMES_H
-#define MINIGAMES_H
+#pragma once
// previous node in a doubly linked list
.entity list_prev;
int msle_id(string class_name);
string msle_classname(int id);
-
-#endif
GameLogEcho(strcat(":minigame:part:",minigame_session.netname,":",
ftos(etof(player)),":",player.netname));
minigame_session.minigame_players = p.list_next;
- remove ( p );
+ delete ( p );
player_clear_minigame(player);
}
else
GameLogEcho(strcat(":minigame:part:",minigame_session.netname,":",
ftos(etof(player)),":",player.netname));
p.list_next = e.list_next;
- remove(e);
+ delete(e);
player_clear_minigame(player);
return;
}
minigame_resend(minigame_session);
}
- else { remove(player_pointer); }
+ else { delete(player_pointer); }
GameLogEcho(strcat(":minigame:join",(mgteam?"":"fail"),":",minigame_session.netname,":",
ftos(etof(player)),":",player.netname));
GameLogEcho(strcat(":minigame:start:",minig.netname));
if ( ! minigame_addplayer(minig,player) )
{
- LOG_TRACE("Minigame ",minig.netname," rejected the first player join!\n");
+ LOG_TRACE("Minigame ",minig.netname," rejected the first player join!");
end_minigame(minig);
return NULL;
}
while( (e = findentity(e, owner, minigame_session)) )
if ( e.minigame_autoclean )
{
- LOG_TRACE("SV Auto-cleaned: ",ftos(etof(e)), " (",e.classname,")\n");
- remove(e);
+ LOG_TRACE("SV Auto-cleaned: ",ftos(etof(e)), " (",e.classname,")");
+ delete(e);
}
entity p;
{
p = e.list_next;
player_clear_minigame(e.minigame_players);
- remove(e);
+ delete(e);
}
strunzone(minigame_session.netname);
- remove(minigame_session);
+ delete(minigame_session);
}
void end_minigames()
-#ifndef SV_MINIGAMES_H
-#define SV_MINIGAMES_H
+#pragma once
/// Create a new minigame session
/// \return minigame session entity
this.minigame_event = name##_server_event; \
} \
REGISTER_INIT(MINIGAME_##name)
-
-#endif
-#ifndef MODELS_ALL_H
-#define MODELS_ALL_H
+#pragma once
#include "model.qh"
MODEL(Null, "null");
#include "all.inc"
-
-#endif
-#ifndef MODEL_H
-#define MODEL_H
+#pragma once
#define setmodel(e, m) _setmodel((e), (m).model_str())
CLASS(Model, Object)
- ATTRIB(Model, m_id, int, 0)
- ATTRIB(Model, model_str, string(), func_null)
+ ATTRIB(Model, m_id, int, 0);
+ ATTRIB(Model, model_str, string());
CONSTRUCTOR(Model, string() path)
{
CONSTRUCT(Model);
TC(Model, this);
string s = this.model_str();
if (s != "" && s != "null" && !fexists(s)) {
- LOG_WARNINGF("Missing model: \"%s\"\n", s);
+ LOG_WARNF("Missing model: \"%s\"", s);
return;
}
- profile(sprintf("precache_model(\"%s\")\n", s));
+ profile(sprintf("precache_model(\"%s\")", s));
precache_model(s);
}
ENDCLASS(Model)
-
-#endif
-#ifndef MONSTERS_ALL_H
-#define MONSTERS_ALL_H
+#pragma once
#include "monster.qh"
#include "monster/_mod.inc"
-
-#endif
-#ifndef MONSTER_H
-#define MONSTER_H
+#pragma once
#ifdef SVQC
#include "sv_monsters.qh"
#include <server/g_damage.qh>
-#include <server/bot/bot.qh>
+#include <server/bot/api.qh>
#include <server/weapons/common.qh>
#include <server/weapons/tracing.qh>
#include <server/weapons/weaponsystem.qh>
.vector anim_spawn;
CLASS(Monster, Object)
- ATTRIB(Monster, monsterid, int, 0)
+ ATTRIB(Monster, monsterid, int, 0);
/** attributes */
- ATTRIB(Monster, spawnflags, int, 0)
+ ATTRIB(Monster, spawnflags, int, 0);
/** human readable name */
- ATTRIB(Monster, monster_name, string, "Monster")
+ ATTRIB(Monster, monster_name, string, "Monster");
/** short name */
- ATTRIB(Monster, netname, string, "")
+ ATTRIB(Monster, netname, string, "");
/** model */
- ATTRIB(Monster, m_model, entity, NULL)
+ ATTRIB(Monster, m_model, entity);
/** hitbox size */
- ATTRIB(Monster, mins, vector, '-0 -0 -0')
+ ATTRIB(Monster, mins, vector, '-0 -0 -0');
/** hitbox size */
- ATTRIB(Monster, maxs, vector, '0 0 0')
+ ATTRIB(Monster, maxs, vector, '0 0 0');
/** (SERVER) setup monster data */
METHOD(Monster, mr_setup, bool(Monster this, entity actor)) { TC(Monster, this); return false; }
METHOD(Monster, mr_anim, bool(Monster this, entity actor)) { TC(Monster, this); return false; }
ENDCLASS(Monster)
-
-#endif
if (!IS_PLAYER(actor) || weapon_prepareattack(thiswep, actor, weaponentity, false, 0.2)) {
if (!actor.target_range) actor.target_range = autocvar_g_monsters_target_range;
actor.enemy = Monster_FindTarget(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, SND_MageSpike_FIRE, CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_MageSpike_FIRE, CH_WEAPON_B, 0);
if (!IS_PLAYER(actor)) w_shotdir = normalize((actor.enemy.origin + '0 0 10') - actor.origin);
M_Mage_Attack_Spike(actor, w_shotdir);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, w_ready);
Send_Effect(EFFECT_EXPLOSION_SMALL, this.origin, '0 0 0', 1);
RadiusDamage (this, this.realowner, (autocvar_g_monster_mage_attack_spike_damage), (autocvar_g_monster_mage_attack_spike_damage) * 0.5, (autocvar_g_monster_mage_attack_spike_radius), NULL, NULL, 0, DEATH_MONSTER_MAGE.m_id, directhitentity);
- remove (this);
+ delete (this);
}
void M_Mage_Attack_Spike_Touch(entity this, entity toucher)
missile.solid = SOLID_BBOX;
set_movetype(missile, MOVETYPE_FLYMISSILE);
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
setorigin(missile, this.origin + v_forward * 14 + '0 0 30' + v_right * -14);
setsize(missile, '0 0 0', '0 0 0');
missile.velocity = dir * 400;
if(this.move_movetype == MOVETYPE_NONE)
this.velocity = this.oldvelocity;
- RadiusDamage (this, this.realowner, (autocvar_g_monster_shambler_attack_lightning_damage), (autocvar_g_monster_shambler_attack_lightning_damage), (autocvar_g_monster_shambler_attack_lightning_radius),
+ RadiusDamage (this, this.realowner, (autocvar_g_monster_shambler_attack_lightning_damage), (autocvar_g_monster_shambler_attack_lightning_damage), (autocvar_g_monster_shambler_attack_lightning_radius),
NULL, NULL, (autocvar_g_monster_shambler_attack_lightning_force), this.projectiledeathtype, directhitentity);
FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_monster_shambler_attack_lightning_radius_zap, it != this.realowner && it.takedamage,
gren.angles = vectoangles (gren.velocity);
gren.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, gren);
CSQCProjectile(gren, true, PROJECTILE_SHAMBLER_LIGHTNING, true);
}
actor.anim_finished = time + 1;
}
if (isPlayer) actor.enemy = Monster_FindTarget(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, SND_SpiderAttack_FIRE, CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_SpiderAttack_FIRE, CH_WEAPON_B, 0);
if (!isPlayer) w_shotdir = normalize((actor.enemy.origin + '0 0 10') - actor.origin);
M_Spider_Attack_Web(actor);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, w_ready);
it.spider_slowness = time + (autocvar_g_monster_spider_attack_web_damagetime);
});
- remove(this);
+ delete(this);
}
}
proj.health = 500;
proj.event_damage = func_null;
proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.damagedbycontents = true;
proj.bouncefactor = 0.3;
TC(WyvernAttack, thiswep);
if (fire & 1)
if (time > actor.attack_finished_single[0] || weapon_prepareattack(thiswep, actor, weaponentity, false, 1.2)) {
- if (IS_PLAYER(actor)) W_SetupShot_Dir(actor, v_forward, false, 0, SND_WyvernAttack_FIRE, CH_WEAPON_B, 0);
+ if (IS_PLAYER(actor)) W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_WyvernAttack_FIRE, CH_WEAPON_B, 0);
if (IS_MONSTER(actor)) {
actor.attack_finished_single[0] = time + 1.2;
actor.anim_finished = time + 1.2;
setsize(missile, '-6 -6 -6', '6 6 6');
setorigin(missile, actor.origin + actor.view_ofs + v_forward * 14);
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
missile.velocity = w_shotdir * (autocvar_g_monster_wyvern_attack_fireball_speed);
missile.avelocity = '300 300 300';
missile.nextthink = time + 5;
Fire_AddDamage(it, own, 5 * MONSTER_SKILLMOD(own), autocvar_g_monster_wyvern_attack_fireball_damagetime, this.projectiledeathtype);
});
- remove(this);
+ delete(this);
}
void M_Wyvern_Attack_Fireball_Touch(entity this, entity toucher)
-#ifndef SPAWN_H
-#define SPAWN_H
+#pragma once
entity spawnmonster (string monster, float monster_id, entity spawnedby, entity own, vector orig, float respwn, float invincible, float moveflag);
-#endif
{
if(tokenize_console(s) != 3)
{
- LOG_TRACE("Invalid sound info line: ", s, "\n");
+ LOG_TRACE("Invalid sound info line: ", s);
continue;
}
PrecacheGlobalSound(strcat(argv(1), " ", argv(2)));
fh = fopen(f, FILE_READ);
if(fh < 0)
{
- LOG_TRACE("Monster sound file not found: ", f, "\n");
+ LOG_TRACE("Monster sound file not found: ", f);
return false;
}
while((s = fgets(fh)))
//this.angles = vectoangles(this.velocity);
}
+.entity draggedby;
+
void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed)
{
if(this.target2) { this.goalentity = find(NULL, targetname, this.target2); }
if(IS_CLIENT(this))
return; // don't remove it?
- .entity weaponentity = weaponentities[0];
if(!this) { return; }
if(!MUTATOR_CALLHOOK(MonsterRemove, this))
Send_Effect(EFFECT_ITEM_PICKUP, this.origin, '0 0 0', 1);
- if(this.(weaponentity)) { remove(this.(weaponentity)); }
- if(this.iceblock) { remove(this.iceblock); }
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ if(this.(weaponentity))
+ delete(this.(weaponentity));
+ }
+ if(this.iceblock) { delete(this.iceblock); }
WaypointSprite_Kill(this.sprite);
- remove(this);
+ delete(this);
}
void Monster_Dead_Think(entity this)
-#ifndef SV_MONSTERS_H
-#define SV_MONSTERS_H
+#pragma once
// stats networking
.int stat_monsters_killed;
#undef _MSOUND
float GetMonsterSoundSampleField_notFound;
-
-#endif
#include "mutator/damagetext/module.inc"
#include "mutator/dodging/module.inc"
#include "mutator/doublejump/module.inc"
+#include "mutator/globalforces/module.inc"
#include "mutator/hook/module.inc"
#include "mutator/instagib/module.inc"
#include "mutator/invincibleproj/module.inc"
* return false;
* }
*/
- ATTRIB(Callback, cbc_func, bool(), func_null)
+ ATTRIB(Callback, cbc_func, bool());
CONSTRUCTOR(Callback, bool() func) {
CONSTRUCT(Callback);
this.cbc_func = func;
*/
CLASS(CallbackChain, Object)
CLASS(CallbackNode, Object)
- ATTRIB(CallbackNode, cbc, Callback, NULL)
- ATTRIB(CallbackNode, cbc_next, CallbackNode, NULL)
- ATTRIB(CallbackNode, cbc_order, int, 0)
+ ATTRIB(CallbackNode, cbc, Callback);
+ ATTRIB(CallbackNode, cbc_next, CallbackNode);
+ ATTRIB(CallbackNode, cbc_order, int, 0);
CONSTRUCTOR(CallbackNode, Callback it, int order) {
CONSTRUCT(CallbackNode);
this.cbc = it;
}
ENDCLASS(CallbackNode)
- ATTRIB(CallbackChain, cbc_next, CallbackNode, NULL)
- ATTRIB(CallbackChain, cbc_order, int, 0)
+ ATTRIB(CallbackChain, cbc_next, CallbackNode);
+ ATTRIB(CallbackChain, cbc_order, int, 0);
CONSTRUCTOR(CallbackChain, string _name) {
CONSTRUCT(CallbackChain);
this.netname = _name;
USING(mutatorfunc_t, bool(int));
CLASS(Mutator, Object)
- ATTRIB(Mutator, m_id, int, 0)
- ATTRIB(Mutator, m_name, string, string_null)
- ATTRIB(Mutator, mutatorfunc, mutatorfunc_t, func_null)
- ATTRIB(Mutator, mutatorcheck, bool(), func_null)
+ ATTRIB(Mutator, m_id, int, 0);
+ ATTRIB(Mutator, m_name, string);
+ ATTRIB(Mutator, mutatorfunc, mutatorfunc_t);
+ ATTRIB(Mutator, mutatorcheck, bool());
CONSTRUCTOR(Mutator, string _name, mutatorfunc_t func) {
CONSTRUCT(Mutator);
this.m_name = _name;
WITH(bool, mutator_log, true, LAMBDA(
FOREACH(Mutators, it.registered_id == s, { Mutator_Add(it); ++added; });
));
- if (added > 1) LOG_WARNINGF("Added more than one mutator for %s\n", s);
+ if (added > 1) LOG_WARNF("Added more than one mutator for %s", s);
}
}
#endif
mutatorfunc_t func = mut.mutatorfunc;
if (!func(MUTATOR_ADDING)) {
// good
- if (mutator_log) LOG_TRACEF("Mutator: added %s\n", mut.m_name);
+ if (mutator_log) LOG_TRACEF("Mutator: added %s", mut.m_name);
#ifdef SVQC
Net_LinkEntity(mut, false, 0, Mutator_SendEntity);
#endif
// baaaaad
error("Mutator_Remove: removing mutator failed");
}
- if (mutator_log) LOG_TRACEF("Mutator: removed %s\n", mut.m_name);
+ if (mutator_log) LOG_TRACEF("Mutator: removed %s", mut.m_name);
#ifdef SVQC
Net_UnlinkEntity(mut);
#endif
*/
#define EV_PlayerPhysics(i, o) \
/** player */ i(entity, MUTATOR_ARGV_0_entity) \
+ /** ticrate*/ i(float, MUTATOR_ARGV_1_float) \
/**/
MUTATOR_HOOKABLE(PlayerPhysics, EV_PlayerPhysics);
#define EV_PM_Physics(i, o) \
/** player */ i(entity, MUTATOR_ARGV_0_entity) \
/** maxspeed_mod */ i(float, MUTATOR_ARGV_1_float) \
+ /** tick rate */ i(float, MUTATOR_ARGV_2_float) \
/**/
MUTATOR_HOOKABLE(PM_Physics, EV_PM_Physics);
#include <common/items/item/pickup.qh>
CLASS(Buff, Pickup)
/** bit index */
- ATTRIB(Buff, m_itemid, int, 0)
- ATTRIB(Buff, m_name, string, "buff")
- ATTRIB(Buff, m_color, vector, '1 1 1')
- ATTRIB(Buff, m_prettyName, string, "Buff")
- ATTRIB(Buff, m_skin, int, 0)
- ATTRIB(Buff, m_sprite, string, "")
+ ATTRIB(Buff, m_itemid, int, 0);
+ ATTRIB(Buff, m_name, string, "buff");
+ ATTRIB(Buff, m_color, vector, '1 1 1');
+ ATTRIB(Buff, m_prettyName, string, "Buff");
+ ATTRIB(Buff, m_skin, int, 0);
+ ATTRIB(Buff, m_sprite, string, "");
METHOD(Buff, display, void(entity this, void(string name, string icon) returns)) {
returns(this.m_prettyName, sprintf("/gfx/hud/%s/buff_%s", cvar_string("menu_skin"), this.m_name));
}
void buff_Init(entity this)
{
- if(!cvar("g_buffs")) { remove(this); return; }
+ if(!cvar("g_buffs")) { delete(this); return; }
if(!teamplay && this.team) { this.team = 0; }
if(this.enemy)
Damage(this.enemy, this.owner, this.owner, this.dmg, DEATH_BUFF.m_id, this.enemy.origin, '0 0 0');
- remove(this);
+ delete(this);
return;
}
MUTATOR_HOOKFUNCTION(buffs, PlayerDies)
{
entity frag_target = M_ARGV(2, entity);
-
+
if(frag_target.buffs)
{
int buffid = buff_FirstFromFlags(frag_target.buffs).m_id;
if(frag_target.buff_model)
{
- remove(frag_target.buff_model);
+ delete(frag_target.buff_model);
frag_target.buff_model = NULL;
}
}
{
if(player.buff_model)
{
- remove(player.buff_model);
+ delete(player.buff_model);
player.buff_model = NULL;
}
}
else
{
- remove(player.buff_model);
+ delete(player.buff_model);
player.buff_model = NULL;
player.effects &= ~(EF_NOSHADOW);
#endif
-void RaceCarPhysics(entity this)
+void RaceCarPhysics(entity this, float dt)
{
// using this move type for "big rigs"
// the engine does not push the entity!
{
if (myspeed > 0)
{
- myspeed = max(0, myspeed - PHYS_INPUT_TIMELENGTH * (PHYS_BUGRIGS_FRICTION_FLOOR(this) - PHYS_BUGRIGS_FRICTION_BRAKE(this) * accel));
+ myspeed = max(0, myspeed - dt * (PHYS_BUGRIGS_FRICTION_FLOOR(this) - PHYS_BUGRIGS_FRICTION_BRAKE(this) * accel));
}
else
{
if (!PHYS_BUGRIGS_REVERSE_SPEEDING(this))
- myspeed = min(0, myspeed + PHYS_INPUT_TIMELENGTH * PHYS_BUGRIGS_FRICTION_FLOOR(this));
+ myspeed = min(0, myspeed + dt * PHYS_BUGRIGS_FRICTION_FLOOR(this));
}
}
else
{
if (myspeed >= 0)
{
- myspeed = max(0, myspeed - PHYS_INPUT_TIMELENGTH * PHYS_BUGRIGS_FRICTION_FLOOR(this));
+ myspeed = max(0, myspeed - dt * PHYS_BUGRIGS_FRICTION_FLOOR(this));
}
else
{
if (PHYS_BUGRIGS_REVERSE_STOPPING(this))
myspeed = 0;
else
- myspeed = min(0, myspeed + PHYS_INPUT_TIMELENGTH * (PHYS_BUGRIGS_FRICTION_FLOOR(this) + PHYS_BUGRIGS_FRICTION_BRAKE(this) * accel));
+ myspeed = min(0, myspeed + dt * (PHYS_BUGRIGS_FRICTION_FLOOR(this) + PHYS_BUGRIGS_FRICTION_BRAKE(this) * accel));
}
}
// terminal velocity = velocity at which 50 == accelfactor, that is, 1549 units/sec
//MAXIMA: friction(v) := PHYS_BUGRIGS_FRICTION_FLOOR(this);
- this.angles_y += steer * PHYS_INPUT_TIMELENGTH * steerfactor; // apply steering
+ this.angles_y += steer * dt * steerfactor; // apply steering
makevectors(this.angles); // new forward direction!
- myspeed += accel * accelfactor * PHYS_INPUT_TIMELENGTH;
+ myspeed += accel * accelfactor * dt;
rigvel = myspeed * v_forward + '0 0 1' * upspeed;
}
// responsiveness factor for steering and acceleration
float f = 1 / (1 + pow(max(0, myspeed / PHYS_BUGRIGS_SPEED_REF(this)), PHYS_BUGRIGS_SPEED_POW(this)));
float steerfactor = -myspeed * f;
- this.angles_y += steer * PHYS_INPUT_TIMELENGTH * steerfactor; // apply steering
+ this.angles_y += steer * dt * steerfactor; // apply steering
rigvel = this.velocity;
makevectors(this.angles); // new forward direction!
}
- rigvel *= max(0, 1 - vlen(rigvel) * PHYS_BUGRIGS_FRICTION_AIR(this) * PHYS_INPUT_TIMELENGTH);
+ rigvel *= max(0, 1 - vlen(rigvel) * PHYS_BUGRIGS_FRICTION_AIR(this) * dt);
//MAXIMA: airfriction(v) := v * v * PHYS_BUGRIGS_FRICTION_AIR(this);
//MAXIMA: total_acceleration(v) := accel(v) - friction(v) - airfriction(v);
//MAXIMA: solve(total_acceleration(v) = 0, v);
vector rigvel_xy, neworigin, up;
float mt;
- rigvel_z -= PHYS_INPUT_TIMELENGTH * PHYS_GRAVITY(this); // 4x gravity plays better
+ rigvel_z -= dt * PHYS_GRAVITY(this); // 4x gravity plays better
rigvel_xy = vec2(rigvel);
if (PHYS_BUGRIGS_CAR_JUMPING(this))
// BUG RIGS: align the move to the surface instead of doing collision testing
// can we move?
- tracebox(trace_endpos, this.mins, this.maxs, trace_endpos + rigvel_xy * PHYS_INPUT_TIMELENGTH, mt, this);
+ tracebox(trace_endpos, this.mins, this.maxs, trace_endpos + rigvel_xy * dt, mt, this);
// align to surface
- tracebox(trace_endpos, this.mins, this.maxs, trace_endpos - up + '0 0 1' * rigvel_z * PHYS_INPUT_TIMELENGTH, mt, this);
+ tracebox(trace_endpos, this.mins, this.maxs, trace_endpos - up + '0 0 1' * rigvel_z * dt, mt, this);
if (trace_fraction < 0.5)
{
UNSET_ONGROUND(this);
}
- this.velocity = (neworigin - this.origin) * (1.0 / PHYS_INPUT_TIMELENGTH);
+ this.velocity = (neworigin - this.origin) * (1.0 / dt);
set_movetype(this, MOVETYPE_NOCLIP);
}
else
{
- rigvel_z -= PHYS_INPUT_TIMELENGTH * PHYS_GRAVITY(this); // 4x gravity plays better
+ rigvel_z -= dt * PHYS_GRAVITY(this); // 4x gravity plays better
this.velocity = rigvel;
set_movetype(this, MOVETYPE_FLY);
}
// smooth the angles
vector vf1, vu1, smoothangles;
makevectors(this.angles);
- float f = bound(0, PHYS_INPUT_TIMELENGTH * PHYS_BUGRIGS_ANGLE_SMOOTHING(this), 1);
+ float f = bound(0, dt * PHYS_BUGRIGS_ANGLE_SMOOTHING(this), 1);
if (f == 0)
f = 1;
vf1 = v_forward * f;
MUTATOR_HOOKFUNCTION(bugrigs, PM_Physics)
{
entity player = M_ARGV(0, entity);
+ float dt = M_ARGV(2, float);
if(!PHYS_BUGRIGS(player) || !IS_PLAYER(player)) { return; }
player.angles = player.bugrigs_prevangles;
#endif
- RaceCarPhysics(player);
+ RaceCarPhysics(player, dt);
return true;
}
MUTATOR_HOOKFUNCTION(campcheck, PlayerDies)
{
entity frag_target = M_ARGV(2, entity);
-
+
Kill_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CPID_CAMPCHECK);
}
MUTATOR_HOOKFUNCTION(campcheck, BuildMutatorsString)
{
- M_ARGV(0, string) = strcat(M_ARGV(0, string), ":CampCheck");;
+ M_ARGV(0, string) = strcat(M_ARGV(0, string), ":CampCheck");
}
#endif
#ifdef CSQC
CLASS(DamageText, Object)
- ATTRIB(DamageText, m_color, vector, autocvar_cl_damagetext_color)
- ATTRIB(DamageText, m_color_friendlyfire, vector, autocvar_cl_damagetext_friendlyfire_color)
- ATTRIB(DamageText, m_size, float, autocvar_cl_damagetext_size)
- ATTRIB(DamageText, alpha, float, autocvar_cl_damagetext_alpha_start)
- ATTRIB(DamageText, fade_rate, float, 1 / autocvar_cl_damagetext_alpha_lifetime)
- ATTRIB(DamageText, velocity, vector, autocvar_cl_damagetext_velocity)
- ATTRIB(DamageText, m_group, int, 0)
- ATTRIB(DamageText, m_friendlyfire, bool, false)
- ATTRIB(DamageText, m_damage, int, 0)
- ATTRIB(DamageText, m_armordamage, int, 0)
- ATTRIB(DamageText, m_deathtype, int, 0)
- ATTRIB(DamageText, time_prev, float, time)
+ ATTRIB(DamageText, m_color, vector, autocvar_cl_damagetext_color);
+ ATTRIB(DamageText, m_color_friendlyfire, vector, autocvar_cl_damagetext_friendlyfire_color);
+ ATTRIB(DamageText, m_size, float, autocvar_cl_damagetext_size);
+ ATTRIB(DamageText, alpha, float, autocvar_cl_damagetext_alpha_start);
+ ATTRIB(DamageText, fade_rate, float, 1 / autocvar_cl_damagetext_alpha_lifetime);
+ ATTRIB(DamageText, velocity, vector, autocvar_cl_damagetext_velocity);
+ ATTRIB(DamageText, m_group, int, 0);
+ ATTRIB(DamageText, m_friendlyfire, bool, false);
+ ATTRIB(DamageText, m_damage, int, 0);
+ ATTRIB(DamageText, m_armordamage, int, 0);
+ ATTRIB(DamageText, m_deathtype, int, 0);
+ ATTRIB(DamageText, time_prev, float, time);
void DamageText_draw2d(DamageText this) {
float dt = time - this.time_prev;
this.time_prev = time;
setorigin(this, this.origin + dt * this.velocity);
this.alpha -= dt * this.fade_rate;
- if (this.alpha < 0) remove(this);
+ if (this.alpha < 0) delete(this);
vector pos = project_3d_to_2d(this.origin) + autocvar_cl_damagetext_offset;
if (pos.z >= 0 && this.m_size > 0) {
pos.z = 0;
drawcolorcodedstring2_builtin(pos, s, this.m_size * '1 1 0', rgb, this.alpha, DRAWFLAG_NORMAL);
}
}
- ATTRIB(DamageText, draw2d, void(DamageText), DamageText_draw2d)
+ ATTRIB(DamageText, draw2d, void(DamageText), DamageText_draw2d);
void DamageText_update(DamageText this, vector _origin, int _health, int _armor, int _deathtype) {
this.m_damage = _health;
CLASS(XonoticDamageTextSettings, XonoticTab)
#include <menu/gamesettings.qh>
REGISTER_SETTINGS(damagetext, NEW(XonoticDamageTextSettings));
- ATTRIB(XonoticDamageTextSettings, title, string, _("Damage text"))
- ATTRIB(XonoticDamageTextSettings, intendedWidth, float, 0.9)
- ATTRIB(XonoticDamageTextSettings, rows, float, 15.5)
- ATTRIB(XonoticDamageTextSettings, columns, float, 5)
+ ATTRIB(XonoticDamageTextSettings, title, string, _("Damage text"));
+ ATTRIB(XonoticDamageTextSettings, intendedWidth, float, 0.9);
+ ATTRIB(XonoticDamageTextSettings, rows, float, 15.5);
+ ATTRIB(XonoticDamageTextSettings, columns, float, 5);
INIT(XonoticDamageTextSettings) { this.configureDialog(this); }
METHOD(XonoticDamageTextSettings, showNotify, void(entity this)) { loadAllCvars(this); }
METHOD(XonoticDamageTextSettings, fill, void(entity this))
--- /dev/null
+// generated file; do not modify
+#include <common/mutators/mutator/globalforces/globalforces.qc>
--- /dev/null
+// generated file; do not modify
+#include <common/mutators/mutator/globalforces/globalforces.qh>
--- /dev/null
+#ifdef IMPLEMENTATION
+
+AUTOCVAR(g_globalforces, float, false, "Global forces: knockback affects everyone");
+AUTOCVAR(g_globalforces_noself, bool, true, "Global forces: ignore self damage");
+AUTOCVAR(g_globalforces_self, float, 1, "Global forces: knockback self scale");
+AUTOCVAR(g_globalforces_range, float, 1000, "Global forces: max range of effect");
+REGISTER_MUTATOR(mutator_globalforces, autocvar_g_globalforces);
+
+MUTATOR_HOOKFUNCTION(mutator_globalforces, BuildMutatorsString) {
+ M_ARGV(0, string) = strcat(M_ARGV(0, string), ":GlobalForces");
+}
+
+MUTATOR_HOOKFUNCTION(mutator_globalforces, BuildMutatorsPrettyString) {
+ M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Global forces");
+}
+
+MUTATOR_HOOKFUNCTION(mutator_globalforces, PlayerDamage_SplitHealthArmor) {
+ entity frag_attacker = M_ARGV(1, entity);
+ entity frag_target = M_ARGV(2, entity);
+ if (autocvar_g_globalforces_noself && frag_target == frag_attacker) return;
+ vector damage_force = M_ARGV(3, vector) * autocvar_g_globalforces;
+ FOREACH_CLIENT(IS_PLAYER(it) && it != frag_target, {
+ if (autocvar_g_globalforces_range) {
+ if (vdist(it.origin - frag_target.origin, >, autocvar_g_globalforces_range)) {
+ continue;
+ }
+ }
+ float f = (it == frag_attacker) ? autocvar_g_globalforces_self : 1;
+ it.velocity += damage_explosion_calcpush(f * it.damageforcescale * damage_force, it.velocity, autocvar_g_balance_damagepush_speedfactor);
+ });
+}
+
+#endif
--- /dev/null
+#ifdef SVQC
+ #include "globalforces.qc"
+#endif
spawnfunc(item_minst_cells)
{
- if (!g_instagib) { remove(this); return; }
+ if (!g_instagib) { delete(this); return; }
if (!this.ammo_cells) this.ammo_cells = autocvar_g_instagib_ammo_drop;
StartItem(this, ITEM_VaporizerCells);
}
{
// client became player on connection skipping putObserverInServer step
if (IS_REAL_CLIENT(player))
- if (warmup_stage)
+ if (warmup_stage || autocvar_sv_itemstime == 2)
Item_ItemsTime_SetTimesForPlayer(player);
}
}
MUTATOR_HOOKFUNCTION(itemstime, PlayerSpawn)
{
- if (warmup_stage) return;
+ if (warmup_stage || autocvar_sv_itemstime == 2) return;
entity player = M_ARGV(0, entity);
Item_ItemsTime_ResetTimesForPlayer(player);
{
if (!(
(autocvar_hud_panel_itemstime == 1 && spectatee_status != 0)
- || (autocvar_hud_panel_itemstime == 2 && (spectatee_status != 0 || warmup_stage))
+ || (autocvar_hud_panel_itemstime == 2 && (spectatee_status != 0 || warmup_stage || STAT(ITEMSTIME) == 2))
)) { return; }
}
else
if (autocvar_hud_panel_itemstime_dynamicsize)
{
if (autocvar__hud_configure)
- if (menu_enabled != 2)
+ if (hud_configure_menu_open != 2)
HUD_Panel_DrawBg(1); // also draw the bg of the entire panel
// reduce panel to avoid spacing items
{
entity frag_attacker = M_ARGV(1, entity);
entity frag_target = M_ARGV(2, entity);
-
+
if(IS_PLAYER(frag_attacker))
if(IS_PLAYER(frag_target))
if(time < frag_target.midair_shieldtime)
int phys_multijump = PHYS_MULTIJUMP(player);
- if(!M_ARGV(2, bool) && player.multijump_ready && (PHYS_MULTIJUMP_COUNT(player) < phys_multijump || phys_multijump == -1) && player.velocity_z > PHYS_MULTIJUMP_SPEED(player) &&
+ if(!M_ARGV(2, bool) && player.multijump_ready && (PHYS_MULTIJUMP_COUNT(player) < phys_multijump || phys_multijump == -1) && player.velocity_z > PHYS_MULTIJUMP_SPEED(player) &&
(!PHYS_MULTIJUMP_MAXSPEED(player) || vdist(player.velocity, <=, PHYS_MULTIJUMP_MAXSPEED(player))))
{
if (PHYS_MULTIJUMP(player))
this.skin = 8 - (this.owner.wait - time) / (autocvar_g_nades_nade_lifetime / 10);
this.nextthink = time;
if(!this.owner || wasfreed(this.owner))
- remove(this);
+ delete(this);
}
void nade_burn_spawn(entity _nade)
if(round_handler_IsActive())
if(!round_handler_IsRoundStarted())
{
- remove(this);
+ delete(this);
return;
}
if(time > this.pushltime)
{
- remove(this);
+ delete(this);
return;
}
proj.angles = vectoangles(proj.velocity);
proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_ARC;
//CSQCProjectile(proj, true, PROJECTILE_NAPALM_FIRE, true);
if(round_handler_IsActive())
if(!round_handler_IsRoundStarted())
{
- remove(this);
+ delete(this);
return;
}
if(time >= this.ltime)
{
- remove(this);
+ delete(this);
return;
}
if(round_handler_IsActive())
if(!round_handler_IsRoundStarted())
{
- remove(this);
+ delete(this);
return;
}
Damage_DamageInfo(this.origin, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
autocvar_g_nades_nade_radius, '1 1 1' * autocvar_g_nades_nade_force, this.projectiledeathtype, 0, this);
}
- remove(this);
+ delete(this);
return;
}
if(this.realowner.nade_spawnloc)
{
- remove(this.realowner.nade_spawnloc);
+ delete(this.realowner.nade_spawnloc);
this.realowner.nade_spawnloc = NULL;
}
{
if(time >= this.ltime)
{
- remove(this);
+ delete(this);
return;
}
RemoveGrapplingHook(it.realowner);
});
- remove(this);
+ delete(this);
}
void spawn_held_nade(entity player, entity nowner, float ntime, int ntype, string pntype);
{
nade_pickup(toucher, this);
sound(this, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, 0.5 *(ATTEN_LARGE + ATTEN_MAX));
- remove(this);
+ delete(this);
return;
}
/*float is_weapclip = 0;
if(it.classname == "grapplinghook")
RemoveGrapplingHook(it.realowner);
});
- remove(this);
+ delete(this);
return;
}
entity _nade = e.nade;
e.nade = NULL;
- remove(e.fake_nade);
+ delete(e.fake_nade);
e.fake_nade = NULL;
makevectors(e.v_angle);
- W_SetupShot(e, false, false, SND_Null, CH_WEAPON_A, 0);
+ // NOTE: always throw from first weapon entity?
+ W_SetupShot(e, weaponentities[0], false, false, SND_Null, CH_WEAPON_A, 0);
Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER, CPID_NADES);
_nade.damagedbycontents = true;
_nade.angles = vectoangles(_nade.velocity);
_nade.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, _nade);
_nade.projectiledeathtype = DEATH_NADE.m_id;
_nade.toss_time = time;
_nade.solid = SOLID_CORPSE; //((_nade.nade_type == NADE_TYPE_TRANSLOCATE) ? SOLID_CORPSE : SOLID_BBOX);
return; // only allow bonus nades
if(this.nade)
- remove(this.nade);
+ delete(this.nade);
if(this.fake_nade)
- remove(this.fake_nade);
+ delete(this.fake_nade);
int ntype;
string pntype = this.pokenade_type;
void nades_Clear(entity player)
{
if(player.nade)
- remove(player.nade);
+ delete(player.nade);
if(player.fake_nade)
- remove(player.fake_nade);
+ delete(player.fake_nade);
player.nade = player.fake_nade = NULL;
player.nade_timer = 0;
if (held_nade)
{
player.nade_timer = bound(0, (time - held_nade.nade_time_primed) / autocvar_g_nades_nade_lifetime, 1);
- // LOG_TRACEF("%d %d\n", player.nade_timer, time - held_nade.nade_time_primed);
+ // LOG_TRACEF("%d %d", player.nade_timer, time - held_nade.nade_time_primed);
makevectors(player.angles);
held_nade.velocity = player.velocity;
setorigin(held_nade, player.origin + player.view_ofs + v_forward * 8 + v_right * -8 + v_up * 0);
if(player.nade_spawnloc.cnt <= 0)
{
- remove(player.nade_spawnloc);
+ delete(player.nade_spawnloc);
player.nade_spawnloc = NULL;
}
}
MUTATOR_HOOKFUNCTION(nades, DropSpecialItems)
{
entity frag_target = M_ARGV(0, entity);
-
+
if(frag_target.nade)
toss_nade(frag_target, true, '0 0 0', time + 0.05);
}
#define REGISTER_NADE(id) REGISTER(Nades, NADE_TYPE, id, m_id, NEW(Nade))
CLASS(Nade, Object)
- ATTRIB(Nade, m_id, int, 0)
- ATTRIB(Nade, m_color, vector, '0 0 0')
- ATTRIB(Nade, m_name, string, _("Grenade"))
- ATTRIB(Nade, m_icon, string, "nade_normal")
- ATTRIBARRAY(Nade, m_projectile, int, 2)
- ATTRIBARRAY(Nade, m_trail, entity, 2)
+ ATTRIB(Nade, m_id, int, 0);
+ ATTRIB(Nade, m_color, vector, '0 0 0');
+ ATTRIB(Nade, m_name, string, _("Grenade"));
+ ATTRIB(Nade, m_icon, string, "nade_normal");
+ ATTRIBARRAY(Nade, m_projectile, int, 2);
+ ATTRIBARRAY(Nade, m_trail, entity, 2);
METHOD(Nade, display, void(entity this, void(string name, string icon) returns)) {
returns(this.m_name, sprintf("/gfx/hud/%s/%s", cvar_string("menu_skin"), this.m_icon));
}
e.draw = orb_draw;
IL_PUSH(g_drawables, e);
e.health = 255;
- e.move_movetype = MOVETYPE_NONE;
+ set_movetype(e, MOVETYPE_NONE);
e.solid = SOLID_NOT;
e.drawmask = MASK_NORMAL;
e.scale = 0.01;
#ifndef IMPLEMENTATION
CLASS(HeavyMachineGun, Weapon)
-/* ammotype */ ATTRIB(HeavyMachineGun, ammo_field, .int, ammo_nails)
-/* impulse */ ATTRIB(HeavyMachineGun, impulse, int, 3)
+/* ammotype */ ATTRIB(HeavyMachineGun, ammo_field, .int, ammo_nails);
+/* impulse */ ATTRIB(HeavyMachineGun, impulse, int, 3);
/* flags */ ATTRIB(HeavyMachineGun, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_SUPERWEAPON);
/* rating */ ATTRIB(HeavyMachineGun, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
/* color */ ATTRIB(HeavyMachineGun, wpcolor, vector, '0.5 0.5 0');
W_DecreaseAmmo(WEP_HMG, actor, WEP_CVAR(hmg, ammo));
- W_SetupShot (actor, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR(hmg, damage));
+ W_SetupShot (actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR(hmg, damage));
if(!autocvar_g_norecoil)
{
Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
- W_MachineGun_MuzzleFlash(actor);
- W_AttachToShotorg(actor, actor.muzzle_flash, '5 0 0');
+ W_MachineGun_MuzzleFlash(actor, weaponentity);
+ W_AttachToShotorg(actor, weaponentity, actor.(weaponentity).muzzle_flash, '5 0 0');
if (autocvar_g_casings >= 2) // casing code
{
makevectors(actor.v_angle); // for some reason, this is lost
- SpawnCasing (((random () * 50 + 50) * v_right) - (v_forward * (random () * 25 + 25)) - ((random () * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor);
+ SpawnCasing (((random () * 50 + 50) * v_right) - (v_forward * (random () * 25 + 25)) - ((random () * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor, weaponentity);
}
int slot = weaponslot(weaponentity);
METHOD(HeavyMachineGun, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
{
- W_Reload(actor, WEP_CVAR(hmg, ammo), SND_RELOAD);
+ W_Reload(actor, weaponentity, WEP_CVAR(hmg, ammo), SND_RELOAD);
}
METHOD(HeavyMachineGun, wr_suicidemessage, Notification(entity thiswep))
return actor.ok_use_ammocharge;
}
-void W_Blaster_Attack(entity, float, float, float, float, float, float, float, float, float, float);
+void W_Blaster_Attack(entity, .entity, float, float, float, float, float, float, float, float, float, float);
spawnfunc(weapon_hmg);
spawnfunc(weapon_rpc);
entity olditem = M_ARGV(1, entity);
entity frag_attacker = M_ARGV(2, entity);
- remove(olditem);
+ delete(olditem);
M_ARGV(1, entity) = NULL;
PS(player).m_weapon = WEP_BLASTER;
W_Blaster_Attack(
player,
+ weaponentities[0], // TODO: unhardcode
WEP_BLASTER.m_id | HITTYPE_SECONDARY,
WEP_CVAR_SEC(vaporizer, shotangle),
WEP_CVAR_SEC(vaporizer, damage),
#ifndef IMPLEMENTATION
CLASS(RocketPropelledChainsaw, Weapon)
-/* ammotype */ ATTRIB(RocketPropelledChainsaw, ammo_field, .int, ammo_rockets)
-/* impulse */ ATTRIB(RocketPropelledChainsaw, impulse, int, 7)
+/* ammotype */ ATTRIB(RocketPropelledChainsaw, ammo_field, .int, ammo_rockets);
+/* impulse */ ATTRIB(RocketPropelledChainsaw, impulse, int, 7);
/* flags */ ATTRIB(RocketPropelledChainsaw, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_CANCLIMB | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH | WEP_FLAG_SUPERWEAPON);
/* rating */ ATTRIB(RocketPropelledChainsaw, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
/* color */ ATTRIB(RocketPropelledChainsaw, wpcolor, vector, '0.5 0.5 0');
RadiusDamage (this, this.realowner, WEP_CVAR(rpc, damage), WEP_CVAR(rpc, edgedamage), WEP_CVAR(rpc, radius), NULL, NULL, WEP_CVAR(rpc, force), this.projectiledeathtype, directhitentity);
- remove (this);
+ delete (this);
}
void W_RocketPropelledChainsaw_Explode_think(entity this)
{
if(this.cnt <= time)
{
- remove(this);
+ delete(this);
return;
}
this.nextthink = time;
}
-void W_RocketPropelledChainsaw_Attack (Weapon thiswep, entity actor)
+void W_RocketPropelledChainsaw_Attack (Weapon thiswep, entity actor, .entity weaponentity)
{
entity missile = spawn(); //WarpZone_RefSys_SpawnSameRefSys(actor);
entity flash = spawn ();
W_DecreaseAmmo(thiswep, actor, WEP_CVAR(rpc, ammo));
- W_SetupShot_ProjectileSize (actor, '-3 -3 -3', '3 3 3', false, 5, SND_ROCKET_FIRE, CH_WEAPON_A, WEP_CVAR(rpc, damage));
+ W_SetupShot_ProjectileSize (actor, weaponentity, '-3 -3 -3', '3 3 3', false, 5, SND_ROCKET_FIRE, CH_WEAPON_A, WEP_CVAR(rpc, damage));
Send_Effect(EFFECT_ROCKET_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
PROJECTILE_MAKETRIGGER(missile);
missile.cnt = time + WEP_CVAR(rpc, lifetime);
missile.nextthink = time;
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
CSQCProjectile(missile, true, PROJECTILE_RPC, false);
setmodel(flash, MDL_RPC_MUZZLEFLASH); // precision set below
SUB_SetFade (flash, time, 0.1);
flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
- W_AttachToShotorg(actor, flash, '5 0 0');
+ W_AttachToShotorg(actor, weaponentity, flash, '5 0 0');
missile.pos1 = missile.velocity;
MUTATOR_CALLHOOK(EditProjectile, actor, missile);
{
if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(rpc, refire)))
{
- W_RocketPropelledChainsaw_Attack(thiswep, actor);
+ W_RocketPropelledChainsaw_Attack(thiswep, actor, weaponentity);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(rpc, animtime), w_ready);
}
}
METHOD(RocketPropelledChainsaw, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
{
- W_Reload(actor, WEP_CVAR(rpc, ammo), SND_RELOAD);
+ W_Reload(actor, weaponentity, WEP_CVAR(rpc, ammo), SND_RELOAD);
}
METHOD(RocketPropelledChainsaw, wr_suicidemessage, Notification(entity thiswep))
{
if (!(autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")))
{
- LOG_TRACE("Warning: Physical items are enabled but no physics engine can be used. Reverting to old items.\n");
+ LOG_TRACE("Warning: Physical items are enabled but no physics engine can be used. Reverting to old items.");
return -1;
}
}
}
if(!this.owner.modelindex)
- remove(this); // the real item is gone, remove this
+ delete(this); // the real item is gone, remove this
}
void physical_item_touch(entity this, entity toucher)
MUTATOR_HOOKFUNCTION(pinata, PlayerDies)
{
entity frag_target = M_ARGV(2, entity);
-
+
FOREACH(Weapons, it != WEP_Null, LAMBDA(
if(frag_target.weapons & WepSet_FromWeapon(it))
if(PS(frag_target).m_switchweapon != it)
gravity_delay = time + autocvar_g_random_gravity_delay;
- LOG_TRACE("Gravity is now: ", ftos(autocvar_sv_gravity), "\n");
+ LOG_TRACE("Gravity is now: ", ftos(autocvar_sv_gravity));
}
MUTATOR_HOOKFUNCTION(random_gravity, BuildMutatorsString)
if(e.netname) { strunzone(e.netname); e.netname = string_null; }
if(e.message) { strunzone(e.message); e.message = string_null; }
if(e.message2) { strunzone(e.message2); e.message2 = string_null; }
- remove(e);
+ delete(e);
e = NULL;
object_count -= 1;
fh = fopen(fn, FILE_WRITE);
if(fh < 0)
{
- LOG_TRACE("^1ERROR: ^7 superspec can not open ", fn, " for writing.\n");
+ LOG_TRACE("^1ERROR: ^7 superspec can not open ", fn, " for writing.");
}
else
{
if(this.enemy.crypto_idfp == "")
Send_Notification(NOTIF_ONE_ONLY, this.enemy, MSG_INFO, INFO_SUPERSPEC_MISSING_UID);
- remove(this);
+ delete(this);
}
MUTATOR_HOOKFUNCTION(superspec, ClientConnect)
fh = fopen(fn, FILE_READ);
if(fh < 0)
{
- LOG_TRACE("^1ERROR: ^7 superspec can not open ", fn, " for reading.\n");
+ LOG_TRACE("^1ERROR: ^7 superspec can not open ", fn, " for reading.");
}
else
{
string _magic = fgets(fh);
if(_magic != _SSMAGIX)
{
- LOG_TRACE("^1ERROR^7 While reading superspec options file: unknown magic\n");
+ LOG_TRACE("^1ERROR^7 While reading superspec options file: unknown magic");
}
else
{
entity e = spawn();
setorigin(e, org);
RadiusDamage(e, NULL, autocvar_g_touchexplode_damage, autocvar_g_touchexplode_edgedamage, autocvar_g_touchexplode_radius, NULL, NULL, autocvar_g_touchexplode_force, DEATH_TOUCHEXPLODE.m_id, NULL);
- remove(e);
+ delete(e);
}
MUTATOR_HOOKFUNCTION(touchexplode, PlayerPreThink)
#define REGISTER_WAYPOINT_(id, init) REGISTER(Waypoints, WP, id, m_id, init)
CLASS(Waypoint, Object)
- ATTRIB(Waypoint, m_id, int, 0)
- ATTRIB(Waypoint, netname, string, string_null)
- ATTRIB(Waypoint, m_name, string, string_null)
- ATTRIB(Waypoint, m_color, vector, '1 1 1')
- ATTRIB(Waypoint, m_blink, int, 1)
+ ATTRIB(Waypoint, m_id, int, 0);
+ ATTRIB(Waypoint, netname, string);
+ ATTRIB(Waypoint, m_name, string);
+ ATTRIB(Waypoint, m_color, vector, '1 1 1');
+ ATTRIB(Waypoint, m_blink, int, 1);
CONSTRUCTOR(Waypoint, string _netname, string _name, vector _color, int _blink) {
CONSTRUCT(Waypoint);
this.netname = _netname;
void Draw_WaypointSprite(entity this)
{
- if (this.lifetime)
+ if (this.lifetime > 0)
this.alpha = pow(bound(0, (this.fadetime - time) / this.lifetime, 1), waypointsprite_timealphaexponent);
else
this.alpha = 1;
if (autocvar_cl_hidewaypoints >= 2)
return;
- if (this.hideflags & 1)
- if (autocvar_cl_hidewaypoints)
- return; // fixed waypoint
+ if (this.hideflags & 1 && autocvar_cl_hidewaypoints)
+ return; // fixed waypoint
InterpolateOrigin_Do(this);
float t = entcs_GetTeam(player_localnum) + 1;
-
string spriteimage = "";
// choose the sprite
case SPRITERULE_SPECTATOR:
if (!(
(autocvar_g_waypointsprite_itemstime == 1 && t == NUM_SPECTATOR + 1)
- || (autocvar_g_waypointsprite_itemstime == 2 && (t == NUM_SPECTATOR + 1 || warmup_stage))
+ || (autocvar_g_waypointsprite_itemstime == 2 && (t == NUM_SPECTATOR + 1 || warmup_stage || STAT(ITEMSTIME) == 2))
))
return;
spriteimage = this.netname;
++waypointsprite_newcount;
- float dist;
- dist = vlen(this.origin - view_origin);
-
- float a;
- a = this.alpha * autocvar_hud_panel_fg_alpha;
+ float dist = vlen(this.origin - view_origin);
+ float a = this.alpha * autocvar_hud_panel_fg_alpha;
if (this.maxdistance > waypointsprite_normdistance)
a *= pow(bound(0, (this.maxdistance - dist) / (this.maxdistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent);
{
if (this.helpme && time < this.helpme)
a *= SPRITE_HELPME_BLINK;
- else if (!this.lifetime) // fading out waypoints don't blink
+ else if (this.lifetime > 0) // fading out waypoints don't blink
a *= spritelookupblinkvalue(this, spriteimage);
}
// ensure:
// (e.teleport_time - time) / wp.fade_time stays
// e.teleport_time = time + fadetime
- float current_fadetime;
- current_fadetime = e.teleport_time - time;
+ float current_fadetime = e.teleport_time - time;
e.teleport_time = time + t;
+ if (e.fade_time < 0)
+ e.fade_time = -e.fade_time;
e.fade_time = e.fade_time * t / current_fadetime;
}
{
if (!wp) return;
if (wp.owner) wp.owner.(wp.owned_by_field) = NULL;
- remove(wp);
+ delete(wp);
}
void WaypointSprite_Disown(entity wp, float fadetime)
)
{
entity wp = new(sprite_waypoint);
+ wp.fade_time = _lifetime; // if negative tells client not to fade it out
+ if(_lifetime < 0)
+ _lifetime = -_lifetime;
wp.teleport_time = time + _lifetime;
- wp.fade_time = _lifetime;
wp.exteriormodeltoclient = ref;
if (ref)
{
if (own)
{
if (own.(ownfield))
- remove(own.(ownfield));
+ delete(own.(ownfield));
own.(ownfield) = wp;
wp.owned_by_field = ownfield;
}
-#ifndef NET_NOTICE_H
-#define NET_NOTICE_H
+#pragma once
#ifdef SVQC
string autocvar_sv_join_notices;
#ifdef CSQC
void cl_notice_read();
#endif
-
-#endif
MSG_CENTER_NOTIF(CTF_PASS_OTHER_NEUTRAL, 1, 2, 0, "s1 s2", CPID_CTF_PASS, "0 0", _("^BG%s^BG passed the flag to %s"), "")
MULTITEAM_CENTER(CTF_PASS_RECEIVED, 4, 1, 1, 0, "s1", CPID_CTF_PASS, "0 0", _("^BGYou received the ^TC^TT^BG flag from %s"), "", FLAG)
MSG_CENTER_NOTIF(CTF_PASS_RECEIVED_NEUTRAL, 1, 1, 0, "s1", CPID_CTF_PASS, "0 0", _("^BGYou received the flag from %s"), "")
- MSG_CENTER_NOTIF(CTF_PASS_REQUESTED, 1, 1, 0, "s1 pass_key", CPID_CTF_PASS, "0 0", _("^BG%s^BG requests you to pass the flag%s"), "")
+ MSG_CENTER_NOTIF(CTF_PASS_REQUESTED, 1, 1, 0, "pass_key s1", CPID_CTF_PASS, "0 0", _("^BGPress ^F2%s^BG to receive the flag from %s^BG"), "")
MSG_CENTER_NOTIF(CTF_PASS_REQUESTING, 1, 1, 0, "s1", CPID_CTF_PASS, "0 0", _("^BGRequesting %s^BG to pass you the flag"), "")
MULTITEAM_CENTER(CTF_PASS_SENT, 4, 1, 1, 0, "s1", CPID_CTF_PASS, "0 0", _("^BGYou passed the ^TC^TT^BG flag to %s"), "", FLAG)
MSG_CENTER_NOTIF(CTF_PASS_SENT_NEUTRAL, 1, 1, 0, "s1", CPID_CTF_PASS, "0 0", _("^BGYou passed the flag to %s"), "")
MSG_CENTER_NOTIF(ONS_GENERATOR_SHIELDED, 1, 0, 0, "", CPID_ONS_CAPSHIELD, "0 0", _("^BGThe enemy generator cannot be destroyed yet\n^F2Capture some control points to unshield it"), "")
MULTITEAM_CENTER(ONS_NOTSHIELDED, 4, 1, 0, 0, "", CPID_ONSLAUGHT, "0 0", _("^BGThe ^TCenemy^BG generator is no longer shielded!"), "", NAME)
MSG_CENTER_NOTIF(ONS_NOTSHIELDED_TEAM, 1, 0, 0, "", CPID_ONSLAUGHT, "0 0", _("^K1Your generator is NOT shielded!\n^BGRe-capture control points to shield it!"), "")
- MSG_CENTER_NOTIF(ONS_TELEPORT, 1, 0, 0, "pass_key", CPID_ONSLAUGHT, "0 0", _("^BGPress ^F2DROPFLAG%s^BG to teleport"), "")
+ MSG_CENTER_NOTIF(ONS_TELEPORT, 1, 0, 0, "pass_key", CPID_ONSLAUGHT, "0 0", _("^BGPress ^F2%s^BG to teleport"), "")
MSG_CENTER_NOTIF(ONS_TELEPORT_ANTISPAM, 1, 0, 1, "f1secs", CPID_ONSLAUGHT, "0 0", _("^BGTeleporting disabled for %s"), "")
MSG_CENTER_NOTIF(OVERTIME_FRAG, 1, 0, 0, "", CPID_OVERTIME, "0 0", _("^F2Now playing ^F4OVERTIME^F2!\nKeep fragging until we have a winner!"), _("^F2Now playing ^F4OVERTIME^F2!\nKeep scoring until we have a winner!"))
MSG_CENTER_NOTIF(JOIN_PREVENT_MINIGAME, 1, 0, 0, "", CPID_Null, "0 0", _("^K1Cannot join given minigame session!"), "" )
- MSG_CENTER_NOTIF(VEHICLE_ENTER, 1, 0, 0, "pass_key", CPID_VEHICLES, "0 0", _("^BGPress ^F2DROPFLAG%s^BG to enter/exit the vehicle"), "")
- MSG_CENTER_NOTIF(VEHICLE_ENTER_GUNNER, 1, 0, 0, "pass_key", CPID_VEHICLES, "0 0", _("^BGPress ^F2DROPFLAG%s^BG to enter the vehicle gunner"), "")
- MSG_CENTER_NOTIF(VEHICLE_ENTER_STEAL, 1, 0, 0, "pass_key", CPID_VEHICLES, "0 0", _("^BGPress ^F2DROPFLAG%s^BG to steal this vehicle"), "")
+ MSG_CENTER_NOTIF(VEHICLE_ENTER, 1, 0, 0, "pass_key", CPID_VEHICLES, "0 0", _("^BGPress ^F2%s^BG to enter/exit the vehicle"), "")
+ MSG_CENTER_NOTIF(VEHICLE_ENTER_GUNNER, 1, 0, 0, "pass_key", CPID_VEHICLES, "0 0", _("^BGPress ^F2%s^BG to enter the vehicle gunner"), "")
+ MSG_CENTER_NOTIF(VEHICLE_ENTER_STEAL, 1, 0, 0, "pass_key", CPID_VEHICLES, "0 0", _("^BGPress ^F2%s^BG to steal this vehicle"), "")
MSG_CENTER_NOTIF(VEHICLE_STEAL, 1, 0, 0, "", CPID_VEHICLES_OTHER, "0 0", _("^F2The enemy is stealing one of your vehicles!\n^F4Stop them!"), "")
MSG_CENTER_NOTIF(VEHICLE_STEAL_SELF, 1, 0, 0, "", CPID_VEHICLES_OTHER, "4 0", _("^F2You have stolen the enemy's vehicle, you are now visible on their radar!"), "")
if (notif.nent_icon != "") strunzone(notif.nent_icon);
if (notif.nent_durcnt != "") strunzone(notif.nent_durcnt);
if (notif.nent_string != "") strunzone(notif.nent_string);
- remove(notif);
+ delete(notif);
}
void Destroy_All_Notifications()
}
else if(icon != "")
{
- LOG_WARNINGF(
+ LOG_WARNF(
(
"^1NOTIFICATION HAS ICON BUT NO HUDARGS: "
"^7net_type = %s, net_name = %s.\n"
if (cpid == CPID_Null && durcnt != "0 0")
{
- LOG_WARNINGF(
+ LOG_WARNF(
(
"Notification has durcnt but no cpid: "
"net_type = %s, net_name = %s."
Get_Notif_TypeName(net_type)
));
#endif
- LOG_WARNINGF("Incorrect usage of Local_Notification: %s\n", "Null notification");
+ LOG_WARNF("Incorrect usage of Local_Notification: %s", "Null notification");
return;
}
));
#endif
for (int i = 0; i < this.nent_stringcount; ++i) { if (this.nent_strings[i]) strunzone(this.nent_strings[i]); }
- remove(this);
+ delete(this);
}
bool Net_Write_Notification(entity this, entity client, int sf)
#endif
string checkargs = Notification_CheckArgs(broadcast, client);
- if (checkargs != "") { LOG_WARNINGF("Incorrect usage of Kill_Notification: %s", checkargs); return; }
+ if (checkargs != "") { LOG_WARNF("Incorrect usage of Kill_Notification: %s", checkargs); return; }
entity net_notif = new_pure(net_kill_notification);
net_notif.nent_broadcast = broadcast;
if (!notif)
{
- LOG_WARNING("Send_Notification: Could not find notification entity!");
+ LOG_WARN("Send_Notification: Could not find notification entity!");
return;
}
if (!net_name) { checkargs = sprintf("No notification provided! %s", checkargs); }
if (checkargs != "")
{
- LOG_WARNINGF("Incorrect usage of Send_Notification: %s", checkargs);
+ LOG_WARNF("Incorrect usage of Send_Notification: %s", checkargs);
return;
}
if ((notif.nent_stringcount + notif.nent_floatcount) != count)
{
- LOG_WARNINGF(
+ LOG_WARNF(
"Argument mismatch for Send_Notification(%s, ...)! "
"stringcount(%d) + floatcount(%d) != count(%d)\n"
"Check the definition and function call for accuracy...?\n",
-#ifndef NOTIFICATIONS_H
-#define NOTIFICATIONS_H
+#pragma once
#include <common/command/all.qh>
case MSG_MULTI: return "MSG_MULTI";
case MSG_CHOICE: return "MSG_CHOICE";
}
- LOG_WARNINGF("Get_Notif_TypeName(%d): Improper net type!\n", ORDINAL(net_type));
+ LOG_WARNF("Get_Notif_TypeName(%d): Improper net type!", ORDINAL(net_type));
return "";
}
case NOTIF_TEAM: return "NOTIF_TEAM";
case NOTIF_TEAM_EXCEPT: return "NOTIF_TEAM_EXCEPT";
}
- LOG_WARNINGF("Get_Notif_BroadcastName(%d): Improper broadcast!\n", broadcast);
+ LOG_WARNF("Get_Notif_BroadcastName(%d): Improper broadcast!", broadcast);
return "";
}
ARG_CASE(ARG_CS_SV, "race_col", CCR(((f1 == 1) ? "^F1" : "^F2"))) \
ARG_CASE(ARG_CS_SV, "race_diff", ((f2 > f3) ? sprintf(CCR("^1[+%s]"), mmssss(f2 - f3)) : sprintf(CCR("^2[-%s]"), mmssss(f3 - f2)))) \
ARG_CASE(ARG_CS, "missing_teams", notif_arg_missing_teams(f1)) \
- ARG_CASE(ARG_CS, "pass_key", ((((tmp_s = getcommandkey("pass", "+use")) != "pass") && !(strstrofs(tmp_s, "not bound", 0) >= 0)) ? sprintf(CCR(_(" ^F1(Press %s)")), tmp_s) : "")) \
+ ARG_CASE(ARG_CS, "pass_key", getcommandkey(_("drop flag"), "+use")) \
ARG_CASE(ARG_CS, "frag_ping", notif_arg_frag_ping(true, f2)) \
ARG_CASE(ARG_CS, "frag_stats", notif_arg_frag_stats(f2, f3, f4)) \
/*ARG_CASE(ARG_CS, "frag_pos", ((Should_Print_Score_Pos(f1)) ? sprintf("\n^BG%s", Read_Score_Pos(f1)) : ""))*/ \
{
Notification it = _Notifications_from(net_name, NULL);
if (it.nent_type != net_type) {
- LOG_WARNINGF("Get_Notif_Ent(%s (%d), %s (%d)): Improper net type '%s'!\n",
+ LOG_WARNF("Get_Notif_Ent(%s (%d), %s (%d)): Improper net type '%s'!",
Get_Notif_TypeName(net_type), net_type,
it.registered_id, net_name,
Get_Notif_TypeName(it.nent_type)
}
#include "all.inc"
-
-#endif
-#ifndef MOVELIB_H
-#define MOVELIB_H
+#pragma once
#ifdef SVQC
.vector moveto;
#endif
void movelib_groundalign4point(entity this, float spring_length, float spring_up, float blendrate, float _max);
-
-#endif
#ifdef SVQC
void set_movetype(entity this, int mt)
{
- if(mt == MOVETYPE_PHYSICS || mt == MOVETYPE_PUSH || mt == MOVETYPE_FAKEPUSH)
- {
- this.movetype = this.move_movetype = mt; // we still set move_movetype, for other code that checks movetype
+ this.move_movetype = mt;
+ if (mt == MOVETYPE_PHYSICS || mt == MOVETYPE_PUSH || mt == MOVETYPE_FAKEPUSH) {
this.move_qcphysics = false;
- return;
}
-
- this.move_movetype = mt;
-
- if(!this.move_qcphysics)
+ if (!this.move_qcphysics) {
this.movetype = mt;
+ }
}
#elif defined(CSQC)
void set_movetype(entity this, int mt)
X(17)
#undef X
{
- LOG_DEBUGF("Can't unstick an entity (edict: %d, classname: %s, origin: %s)\n",
+ LOG_DEBUGF("Can't unstick an entity (edict: %d, classname: %s, origin: %s)",
etof(this), this.classname, vtos(this.origin));
return false;
}
}
- LOG_DEBUGF("Sucessfully unstuck an entity (edict: %d, classname: %s, origin: %s)\n",
+ LOG_DEBUGF("Sucessfully unstuck an entity (edict: %d, classname: %s, origin: %s)",
etof(this), this.classname, vtos(this.origin));
_Movetype_LinkEdict(this, true);
return true;
{
case MOVETYPE_PUSH:
case MOVETYPE_FAKEPUSH:
- LOG_DEBUGF("Physics: Lacking QuakeC support for Push movetype, FIX ME by using engine physics!\n");
+ LOG_DEBUGF("Physics: Lacking QuakeC support for Push movetype, FIX ME by using engine physics!");
break;
case MOVETYPE_NONE:
break;
{
case MOVETYPE_PUSH:
case MOVETYPE_FAKEPUSH:
- LOG_DEBUGF("Physics: Lacking QuakeC support for Push movetype, FIX ME by using engine physics!\n");
+ LOG_DEBUGF("Physics: Lacking QuakeC support for Push movetype, FIX ME by using engine physics!");
break;
case MOVETYPE_NONE:
break;
-#ifndef MOVETYPES_H
-#define MOVETYPES_H
+#pragma once
#define IS_ONGROUND(s) boolean((s).flags & FL_ONGROUND)
#define SET_ONGROUND(s) ((s).flags |= FL_ONGROUND)
.float bouncefactor;
#endif
-#ifdef SVQC
-.bool move_qcphysics;
-#endif
-
void set_movetype(entity this, int mt);
.float move_movetype;
#ifdef CSQC
#define moveflags STAT(MOVEFLAGS)
#endif
-
-#endif
do_crouch = false;
if(STAT(FROZEN, this))
do_crouch = false;
- if((activeweapon.spawnflags & WEP_TYPE_MELEE_PRI) && viewmodel.animstate_startframe == viewmodel.anim_fire1_x && time < viewmodel.weapon_nextthink)
- do_crouch = false;
- if((activeweapon.spawnflags & WEP_TYPE_MELEE_SEC) && viewmodel.animstate_startframe == viewmodel.anim_fire2_x && time < viewmodel.weapon_nextthink)
- do_crouch = false;
if (do_crouch)
{
}
}
- if (IS_ONGROUND(this) || this.velocity.z <= 0 || pmove_waterjumptime <= 0)
- pmove_waterjumptime = 0;
+ if (IS_ONGROUND(this) || this.velocity.z <= 0 || PHYS_WATERJUMP_TIME(this) <= 0)
+ PHYS_WATERJUMP_TIME(this) = 0;
#endif
}
-void CPM_PM_Aircontrol(entity this, vector wishdir, float wishspeed)
+void CPM_PM_Aircontrol(entity this, float dt, vector wishdir, float wishspeed)
{
float k = 32 * (2 * IsMoveInDirection(this.movement, 0) - 1);
if (k <= 0)
if (dot > 0) // we can't change direction while slowing down
{
- k *= pow(dot, PHYS_AIRCONTROL_POWER(this)) * PHYS_INPUT_TIMELENGTH;
+ k *= pow(dot, PHYS_AIRCONTROL_POWER(this)) * dt;
xyspeed = max(0, xyspeed - PHYS_AIRCONTROL_PENALTY(this) * sqrt(max(0, 1 - dot*dot)) * k/32);
k *= PHYS_AIRCONTROL(this);
this.velocity = normalize(this.velocity * xyspeed + wishdir * k);
// sv_airaccel_sideways_friction 0
// prvm_globalset server speedclamp_mode 1
// (or 2)
-void PM_Accelerate(entity this, vector wishdir, float wishspeed, float wishspeed0, float accel, float accelqw, float stretchfactor, float sidefric, float speedlimit)
+void PM_Accelerate(entity this, float dt, vector wishdir, float wishspeed, float wishspeed0, float accel, float accelqw, float stretchfactor, float sidefric, float speedlimit)
{
float speedclamp = stretchfactor > 0 ? stretchfactor
: accelqw < 0 ? 1 // full clamping, no stretch
vector vel_xy = vec2(this.velocity);
vector vel_perpend = vel_xy - vel_straight * wishdir;
- float step = accel * PHYS_INPUT_TIMELENGTH * wishspeed0;
+ float step = accel * dt * wishspeed0;
float vel_xy_current = vlen(vel_xy);
if (speedlimit)
if (sidefric < 0 && (vel_perpend*vel_perpend))
// negative: only apply so much sideways friction to stay below the speed you could get by "braking"
{
- float f = max(0, 1 + PHYS_INPUT_TIMELENGTH * wishspeed * sidefric);
+ float f = max(0, 1 + dt * wishspeed * sidefric);
float themin = (vel_xy_backward * vel_xy_backward - vel_straight * vel_straight) / (vel_perpend * vel_perpend);
// assume: themin > 1
// vel_xy_backward*vel_xy_backward - vel_straight*vel_straight > vel_perpend*vel_perpend
}
}
else
- vel_perpend *= max(0, 1 - PHYS_INPUT_TIMELENGTH * wishspeed * sidefric);
+ vel_perpend *= max(0, 1 - dt * wishspeed * sidefric);
vel_xy = vel_straight * wishdir + vel_perpend;
this.velocity = vel_xy + vel_z * '0 0 1';
}
-void PM_AirAccelerate(entity this, vector wishdir, float wishspeed)
+void PM_AirAccelerate(entity this, float dt, vector wishdir, float wishspeed)
{
if (wishspeed == 0)
return;
float curspeed = vlen(curvel);
if (wishspeed > curspeed * 1.01)
- wishspeed = min(wishspeed, curspeed + PHYS_WARSOWBUNNY_AIRFORWARDACCEL(this) * PHYS_MAXSPEED(this) * PHYS_INPUT_TIMELENGTH);
+ wishspeed = min(wishspeed, curspeed + PHYS_WARSOWBUNNY_AIRFORWARDACCEL(this) * PHYS_MAXSPEED(this) * dt);
else
{
float f = max(0, (PHYS_WARSOWBUNNY_TOPSPEED(this) - curspeed) / (PHYS_WARSOWBUNNY_TOPSPEED(this) - PHYS_MAXSPEED(this)));
- wishspeed = max(curspeed, PHYS_MAXSPEED(this)) + PHYS_WARSOWBUNNY_ACCEL(this) * f * PHYS_MAXSPEED(this) * PHYS_INPUT_TIMELENGTH;
+ wishspeed = max(curspeed, PHYS_MAXSPEED(this)) + PHYS_WARSOWBUNNY_ACCEL(this) * f * PHYS_MAXSPEED(this) * dt;
}
vector wishvel = wishdir * wishspeed;
vector acceldir = wishvel - curvel;
float addspeed = vlen(acceldir);
acceldir = normalize(acceldir);
- float accelspeed = min(addspeed, PHYS_WARSOWBUNNY_TURNACCEL(this) * PHYS_MAXSPEED(this) * PHYS_INPUT_TIMELENGTH);
+ float accelspeed = min(addspeed, PHYS_WARSOWBUNNY_TURNACCEL(this) * PHYS_MAXSPEED(this) * dt);
if (PHYS_WARSOWBUNNY_BACKTOSIDERATIO(this) < 1)
{
{
#ifdef SVQC
if(autocvar_speedmeter)
- LOG_TRACE(strcat("landing velocity: ", vtos(this.velocity), " (abs: ", ftos(vlen(this.velocity)), ")\n"));
+ LOG_TRACE("landing velocity: ", vtos(this.velocity), " (abs: ", ftos(vlen(this.velocity)), ")");
#endif
if(this.lastground < time - 0.3)
{
}
#ifdef SVQC
if(this.jumppadcount > 1)
- LOG_TRACE(strcat(ftos(this.jumppadcount), "x jumppad combo\n"));
+ LOG_TRACE(ftos(this.jumppadcount), "x jumppad combo");
this.jumppadcount = 0;
#endif
}
#ifdef SVQC
PHYS_TELEPORT_TIME(this) = time + 2; // safety net
#elif defined(CSQC)
- pmove_waterjumptime = 2;
+ PHYS_WATERJUMP_TIME(this) = 2;
#endif
}
}
#endif
}
-void PM_check_punch(entity this)
+void PM_check_punch(entity this, float dt)
{
#ifdef SVQC
if (this.punchangle != '0 0 0')
{
- float f = vlen(this.punchangle) - 10 * PHYS_INPUT_TIMELENGTH;
+ float f = vlen(this.punchangle) - 10 * dt;
if (f > 0)
this.punchangle = normalize(this.punchangle) * f;
else
if (this.punchvector != '0 0 0')
{
- float f = vlen(this.punchvector) - 30 * PHYS_INPUT_TIMELENGTH;
+ float f = vlen(this.punchvector) - 30 * dt;
if (f > 0)
this.punchvector = normalize(this.punchvector) * f;
else
#endif
}
-void PM_fly(entity this, float maxspd_mod)
-{
- // noclipping or flying
- UNSET_ONGROUND(this);
-
- this.velocity = this.velocity * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this));
- makevectors(this.v_angle);
- //wishvel = v_forward * this.movement.x + v_right * this.movement.y + v_up * this.movement.z;
- vector wishvel = v_forward * this.movement.x
- + v_right * this.movement.y
- + '0 0 1' * this.movement.z;
- // acceleration
- vector wishdir = normalize(wishvel);
- float wishspeed = min(vlen(wishvel), PHYS_MAXSPEED(this) * maxspd_mod);
-#ifdef SVQC
- if(time >= PHYS_TELEPORT_TIME(this))
-#elif defined(CSQC)
- if(pmove_waterjumptime <= 0)
-#endif
- PM_Accelerate(this, wishdir, wishspeed, wishspeed, PHYS_ACCELERATE(this) * maxspd_mod, 1, 0, 0, 0);
-}
-
-void PM_swim(entity this, float maxspd_mod)
-{
- // swimming
- UNSET_ONGROUND(this);
-
- float jump = PHYS_INPUT_BUTTON_JUMP(this);
- // water jump only in certain situations
- // this mimics quakeworld code
- if (jump && this.waterlevel == WATERLEVEL_SWIMMING && this.velocity_z >= -180 && !this.viewloc)
- {
- vector yawangles = '0 1 0' * this.v_angle.y;
- makevectors(yawangles);
- vector forward = v_forward;
- vector spot = this.origin + 24 * forward;
- spot_z += 8;
- traceline(spot, spot, MOVE_NOMONSTERS, this);
- if (trace_startsolid)
- {
- spot_z += 24;
- traceline(spot, spot, MOVE_NOMONSTERS, this);
- if (!trace_startsolid)
- {
- this.velocity = forward * 50;
- this.velocity_z = 310;
- UNSET_ONGROUND(this);
- SET_JUMP_HELD(this);
- }
- }
- }
- makevectors(this.v_angle);
- float wishdown = this.movement.z;
- if(PHYS_INPUT_BUTTON_CROUCH(this))
- wishdown = -PHYS_MAXSPEED(this);
- //wishvel = v_forward * this.movement.x + v_right * this.movement.y + v_up * this.movement.z;
- vector wishvel = v_forward * this.movement.x
- + v_right * this.movement.y
- + '0 0 1' * wishdown;
- if(this.viewloc)
- wishvel.z = -160; // drift anyway
- else if (wishvel == '0 0 0')
- wishvel = '0 0 -60'; // drift towards bottom
-
- vector wishdir = normalize(wishvel);
- float wishspeed = min(vlen(wishvel), PHYS_MAXSPEED(this) * maxspd_mod) * 0.7;
-
-// if (pmove_waterjumptime <= 0) // TODO: use
- {
- // water friction
- float f = 1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this);
- f = min(max(0, f), 1);
- this.velocity *= f;
-
- f = wishspeed - this.velocity * wishdir;
- if (f > 0)
- {
- float accelspeed = min(PHYS_ACCELERATE(this) * PHYS_INPUT_TIMELENGTH * wishspeed, f);
- this.velocity += accelspeed * wishdir;
- }
-
- // holding jump button swims upward slowly
- if (jump && !this.viewloc)
- {
-#if 0
- if (this.watertype & CONTENT_LAVA)
- this.velocity_z = 50;
- else if (this.watertype & CONTENT_SLIME)
- this.velocity_z = 80;
- else
- {
- if (IS_NEXUIZ_DERIVED(gamemode))
-#endif
- if(this.waterlevel >= WATERLEVEL_SUBMERGED)
- this.velocity_z = PHYS_MAXSPEED(this);
- else
- this.velocity_z = 200;
-#if 0
- else
- this.velocity_z = 100;
- }
-#endif
- }
- }
- if(this.viewloc)
- {
- const float addspeed = wishspeed - this.velocity * wishdir;
- if (addspeed > 0)
- {
- const float accelspeed = min(PHYS_ACCELERATE(this) * PHYS_INPUT_TIMELENGTH * wishspeed, addspeed);
- this.velocity += accelspeed * wishdir;
- }
- }
- else
- {
- // water acceleration
- PM_Accelerate(this, wishdir, wishspeed, wishspeed, PHYS_ACCELERATE(this) * maxspd_mod, 1, 0, 0, 0);
- }
-}
-
.vector oldmovement;
-void PM_ladder(entity this, float maxspd_mod)
-{
- // on a spawnfunc_func_ladder or swimming in spawnfunc_func_water
- UNSET_ONGROUND(this);
-
- float g;
- g = PHYS_GRAVITY(this) * PHYS_INPUT_TIMELENGTH;
- if (PHYS_ENTGRAVITY(this))
- g *= PHYS_ENTGRAVITY(this);
- if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
- {
- g *= 0.5;
- this.velocity_z += g;
- }
- this.velocity = this.velocity * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this));
- makevectors(this.v_angle);
- //wishvel = v_forward * this.movement.x + v_right * this.movement.y + v_up * this.movement.z;
- vector wishvel = v_forward * this.movement_x
- + v_right * this.movement_y
- + '0 0 1' * this.movement_z;
- if(this.viewloc)
- wishvel.z = this.oldmovement.x;
- this.velocity_z += g;
- if (this.ladder_entity.classname == "func_water")
- {
- float f = vlen(wishvel);
- if (f > this.ladder_entity.speed)
- wishvel *= (this.ladder_entity.speed / f);
-
- this.watertype = this.ladder_entity.skin;
- f = this.ladder_entity.origin_z + this.ladder_entity.maxs_z;
- if ((this.origin_z + this.view_ofs_z) < f)
- this.waterlevel = WATERLEVEL_SUBMERGED;
- else if ((this.origin_z + (this.mins_z + this.maxs_z) * 0.5) < f)
- this.waterlevel = WATERLEVEL_SWIMMING;
- else if ((this.origin_z + this.mins_z + 1) < f)
- this.waterlevel = WATERLEVEL_WETFEET;
- else
- {
- this.waterlevel = WATERLEVEL_NONE;
- this.watertype = CONTENT_EMPTY;
- }
- }
- // acceleration
- vector wishdir = normalize(wishvel);
- float wishspeed = min(vlen(wishvel), PHYS_MAXSPEED(this) * maxspd_mod);
-#ifdef SVQC
- if(time >= PHYS_TELEPORT_TIME(this))
-#elif defined(CSQC)
- if(pmove_waterjumptime <= 0)
-#endif
- // water acceleration
- PM_Accelerate(this, wishdir, wishspeed, wishspeed, PHYS_ACCELERATE(this)*maxspd_mod, 1, 0, 0, 0);
-}
-
-void PM_jetpack(entity this, float maxspd_mod)
+void PM_jetpack(entity this, float maxspd_mod, float dt)
{
//makevectors(this.v_angle.y * '0 1 0');
makevectors(this.v_angle);
fvel = min(1, vlen(wishvel) / best);
if (PHYS_JETPACK_FUEL(this) && !(ITEMS_STAT(this) & IT_UNLIMITED_WEAPON_AMMO))
- f = min(1, PHYS_AMMO_FUEL(this) / (PHYS_JETPACK_FUEL(this) * PHYS_INPUT_TIMELENGTH * fvel));
+ f = min(1, PHYS_AMMO_FUEL(this) / (PHYS_JETPACK_FUEL(this) * dt * fvel));
else
f = 1;
if (f > 0 && wishvel != '0 0 0')
{
- this.velocity = this.velocity + wishvel * f * PHYS_INPUT_TIMELENGTH;
+ this.velocity = this.velocity + wishvel * f * dt;
UNSET_ONGROUND(this);
#ifdef SVQC
if (!(ITEMS_STAT(this) & IT_UNLIMITED_WEAPON_AMMO))
- this.ammo_fuel -= PHYS_JETPACK_FUEL(this) * PHYS_INPUT_TIMELENGTH * fvel * f;
+ this.ammo_fuel -= PHYS_JETPACK_FUEL(this) * dt * fvel * f;
ITEMS_STAT(this) |= IT_USING_JETPACK;
}
}
-void PM_walk(entity this, float maxspd_mod)
-{
- if (!WAS_ONGROUND(this))
- {
-#ifdef SVQC
- if (autocvar_speedmeter)
- LOG_TRACE(strcat("landing velocity: ", vtos(this.velocity), " (abs: ", ftos(vlen(this.velocity)), ")\n"));
-#endif
- if (this.lastground < time - 0.3)
- this.velocity *= (1 - PHYS_FRICTION_ONLAND(this));
-#ifdef SVQC
- if (this.jumppadcount > 1)
- LOG_TRACE(strcat(ftos(this.jumppadcount), "x jumppad combo\n"));
- this.jumppadcount = 0;
-#endif
- }
-
- // walking
- makevectors(this.v_angle.y * '0 1 0');
- const vector wishvel = v_forward * this.movement.x
- + v_right * this.movement.y;
- // acceleration
- const vector wishdir = normalize(wishvel);
- float wishspeed = vlen(wishvel);
- wishspeed = min(wishspeed, PHYS_MAXSPEED(this) * maxspd_mod);
- if (IS_DUCKED(this)) wishspeed *= 0.5;
-
- // apply edge friction
- const float f2 = vlen2(vec2(this.velocity));
- if (f2 > 0)
- {
- trace_dphitq3surfaceflags = 0;
- tracebox(this.origin, this.mins, this.maxs, this.origin - '0 0 1', MOVE_NOMONSTERS, this);
- // TODO: apply edge friction
- // apply ground friction
- const int realfriction = (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK)
- ? PHYS_FRICTION_SLICK(this)
- : PHYS_FRICTION(this);
-
- float f = sqrt(f2);
- f = 1 - PHYS_INPUT_TIMELENGTH * realfriction * ((f < PHYS_STOPSPEED(this)) ? (PHYS_STOPSPEED(this) / f) : 1);
- f = max(0, f);
- this.velocity *= f;
- /*
- Mathematical analysis time!
-
- Our goal is to invert this mess.
-
- For the two cases we get:
- v = v0 * (1 - PHYS_INPUT_TIMELENGTH * (PHYS_STOPSPEED(this) / v0) * PHYS_FRICTION(this))
- = v0 - PHYS_INPUT_TIMELENGTH * PHYS_STOPSPEED(this) * PHYS_FRICTION(this)
- v0 = v + PHYS_INPUT_TIMELENGTH * PHYS_STOPSPEED(this) * PHYS_FRICTION(this)
- and
- v = v0 * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this))
- v0 = v / (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this))
-
- These cases would be chosen ONLY if:
- v0 < PHYS_STOPSPEED(this)
- v + PHYS_INPUT_TIMELENGTH * PHYS_STOPSPEED(this) * PHYS_FRICTION(this) < PHYS_STOPSPEED(this)
- v < PHYS_STOPSPEED(this) * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this))
- and, respectively:
- v0 >= PHYS_STOPSPEED(this)
- v / (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this)) >= PHYS_STOPSPEED(this)
- v >= PHYS_STOPSPEED(this) * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION(this))
- */
- }
- const float addspeed = wishspeed - this.velocity * wishdir;
- if (addspeed > 0)
- {
- const float accelspeed = min(PHYS_ACCELERATE(this) * PHYS_INPUT_TIMELENGTH * wishspeed, addspeed);
- this.velocity += accelspeed * wishdir;
- }
-}
-
-void PM_air(entity this, float buttons_prev, float maxspd_mod)
-{
- makevectors(this.v_angle.y * '0 1 0');
- vector wishvel = v_forward * this.movement.x
- + v_right * this.movement.y;
- // acceleration
- vector wishdir = normalize(wishvel);
- float wishspeed = vlen(wishvel);
-
-#ifdef SVQC
- if(time >= PHYS_TELEPORT_TIME(this))
-#elif defined(CSQC)
- if(pmove_waterjumptime <= 0)
-#endif
- {
- float maxairspd = PHYS_MAXAIRSPEED(this) * min(maxspd_mod, 1);
-
- // apply air speed limit
- float airaccelqw = PHYS_AIRACCEL_QW(this);
- float wishspeed0 = wishspeed;
- wishspeed = min(wishspeed, maxairspd);
- if (IS_DUCKED(this))
- wishspeed *= 0.5;
- float airaccel = PHYS_AIRACCELERATE(this) * min(maxspd_mod, 1);
-
- float accelerating = (this.velocity * wishdir > 0);
- float wishspeed2 = wishspeed;
-
- // CPM: air control
- if (PHYS_AIRSTOPACCELERATE(this))
- {
- vector curdir = normalize(vec2(this.velocity));
- airaccel += (PHYS_AIRSTOPACCELERATE(this)*maxspd_mod - airaccel) * max(0, -(curdir * wishdir));
- }
- // note that for straight forward jumping:
- // step = accel * PHYS_INPUT_TIMELENGTH * wishspeed0;
- // accel = bound(0, wishspeed - vel_xy_current, step) * accelqw + step * (1 - accelqw);
- // -->
- // dv/dt = accel * maxspeed (when slow)
- // dv/dt = accel * maxspeed * (1 - accelqw) (when fast)
- // log dv/dt = logaccel + logmaxspeed (when slow)
- // log dv/dt = logaccel + logmaxspeed + log(1 - accelqw) (when fast)
- float strafity = IsMoveInDirection(this.movement, -90) + IsMoveInDirection(this.movement, +90); // if one is nonzero, other is always zero
- if (PHYS_MAXAIRSTRAFESPEED(this))
- wishspeed = min(wishspeed, GeomLerp(PHYS_MAXAIRSPEED(this)*maxspd_mod, strafity, PHYS_MAXAIRSTRAFESPEED(this)*maxspd_mod));
- if (PHYS_AIRSTRAFEACCELERATE(this))
- airaccel = GeomLerp(airaccel, strafity, PHYS_AIRSTRAFEACCELERATE(this)*maxspd_mod);
- if (PHYS_AIRSTRAFEACCEL_QW(this))
- airaccelqw =
- (((strafity > 0.5 ? PHYS_AIRSTRAFEACCEL_QW(this) : PHYS_AIRACCEL_QW(this)) >= 0) ? +1 : -1)
- *
- (1 - GeomLerp(1 - fabs(PHYS_AIRACCEL_QW(this)), strafity, 1 - fabs(PHYS_AIRSTRAFEACCEL_QW(this))));
- // !CPM
-
- if (PHYS_WARSOWBUNNY_TURNACCEL(this) && accelerating && this.movement.y == 0 && this.movement.x != 0)
- PM_AirAccelerate(this, wishdir, wishspeed2);
- else {
- float sidefric = maxairspd ? (PHYS_AIRACCEL_SIDEWAYS_FRICTION(this) / maxairspd) : 0;
- PM_Accelerate(this, wishdir, wishspeed, wishspeed0, airaccel, airaccelqw, PHYS_AIRACCEL_QW_STRETCHFACTOR(this), sidefric, PHYS_AIRSPEEDLIMIT_NONQW(this));
- }
-
- if (PHYS_AIRCONTROL(this))
- CPM_PM_Aircontrol(this, wishdir, wishspeed2);
- }
-}
-
// used for calculating airshots
bool IsFlying(entity this)
{
return true;
}
-void PM_Main(entity this)
-{
- int buttons = PHYS_INPUT_BUTTON_MASK(this);
-#ifdef CSQC
- this.items = STAT(ITEMS);
-
- this.movement = PHYS_INPUT_MOVEVALUES(this);
-
- this.spectatorspeed = STAT(SPECTATORSPEED);
-
- this.team = myteam + 1; // is this correct?
- if (!(PHYS_INPUT_BUTTON_JUMP(this))) // !jump
- UNSET_JUMP_HELD(this); // canjump = true
- pmove_waterjumptime -= PHYS_INPUT_TIMELENGTH;
-
- PM_ClientMovement_UpdateStatus(this);
-#endif
-
- this.oldmovement = this.movement;
-
-
-#ifdef SVQC
- WarpZone_PlayerPhysics_FixVAngle(this);
-#endif
- float maxspeed_mod = 1;
- maxspeed_mod *= PHYS_HIGHSPEED(this);
-
-#ifdef SVQC
- Physics_UpdateStats(this, maxspeed_mod);
-
- if (this.PlayerPhysplug)
- if (this.PlayerPhysplug(this))
- return;
-#elif defined(CSQC)
- if(hud != HUD_NORMAL)
- return; // no vehicle prediction (yet)
-#endif
-
-#ifdef SVQC
- anticheat_physics(this);
-#endif
-
- if (PM_check_specialcommand(this, buttons))
- return;
-#ifdef SVQC
- if (sv_maxidle > 0)
- {
- if (buttons != this.buttons_old || this.movement != this.movement_old || this.v_angle != this.v_angle_old)
- this.parm_idlesince = time;
- }
-#endif
- int buttons_prev = this.buttons_old;
- this.buttons_old = buttons;
- this.movement_old = this.movement;
- this.v_angle_old = this.v_angle;
-
- PM_check_nickspam(this);
-
- PM_check_punch(this);
-#ifdef SVQC
- if (IS_BOT_CLIENT(this))
- {
- if (playerdemo_read(this))
- return;
- bot_think(this);
- }
-#endif
-
-#ifdef SVQC
- if (IS_PLAYER(this))
- {
- const bool allowed_to_move = (time >= game_starttime);
- if (!allowed_to_move)
- {
- this.velocity = '0 0 0';
- set_movetype(this, MOVETYPE_NONE);
- this.disableclientprediction = 2;
- }
- else if (this.disableclientprediction == 2)
- {
- if (this.move_movetype == MOVETYPE_NONE)
- set_movetype(this, MOVETYPE_WALK);
- this.disableclientprediction = 0;
- }
- }
-#endif
-
-#ifdef SVQC
- if (this.move_movetype == MOVETYPE_NONE)
- return;
-
- // when we get here, disableclientprediction cannot be 2
- this.disableclientprediction = (this.move_qcphysics) ? -1 : 0;
-#endif
-
- viewloc_PlayerPhysics(this);
-
- PM_check_frozen(this);
-
- PM_check_blocked(this);
-
- maxspeed_mod = 1;
-
- if (this.in_swamp)
- maxspeed_mod *= this.swamp_slowdown; //cvar("g_balance_swamp_moverate");
-
- // conveyors: first fix velocity
- if (this.conveyor.state)
- this.velocity -= this.conveyor.movedir;
-
- MUTATOR_CALLHOOK(PlayerPhysics, this);
-
- if (!IS_PLAYER(this))
- {
-#ifdef SVQC
- maxspeed_mod = autocvar_sv_spectator_speed_multiplier;
- if (!this.spectatorspeed)
- this.spectatorspeed = maxspeed_mod;
- if (this.impulse && this.impulse <= 19 || (this.impulse >= 200 && this.impulse <= 209) || (this.impulse >= 220 && this.impulse <= 229))
- {
- if (this.lastclassname != STR_PLAYER)
- {
- if (this.impulse == 10 || this.impulse == 15 || this.impulse == 18 || (this.impulse >= 200 && this.impulse <= 209))
- this.spectatorspeed = bound(1, this.spectatorspeed + 0.5, 5);
- else if (this.impulse == 11)
- this.spectatorspeed = maxspeed_mod;
- else if (this.impulse == 12 || this.impulse == 16 || this.impulse == 19 || (this.impulse >= 220 && this.impulse <= 229))
- this.spectatorspeed = bound(1, this.spectatorspeed - 0.5, 5);
- else if (this.impulse >= 1 && this.impulse <= 9)
- this.spectatorspeed = 1 + 0.5 * (this.impulse - 1);
- } // otherwise just clear
- this.impulse = 0;
- }
-#endif
- maxspeed_mod = this.spectatorspeed;
- }
-#ifdef SVQC
-
- float spd = max(PHYS_MAXSPEED(this), PHYS_MAXAIRSPEED(this)) * maxspeed_mod;
- if(this.speed != spd)
- {
- this.speed = spd;
- string temps = ftos(spd);
- stuffcmd(this, strcat("cl_forwardspeed ", temps, "\n"));
- stuffcmd(this, strcat("cl_backspeed ", temps, "\n"));
- stuffcmd(this, strcat("cl_sidespeed ", temps, "\n"));
- stuffcmd(this, strcat("cl_upspeed ", temps, "\n"));
- }
-
- if(this.jumpspeedcap_min != autocvar_sv_jumpspeedcap_min)
- {
- this.jumpspeedcap_min = autocvar_sv_jumpspeedcap_min;
- stuffcmd(this, sprintf("\ncl_jumpspeedcap_min \"%s\"\n", autocvar_sv_jumpspeedcap_min));
- }
- if(this.jumpspeedcap_max != autocvar_sv_jumpspeedcap_max)
- {
- this.jumpspeedcap_max = autocvar_sv_jumpspeedcap_max;
- stuffcmd(this, sprintf("\ncl_jumpspeedcap_max \"%s\"\n", autocvar_sv_jumpspeedcap_max));
- }
-#endif
-
- if(IS_DEAD(this))
- {
- // handle water here
- vector midpoint = ((this.absmin + this.absmax) * 0.5);
- if(pointcontents(midpoint) == CONTENT_WATER)
- {
- this.velocity = this.velocity * 0.5;
-
- // do we want this?
- //if(pointcontents(midpoint + '0 0 2') == CONTENT_WATER)
- //{ this.velocity_z = 70; }
- }
- goto end;
- }
-
-#ifdef SVQC
- if (!this.fixangle)
- this.angles = '0 1 0' * this.v_angle.y;
-#endif
-
- if (IS_PLAYER(this) && IS_ONGROUND(this))
- {
- PM_check_hitground(this);
- PM_Footsteps(this);
- }
-
-#ifdef SVQC
- if(IsFlying(this))
- this.wasFlying = 1;
-#endif
-
- if (IS_PLAYER(this))
- CheckPlayerJump(this);
-
- if (this.flags & FL_WATERJUMP)
- {
- this.velocity_x = this.movedir.x;
- this.velocity_y = this.movedir.y;
- if (this.waterlevel == WATERLEVEL_NONE
- #ifdef CSQC
- || pmove_waterjumptime <= 0
- #elif defined(SVQC)
- || time > PHYS_TELEPORT_TIME(this)
- #endif
- )
- {
- this.flags &= ~FL_WATERJUMP;
- #ifdef CSQC
- pmove_waterjumptime = 0;
- #elif defined(CSQC)
- PHYS_TELEPORT_TIME(this) = 0;
- #endif
- }
- }
-
- else if (MUTATOR_CALLHOOK(PM_Physics, this, maxspeed_mod))
- { }
-
-#ifdef SVQC
- else if (this.move_movetype == MOVETYPE_NOCLIP || this.move_movetype == MOVETYPE_FLY || this.move_movetype == MOVETYPE_FLY_WORLDONLY || MUTATOR_CALLHOOK(IsFlying, this))
-#elif defined(CSQC)
- else if (this.move_movetype == MOVETYPE_NOCLIP || this.move_movetype == MOVETYPE_FLY || this.move_movetype == MOVETYPE_FLY_WORLDONLY || MUTATOR_CALLHOOK(IsFlying, this))
-#endif
- PM_fly(this, maxspeed_mod);
-
- else if (this.waterlevel >= WATERLEVEL_SWIMMING)
- PM_swim(this, maxspeed_mod);
-
- else if (time < this.ladder_time)
- PM_ladder(this, maxspeed_mod);
-
- else if (ITEMS_STAT(this) & IT_USING_JETPACK)
- PM_jetpack(this, maxspeed_mod);
-
- else if (IS_ONGROUND(this))
- PM_walk(this, maxspeed_mod);
-
- else
- PM_air(this, buttons_prev, maxspeed_mod);
-
-LABEL(end)
- if (IS_ONGROUND(this))
- this.lastground = time;
-
- // conveyors: then break velocity again
- if(this.conveyor.state)
- this.velocity += this.conveyor.movedir;
-
- this.lastflags = this.flags;
-
- this.lastclassname = this.classname;
-}
+void sys_phys_update(entity this, float dt);
#if defined(SVQC)
void SV_PlayerPhysics(entity this)
#elif defined(CSQC)
void CSQC_ClientMovement_PlayerMove_Frame(entity this)
#endif
{
- PM_Main(this);
+ sys_phys_update(this, PHYS_INPUT_TIMELENGTH);
#ifdef SVQC
this.pm_frametime = frametime;
-#ifndef COMMON_PHYSICS_H
-#define COMMON_PHYSICS_H
+#pragma once
// Client/server mappings
.vector v_angle_old;
.string lastclassname;
-.float(entity) PlayerPhysplug;
+.float(entity,float) PlayerPhysplug;
float AdjustAirAccelQW(float accelqw, float factor);
bool IsFlying(entity a);
#define ITEMS_STAT(s) ((s).items)
.float teleport_time;
+#define PHYS_TELEPORT_TIME(s) ((s).teleport_time)
+
+.float waterjump_time;
+#define PHYS_WATERJUMP_TIME(s) ((s).waterjump_time)
#ifdef CSQC
+ #define PHYS_FIXANGLE(s) ('0 0 0')
+
string autocvar_cl_jumpspeedcap_min;
string autocvar_cl_jumpspeedcap_max;
- noref float pmove_waterjumptime;
-
const int FL_WATERJUMP = 2048; // player jumping out of water
const int FL_JUMPRELEASED = 4096; // for jump debouncing
#define PHYS_GRAVITY(s) STAT(MOVEVARS_GRAVITY, s)
- #define PHYS_TELEPORT_TIME(s) ((s).teleport_time)
-
#define TICRATE ticrate
#define PHYS_INPUT_ANGLES(s) input_angles
#elif defined(SVQC)
+ #define PHYS_FIXANGLE(s) ((s).fixangle)
+
bool Physics_Valid(string thecvar);
.float stat_sv_airspeedlimit_nonqw = _STAT(MOVEVARS_AIRSPEEDLIMIT_NONQW);
.string jumpspeedcap_min;
.string jumpspeedcap_max;
- #define PHYS_TELEPORT_TIME(s) ((s).teleport_time)
-
#define PHYS_GRAVITY(s) autocvar_sv_gravity
#define TICRATE sys_frametime
return true;
}
#endif
-
-#endif
{
// url_fclose is processing, we got a response for writing the data
// this must come from HTTP
- LOG_TRACE("Got response from player stats server:\n");
- while((s = url_fgets(fh))) { LOG_TRACE(" ", s, "\n"); }
- LOG_TRACE("End of response.\n");
+ LOG_TRACE("Got response from player stats server:");
+ while((s = url_fgets(fh))) { LOG_TRACE(" ", s); }
+ LOG_TRACE("End of response.");
url_fclose(fh);
break;
}
case URL_READY_CLOSED:
{
// url_fclose has finished
- LOG_TRACE("Player stats written\n");
+ LOG_TRACE("Player stats written");
PlayerStats_GameReport_DelayMapVote = false;
if(PS_GR_OUT_DB >= 0)
{
void PlayerStats_PlayerBasic(entity joiningplayer, float newrequest)
{
+ PlayerScore_Add(joiningplayer, SP_ELO, -1);
// http://stats.xonotic.org/player/GgXRw6piDtFIbMArMuiAi8JG4tiin8VLjZgsKB60Uds=/elo.txt
if(autocvar_g_playerstats_playerbasic_uri != "")
{
string uri = autocvar_g_playerstats_playerbasic_uri;
- if(joiningplayer.crypto_idfp != "")
- {
+ if (joiningplayer.crypto_idfp == "") {
+ PlayerScore_Add(joiningplayer, SP_ELO, -1);
+ } else {
// create the database if it doesn't already exist
if(PS_B_IN_DB < 0)
PS_B_IN_DB = db_create();
// now request the information
uri = strcat(uri, "/player/", uri_escape(uri_escape(uri_escape(joiningplayer.crypto_idfp))), "/elo.txt");
- LOG_TRACE("Retrieving playerstats from URL: ", uri, "\n");
+ LOG_TRACE("Retrieving playerstats from URL: ", uri);
url_single_fopen(
uri,
FILE_APPEND,
else
{
// server has this disabled, kill the DB and set status to idle
+ PlayerScore_Add(joiningplayer, SP_ELO, -1);
if(PS_B_IN_DB >= 0)
{
db_close(PS_B_IN_DB);
{
// determine whether we should retrieve playerbasic information again
- #if 0
- LOG_INFOF("PlayerStats_PlayerBasic_CheckUpdate('%s'): %f\n",
+ LOG_TRACEF("PlayerStats_PlayerBasic_CheckUpdate('%s'): %f",
joiningplayer.netname,
time
);
- #endif
// TODO: check to see if this playerid is inside the database already somehow...
// for now we'll just check the field, but this won't work for players who disconnect and reconnect properly
{
case URL_READY_CANWRITE:
{
- LOG_TRACE("-- Sending data to player stats server\n");
+ LOG_TRACE("-- Sending data to player stats server");
/*url_fputs(fh, "V 1\n");
#ifdef WATERMARK
url_fputs(fh, sprintf("R %s\n", WATERMARK));
url_fputs(fh, sprintf("m %s %s\n", cvar_string("_cl_playermodel"), cvar_string("_cl_playerskin"))); // model/skin
*/url_fputs(fh, "\n");
url_fclose(fh);
- break;
+ return;
}
case URL_READY_CANREAD:
{
- string s = "";
- LOG_TRACE("-- Got response from player stats server:\n");
- //string gametype = string_null;
- while((s = url_fgets(fh)))
- {
- LOG_TRACE(" ", s, "\n");
- /*
+ bool handled = false;
+ string gt = string_null;
+ for (string s = ""; (s = url_fgets(fh)); ) {
+ int n = tokenizebyseparator(s, " "); // key value? data
+ if (n == 1) continue;
string key = "", value = "", data = "";
-
- n = tokenizebyseparator(s, " "); // key (value) data
- if (n == 1)
- continue;
- else if (n == 2)
- {
- key = argv(0);
- data = argv(1);
- }
- else if (n >= 3)
- {
- key = argv(0);
- value = argv(1);
- data = argv(2);
- }
-
- if (data == "")
- continue;
-
- if (key == "#")
- continue;
- else if (key == "V")
- PlayerInfo_AddItem(p, "_version", data);
- else if (key == "R")
- PlayerInfo_AddItem(p, "_release", data);
- else if (key == "T")
- PlayerInfo_AddItem(p, "_time", data);
- else if (key == "S")
- PlayerInfo_AddItem(p, "_statsurl", data);
- else if (key == "P")
- PlayerInfo_AddItem(p, "_hashkey", data);
- else if (key == "n")
- PlayerInfo_AddItem(p, "_playernick", data);
- else if (key == "i")
- PlayerInfo_AddItem(p, "_playerid", data);
- else if (key == "G")
- gametype = data;
- else if (key == "e" && value != "")
- {
- if (gametype == "")
- PlayerInfo_AddItem(p, value, data);
- else
- PlayerInfo_AddItem(p, sprintf("%s/%s", gametype, value), data);
+ if (n == 2) {
+ key = argv(0);
+ data = argv(1);
+ } else if (n >= 3) {
+ key = argv(0);
+ value = argv(1);
+ data = argv(2);
}
- else
- continue;
- */
+ switch (key) {
+ case "V":
+ // PlayerInfo_AddItem(p, "_version", data);
+ break;
+ case "R":
+ // PlayerInfo_AddItem(p, "_release", data);
+ break;
+ case "T":
+ // PlayerInfo_AddItem(p, "_time", data);
+ break;
+ case "S":
+ // PlayerInfo_AddItem(p, "_statsurl", data);
+ break;
+ case "P":
+ // PlayerInfo_AddItem(p, "_hashkey", data);
+ break;
+ case "n":
+ // PlayerInfo_AddItem(p, "_playernick", data);
+ break;
+ case "i":
+ // PlayerInfo_AddItem(p, "_playerid", data);
+ // p.xonstat_id = stof(data);
+ break;
+ case "G":
+ gt = data;
+ break;
+ case "e":
+ LOG_TRACE("G: ", gt);
+ LOG_TRACE("e: ", data);
+ if (gt == GetGametype()) {
+ handled = true;
+ float e = stof(data);
+ PlayerScore_Add(p, SP_ELO, +1 + e);
+ }
+ if (gt == "") {
+ // PlayerInfo_AddItem(p, value, data);
+ } else {
+ // PlayerInfo_AddItem(p, sprintf("%s/%s", gt, value), data);
+ }
+ break;
+ }
}
- LOG_TRACE("-- End of response.\n");
url_fclose(fh);
+ if (handled) return;
break;
}
case URL_READY_CLOSED:
{
// url_fclose has finished
LOG_INFO("Player stats synchronized with server\n");
- break;
+ return;
}
case URL_READY_ERROR:
break;
}
}
+ PlayerScore_Add(p, SP_ELO, -1);
}
#endif // SVQC
// now actually set the event data
db_put(PS_D_IN_DB, sprintf("#%s", event), data);
- LOG_TRACE("Added item ", sprintf("#%s", event), "=", data, " to PS_D_IN_DB\n");
+ LOG_TRACE("Added item ", sprintf("#%s", event), "=", data, " to PS_D_IN_DB");
}
void PlayerStats_PlayerDetail()
PS_D_IN_DB = db_create();
//uri = strcat(uri, "/player/", uri_escape(crypto_getmyidfp(0)));
- LOG_TRACE("Retrieving playerstats from URL: ", autocvar_g_playerstats_playerdetail_uri, "\n");
+ LOG_TRACE("Retrieving playerstats from URL: ", autocvar_g_playerstats_playerdetail_uri);
url_single_fopen(
autocvar_g_playerstats_playerdetail_uri,
FILE_APPEND,
{
case URL_READY_CANWRITE:
{
- LOG_TRACE("PlayerStats_PlayerDetail_Handler(): Sending data to player stats server...\n");
+ LOG_TRACE("PlayerStats_PlayerDetail_Handler(): Sending data to player stats server...");
url_fputs(fh, "V 1\n");
#ifdef WATERMARK
url_fputs(fh, sprintf("R %s\n", WATERMARK));
-#ifndef PLAYERSTATS_H
-#define PLAYERSTATS_H
+#pragma once
#ifdef SVQC
//float PS_PM_IN_DB = -1; // playerstats_prematch_in_db // db for info COLLECTED at the beginning of a match
void PlayerStats_PlayerDetail_CheckUpdate();
void PlayerStats_PlayerDetail_Handler(entity fh, entity p, float status);
#endif
-#endif
-#ifndef SOUNDS_ALL_H
-#define SOUNDS_ALL_H
+#pragma once
#include "sound.qh"
-REGISTRY(Sounds, BITS(8))
+REGISTRY(Sounds, BITS(9))
#define Sounds_from(i) _Sounds_from(i, SND_Null)
REGISTER_REGISTRY(Sounds)
SOUND(Null, "misc/null");
#include "all.inc"
#include "all.qc"
-#endif
-#ifndef SOUND_H
-#define SOUND_H
+#pragma once
// negative = SVQC autochannels
// positive = one per entity
} MACRO_END
CLASS(Sound, Object)
- ATTRIB(Sound, m_id, int, 0)
- ATTRIB(Sound, sound_str, string(), func_null)
+ ATTRIB(Sound, m_id, int, 0);
+ ATTRIB(Sound, sound_str, string());
CONSTRUCTOR(Sound, string() path)
{
CONSTRUCT(Sound);
/**/
#define tryext(ext) { string s = strcat(base, "." #ext); if (fexists(strcat("sound/", s))) return s; }
extensions(tryext);
- LOG_WARNINGF("Missing sound: \"%s\"\n", strcat("sound/", base));
+ LOG_WARNF("Missing sound: \"%s\"", strcat("sound/", base));
#undef tryext
#undef extensions
return string_null;
TC(Sound, this);
string s = Sound_fixpath(this);
if (!s) return;
- profile(sprintf("precache_sound(\"%s\")\n", s));
+ profile(sprintf("precache_sound(\"%s\")", s));
precache_sound(s);
}
ENDCLASS(Sound)
-
-#endif
if (!ps) return; // initial connect
PS(this) = NULL;
+ if (ps.m_client != this) return; // don't own state, spectator
ps.m_switchweapon = WEP_Null;
ps.m_weapon = WEP_Null;
ps.m_switchingweapon = WEP_Null;
ps.ps_push(ps, this);
-
- if (ps.m_client != this) return; // don't own state, spectator
+
FOREACH_CLIENT(PS(it) == ps, { PS(it) = NULL; });
- remove(ps);
+ delete(ps);
Inventory_delete(this);
}
GetCvars(this, 0); // get other cvars from player
- if (IS_REAL_CLIENT(this)) { PlayerStats_PlayerBasic_CheckUpdate(this); }
-
// TODO: fold all of these into ClientState
DecodeLevelParms(this);
PlayerScore_Attach(this);
+ PlayerStats_PlayerBasic_CheckUpdate(this);
ClientData_Attach(this);
accuracy_init(this);
entcs_attach(this);
void ClientState_detach(entity this)
{
- remove(CS(this));
+ delete(CS(this));
this._cs = NULL;
GetCvars(this, -1); // free cvars
* Server: instance per client, clients decoupled from players
*/
CLASS(PlayerState, Object)
- ATTRIB(PlayerState, m_client, entity, NULL)
+ ATTRIB(PlayerState, m_client, entity);
CONSTRUCTOR(PlayerState, entity client)
{
CONSTRUCT(PlayerState);
this.m_client = client;
}
- ATTRIB(PlayerState, m_switchingweapon, Weapon, Weapons_from(-1))
- ATTRIB(PlayerState, m_switchweapon, Weapon, Weapons_from(-1))
- ATTRIB(PlayerState, m_weapon, Weapon, Weapons_from(-1))
+ ATTRIB(PlayerState, m_switchingweapon, Weapon, Weapons_from(-1));
+ ATTRIB(PlayerState, m_switchweapon, Weapon, Weapons_from(-1));
+ ATTRIB(PlayerState, m_weapon, Weapon, Weapons_from(-1));
METHOD(PlayerState, ps_push, void(PlayerState this, entity cl))
{
TC(PlayerState, this);
* Server: instance per client
*/
CLASS(ClientState, Object)
- ATTRIB(ClientState, m_client, entity, NULL)
+ ATTRIB(ClientState, m_client, entity);
CONSTRUCTOR(ClientState, entity client)
{
CONSTRUCT(ClientState);
-#ifndef STATS_H
-#define STATS_H
+#pragma once
#ifdef SVQC
#include <server/cl_client.qh>
REGISTER_STAT(CTF_FLAGSTATUS, int)
REGISTER_STAT(ENTRAP_ORB, float)
REGISTER_STAT(ENTRAP_ORB_ALPHA, float)
+REGISTER_STAT(ITEMSTIME, int, autocvar_sv_itemstime)
#ifdef SVQC
int autocvar_g_multijump;
#ifdef SVQC
SPECTATE_COPYFIELD(_STAT(GUNALIGN))
#endif
-
-
-#endif
#if defined(SVQC)
- #include "../server/bot/bot.qh"
- #include "../server/bot/waypoints.qh"
+ #include "../server/bot/api.qh"
#include <server/mutators/all.qh>
#ifdef CSQC
bool autocvar_cl_ghost_items_vehicle = true;
+.vector item_glowmod;
void Item_SetAlpha(entity this)
{
bool veh_hud = (hud && autocvar_cl_ghost_items_vehicle);
if(!veh_hud && (this.ItemStatus & ITS_AVAILABLE))
{
this.alpha = 1;
- this.colormod = this.glowmod = '1 1 1';
+ this.colormod = '1 1 1';
+ this.glowmod = this.item_glowmod;
}
else
{
if(sf & ISF_MODEL)
{
this.drawmask = MASK_NORMAL;
- this.move_movetype = MOVETYPE_TOSS;
+ set_movetype(this, MOVETYPE_TOSS);
if (isnew) IL_PUSH(g_drawables, this);
this.draw = ItemDraw;
this.solid = SOLID_TRIGGER;
else
{
this.draw = ItemDraw;
- LOG_TRACE("Simple item requested for ", _fn, " but no model exists for it\n");
+ LOG_TRACE("Simple item requested for ", _fn, " but no model exists for it");
}
}
if(this.mdl == "")
- LOG_TRACE("^1WARNING!^7 this.mdl is unset for item ", this.classname, ", tell tZork about this!\n");
+ LOG_TRACE("^1WARNING!^7 this.mdl is unset for item ", this.classname, ", tell tZork about this!");
precache_model(this.mdl);
_setmodel(this, this.mdl);
}
if(sf & ISF_COLORMAP)
+ {
this.colormap = ReadShort();
+ this.item_glowmod_x = ReadByte() / 255.0;
+ this.item_glowmod_y = ReadByte() / 255.0;
+ this.item_glowmod_z = ReadByte() / 255.0;
+ }
if(sf & ISF_DROP)
{
this.gravity = 1;
this.pushable = true;
//this.angles = '0 0 0';
- this.move_movetype = MOVETYPE_TOSS;
+ set_movetype(this, MOVETYPE_TOSS);
this.velocity_x = ReadCoord();
this.velocity_y = ReadCoord();
this.velocity_z = ReadCoord();
WriteShort(MSG_ENTITY, this.fade_start);
if(this.mdl == "")
- LOG_TRACE("^1WARNING!^7 this.mdl is unset for item ", this.classname, "exspect a crash just aboute now\n");
+ LOG_TRACE("^1WARNING!^7 this.mdl is unset for item ", this.classname, "expect a crash just about now");
WriteString(MSG_ENTITY, this.mdl);
}
if(sf & ISF_COLORMAP)
+ {
WriteShort(MSG_ENTITY, this.colormap);
+ WriteByte(MSG_ENTITY, this.glowmod.x * 255.0);
+ WriteByte(MSG_ENTITY, this.glowmod.y * 255.0);
+ WriteByte(MSG_ENTITY, this.glowmod.z * 255.0);
+ }
if(sf & ISF_DROP)
{
//setmodel(e, "null");
e.solid = SOLID_NOT;
e.colormod = '0 0 0';
- e.glowmod = e.colormod;
+ //e.glowmod = e.colormod;
e.spawnshieldtime = 1;
e.ItemStatus &= ~ITS_AVAILABLE;
}}
{
if (ITEM_TOUCH_NEEDKILL())
{
- remove(this);
+ delete(this);
return;
}
}
_sound (toucher, (this.itemdef.instanceOfPowerup ? CH_TRIGGER_SINGLE : CH_TRIGGER), (this.item_pickupsound ? this.item_pickupsound : Sound_fixpath(this.item_pickupsound_ent)), VOL_BASE, ATTEN_NORM);
if (this.classname == "droppedweapon")
- remove (this);
+ delete (this);
else if (this.spawnshieldtime)
{
entity e;
if(this.effects & EF_NODRAW)
{
// marker for item team search
- LOG_TRACE("Initializing item team ", ftos(this.team), "\n");
+ LOG_TRACE("Initializing item team ", ftos(this.team));
RandomSelection_Init();
FOREACH_ENTITY_FLOAT(team, this.team,
{
{
if(wasfreed(this) || !this) { return; }
Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
- remove(this);
+ delete(this);
}
// pickup evaluation functions
if(MUTATOR_CALLHOOK(FilterItem, this)) // error means we do not want the item
{
startitem_failed = true;
- remove(this);
+ delete(this);
return;
}
if (trace_dpstartcontents & DPCONTENTS_NODROP)
{
startitem_failed = true;
- remove(this);
+ delete(this);
return;
}
}
if(!have_pickup_item(this))
{
startitem_failed = true;
- remove (this);
+ delete (this);
return;
}
// why not flags & fl_item?
FOREACH_ENTITY_RADIUS(this.origin, 3, it.is_item, {
LOG_TRACE("XXX Found duplicated item: ", itemname, vtos(this.origin));
- LOG_TRACE(" vs ", it.netname, vtos(it.origin), "\n");
+ LOG_TRACE(" vs ", it.netname, vtos(it.origin));
error("Mapper sucks.");
});
this.is_item = true;
this.gravity = 1;
if (!(this.spawnflags & 1024))
this.ItemStatus |= ITS_ANIMATE1;
- this.ItemStatus |= ISF_COLORMAP;
+ this.SendFlags |= ISF_COLORMAP;
}
this.state = 0;
if (MUTATOR_CALLHOOK(Item_Spawn, this))
{
startitem_failed = true;
- remove(this);
+ delete(this);
return;
}
}
if(actor.classname == "droppedweapon")
{
EXACTTRIGGER_TOUCH(this, trigger);
- remove(actor);
+ delete(actor);
return;
}
FOREACH_ENTITY_ENT(enemy, actor,
{
if(it.classname == "droppedweapon")
- remove(it);
+ delete(it);
});
if(GiveItems(actor, 0, tokenize_console(this.netname)))
-#ifndef T_ITEMS_H
-#define T_ITEMS_H
+#pragma once
const int AMMO_COUNT = 4; // amount of ammo types to show in the inventory panel
float GiveItems(entity e, float beginarg, float endarg);
#endif
-#endif
-#ifndef TEAMS_H
-#define TEAMS_H
+#pragma once
#ifdef TEAMNUMBERS_THAT_ARENT_STUPID
const int NUM_TEAM_1 = 1; // red
// safe team comparisons
#define SAME_TEAM(a,b) (teamplay ? (a.team == b.team) : (a == b))
#define DIFF_TEAM(a,b) (teamplay ? (a.team != b.team) : (a != b))
-
-#endif
#include <server/g_subs.qh>
#include <server/g_damage.qh>
-#include <server/bot/bot.qh>
+#include <server/bot/api.qh>
#include <common/csqcmodel_settings.qh>
#include <lib/csqcmodel/sv_model.qh>
#include <server/weapons/common.qh>
-#ifndef TRIGGERS_FUNC_BREAKABLE_H
-#define TRIGGERS_FUNC_BREAKABLE_H
+#pragma once
#ifdef SVQC
spawnfunc(func_breakable);
#endif
-
-#endif
IL_PUSH(g_drawables, this);
this.drawmask = MASK_NORMAL;
- this.move_movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
this.model = "";
this.solid = SOLID_TRIGGER;
this.move_time = time;
break;
}
}
- LOG_TRACE("\n");
+ LOG_TRACE("");
// collect health, targetname, message, size
cmins = this.absmin;
this.SUB_LTIME = ReadCoord();
this.solid = SOLID_BSP;
- this.move_movetype = MOVETYPE_PUSH;
+ set_movetype(this, MOVETYPE_PUSH);
this.use = door_use;
LinkDoors(this);
door_init_startopen(this);
this.move_time = time;
- this.move_movetype = MOVETYPE_PUSH;
+ set_movetype(this, MOVETYPE_PUSH);
}
if(sf & SF_TRIGGER_RESET)
-#ifndef TRIGGERS_FUNC_INCLUDE_H
-#define TRIGGERS_FUNC_INCLUDE_H
+#pragma once
#include "door.qh"
#include "ladder.qh"
#include "train.qh"
-
-#endif
this.classname = "plat";
this.solid = SOLID_BSP;
- this.move_movetype = MOVETYPE_PUSH;
+ set_movetype(this, MOVETYPE_PUSH);
this.drawmask = MASK_NORMAL;
this.draw = plat_draw;
if (isnew) IL_PUSH(g_drawables, this);
plat_reset(this); // also called here
- this.move_movetype = MOVETYPE_PUSH;
+ set_movetype(this, MOVETYPE_PUSH);
this.move_time = time;
plat_spawn_inside_trigger(this);
this.classname = "func_train";
this.solid = SOLID_BSP;
- this.move_movetype = MOVETYPE_PUSH;
+ set_movetype(this, MOVETYPE_PUSH);
this.drawmask = MASK_NORMAL;
this.draw = train_draw;
if (isnew) IL_PUSH(g_drawables, this);
// but we will need these
train_next(this);
- this.move_movetype = MOVETYPE_PUSH;
+ set_movetype(this, MOVETYPE_PUSH);
this.move_time = time;
}
-#ifndef TRIGGERS_INCLUDE_H
-#define TRIGGERS_INCLUDE_H
+#pragma once
// some required common stuff
#ifdef CSQC
// trigger
#include "trigger/include.qh"
-
-#endif
}
dst.solid = SOLID_NOT; // solid doesn't work with attachment
- remove(this);
+ delete(this);
}
else
{
follow_sameorigin(dst, src);
}
- remove(this);
+ delete(this);
}
}
}
// otherwise, something is fishy...
- remove(trigger);
+ delete(trigger);
objerror(this, "plat_spawn_inside_trigger: platform has odd size or lip, can't spawn");
}
-#ifndef PLATFORMS_H
-#define PLATFORMS_H
+#pragma once
.float dmgtime2;
const float PLAT_LOW_TRIGGER = 1;
.float dmg;
-
-#endif
else
{
// remove
- remove (ent);
+ delete (ent);
}
}
// derivative: delta + 2 * delta2 (e.g. for angle positioning)
entity own = this.owner;
SUB_THINK(own, this.think1);
- remove(this);
+ delete(this);
SUB_THUNK(own)(own);
}
}
-#ifndef SUBS_H
-#define SUBS_H
+#pragma once
#define SUB_ANGLES(s) (s).angles
#define SUB_VELOCITY velocity
.float max_health; // players maximum health is stored here
#endif
-
-#endif
-#ifndef TRIGGERS_TARGET_INCLUDE_H
-#define TRIGGERS_TARGET_INCLUDE_H
+#pragma once
#include "music.qh"
-
-#endif
_sound(e, CH_BGM_SINGLE, e.noise, 0, ATTEN_NONE);
if(getsoundtime(e, CH_BGM_SINGLE) < 0)
{
- LOG_TRACEF("Cannot initialize sound %s\n", e.noise);
+ LOG_TRACEF("Cannot initialize sound %s", e.noise);
strunzone(e.noise);
e.noise = string_null;
}
_sound(this, CH_BGM_SINGLE, this.noise, 0, ATTEN_NONE);
if(getsoundtime(this, CH_BGM_SINGLE) < 0)
{
- LOG_TRACEF("Cannot initialize sound %s\n", this.noise);
+ LOG_TRACEF("Cannot initialize sound %s", this.noise);
strunzone(this.noise);
this.noise = string_null;
}
-#ifndef TARGET_MUSIC_H
-#define TARGET_MUSIC_H
+#pragma once
.float lifetime;
#elif defined(SVQC)
void target_music_kill();
#endif
-
-#endif
else if(this.spawnflags & 1) // LOOPED_ON
{
ambientsound (this.origin, this.noise, VOL_BASE * this.volume, this.atten);
- remove(this);
+ delete(this);
}
else if(this.spawnflags & 2) // LOOPED_OFF
{
{
// Quake/Nexuiz fallback
ambientsound (this.origin, this.noise, VOL_BASE * this.volume, this.atten);
- remove(this);
+ delete(this);
}
}
#endif
-#ifndef T_TELEPORTERS_H
-#define T_TELEPORTERS_H
+#pragma once
.entity pusher;
const float TELEPORT_FLAG_SOUND = 1;
if(head.isplayermodel) \
if(boxesoverlap(deathmin, deathmax, head.absmin, head.absmax))
#endif
-
-#endif
void gamestart_use(entity this, entity actor, entity trigger)
{
SUB_UseTargets(this, this, trigger);
- remove(this);
+ delete(this);
}
void gamestart_use_this(entity this)
{
UpdateCSQCProjectile(own);
own.gravity = own.trigger_gravity_check.gravity;
- remove(own.trigger_gravity_check);
+ delete(own.trigger_gravity_check);
}
else
backtrace("Removing a trigger_gravity_check with no valid owner");
if(this.owner.trigger_gravity_check == this)
trigger_gravity_remove(this.owner);
else
- remove(this);
+ delete(this);
return;
}
else
if(!targ)
{
objerror(this, "trigger_force without a (valid) .target!\n");
- remove(this);
+ delete(this);
return;
}
-#ifndef TRIGGER_IMPULSE_H
-#define TRIGGER_IMPULSE_H
+#pragma once
// tZorks trigger impulse / gravity
.float radius;
.float falloff;
.float strength;
.float lastpushtime;
-
-#endif
-#ifndef TRIGGERS_TRIGGER_INCLUDE_H
-#define TRIGGERS_TRIGGER_INCLUDE_H
+#pragma once
#include "multi.qh"
#include "jumppads.qh"
#include "keylock.qh"
#include "impulse.qh"
#include "viewloc.qh"
-
-#endif
switch(toucher.move_movetype)
{
case MOVETYPE_FLY:
- toucher.move_movetype = MOVETYPE_TOSS;
+ set_movetype(toucher, MOVETYPE_TOSS);
toucher.gravity = 1;
break;
case MOVETYPE_BOUNCEMISSILE:
- toucher.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(toucher, MOVETYPE_BOUNCE);
toucher.gravity = 1;
break;
}
if (toucher.flags & FL_PROJECTILE)
{
toucher.angles = vectoangles (toucher.velocity);
+ toucher.com_phys_gravity_factor = 1;
switch(toucher.move_movetype)
{
case MOVETYPE_FLY:
tracetoss(e, e);
if(e.move_movetype == MOVETYPE_NONE)
waypoint_spawnforteleporter(this, trace_endpos, vlen(trace_endpos - org) / vlen(e.velocity));
- remove(e);
+ delete(e);
#endif
}
e.velocity = this.movedir;
tracetoss(e, e);
waypoint_spawnforteleporter(this, trace_endpos, vlen(trace_endpos - org) / vlen(e.velocity));
- remove(e);
+ delete(e);
}
trigger_push_link(this);
-#ifndef T_JUMPPADS_H
-#define T_JUMPPADS_H
+#pragma once
const float PUSH_ONCE = 1;
const float PUSH_SILENT = 2;
spawnfunc(info_notnull);
spawnfunc(target_position);
#endif
-#endif
{
entity t;
for(t = NULL; (t = find(t, targetname, s)); )
- remove(t);
+ delete(t);
}
void trigger_keylock_touch(entity this, entity toucher)
if(this.killtarget)
trigger_keylock_kill(this.killtarget);
- remove(this);
+ delete(this);
}
}
*/
spawnfunc(trigger_keylock)
{
- if(!this.itemkeys) { remove(this); return; }
+ if(!this.itemkeys) { delete(this); return; }
// set unlocked message
if(this.message == "")
// handle normal trigger features
multi_touch(this, toucher);
- remove(this);
+ delete(this);
}
/*QUAKED trigger_secret (.5 .5 .5) ?
-#ifndef SECRET_H
-#define SECRET_H
+#pragma once
#ifdef SVQC
/**
*/
void secrets_setstatus(entity this);
#endif
-#endif
if(this.health <= 0)
{
this.owner.in_swamp = 0;
- remove(this);
+ delete(this);
//centerprint(this.owner,"Killing slug...\n");
return;
}
-#ifndef TRIGGER_SWAMP_H
-#define TRIGGER_SWAMP_H
+#pragma once
.float swamp_interval; //Hurt players in swamp with this interval
.float swamp_slowdown; //Players in swamp get slowd down by this mutch 0-1 is slowdown 1-~ is speedup (!?)
.float in_swamp; // bool
.entity swampslug; // Uses this to release from swamp ("untouch" fix)
-
-#endif
break;
}
- if(!this.enemy) { LOG_INFO("^1FAIL!\n"); remove(this); return; }
+ if(!this.enemy) { LOG_INFO("^1FAIL!\n"); delete(this); return; }
if(!this.goalentity)
this.goalentity = this.enemy; // make them match so CSQC knows what to do
spawnfunc(trigger_viewlocation)
{
// we won't check target2 here yet, as it may not even need to exist
- if(this.target == "") { LOG_INFO("^1FAIL!\n"); remove(this); return; }
+ if(this.target == "") { LOG_INFO("^1FAIL!\n"); delete(this); return; }
EXACTTRIGGER_INIT;
InitializeEntity(this, viewloc_init, INITPRIO_FINDTARGET);
-#ifndef T_VIEWLOC_H
-#define T_VIEWLOC_H
+#pragma once
.entity viewloc;
.entity enemy;
.vector movedir;
#endif
-
-#endif
void DelayThink(entity this)
{
SUB_UseTargets (this, this.enemy, NULL);
- remove(this);
+ delete(this);
}
void FixSize(entity e)
if (s != "")
{
for(entity t = NULL; (t = find(t, targetname, s)); )
- remove(t);
+ delete(t);
}
#endif
-#ifndef TRIGGERS_H
-#define TRIGGERS_H
+#pragma once
const float SF_TRIGGER_INIT = 1;
const float SF_TRIGGER_UPDATE = 2;
const int ACTIVE_BUSY = 2;
const int ACTIVE_TOGGLE = 3;
#endif
-
-#endif
-#ifndef TURRETS_ALL_H
-#define TURRETS_ALL_H
+#pragma once
#include <common/command/all.qh>
#include "config.qh"
REGISTER_TURRET(Null, NEW(Turret));
#include "turret/_mod.inc"
-
-#endif
{
this.enemy = find(NULL, targetname, this.target);
if(this.enemy == NULL)
- LOG_TRACE("A turret_checkpoint faild to find its target!\n");
+ LOG_TRACE("A turret_checkpoint faild to find its target!");
}
//setthink(this, turret_checkpoint_think);
//this.nextthink = time + tc_acum + 0.25;
void turret_remove(entity this)
{
- remove(this.tur_head);
+ delete(this.tur_head);
//remove(this.enemy);
this.tur_head = NULL;
}
);
}
-void turret_construct(entity this)
+void turret_construct(entity this, bool isnew)
{
entity tur = get_turretinfo(this.m_id);
this.tur_head.drawmask = MASK_NORMAL;
this.anim_start_time = 0;
this.draw2d = turret_draw2d;
- IL_PUSH(g_drawables_2d, this);
this.maxdistance = autocvar_g_waypointsprite_turrets_maxdist;
this.teamradar_color = '1 0 0';
this.alpha = 1;
+ if(isnew)
+ {
+ IL_PUSH(g_drawables, this);
+ IL_PUSH(g_drawables_2d, this);
+ }
+
tur.tr_setup(tur, this);
}
if(time >= this.nextthink)
{
turret_gibboom(this);
- remove(this);
+ delete(this);
}
}
else
{
this.alpha = bound(0, this.nextthink - time, 1);
if(this.alpha < ALPHA_MIN_VISIBLE)
- remove(this);
+ delete(this);
}
}
this.angles_x = ReadAngle();
this.angles_y = ReadAngle();
- turret_construct(this);
+ turret_construct(this, isnew);
this.colormap = 1024;
this.glowmod = '0 1 1';
this.tur_head.colormap = this.colormap;
-#ifndef TURRETS_CONFIG_H
-#define TURRETS_CONFIG_H
+#pragma once
#ifdef SVQC
#endif
-
-#endif
{
tur.tr_death(tur, this);
- remove(this.tur_head);
- remove(this);
+ delete(this.tur_head);
+ delete(this);
}
else
{
#else
RadiusDamage (this, this.realowner, this.owner.shot_dmg, 0, this.owner.shot_radius, this, NULL, this.owner.shot_force, this.totalfrags, NULL);
#endif
- remove(this);
+ delete(this);
}
void turret_projectile_touch(entity this, entity toucher)
proj.nextthink = time + 9;
set_movetype(proj, MOVETYPE_FLYMISSILE);
proj.velocity = normalize(actor.tur_shotdir_updated + randomvec() * actor.shot_spread) * actor.shot_speed;
- proj.flags = FL_PROJECTILE;
+ proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.enemy = actor.enemy;
proj.totalfrags = _death;
PROJECTILE_MAKETRIGGER(proj);
*/
#ifdef TURRET_DEBUG_TARGETSELECT
- LOG_TRACE("Target:",e_target.netname," is a valid target for ",e_turret.netname,"\n");
+ LOG_TRACE("Target:",e_target.netname," is a valid target for ",e_turret.netname);
#endif
return 1;
*/
void turret_use(entity this, entity actor, entity trigger)
{
- LOG_TRACE("Turret ",this.netname, " used by ", actor.classname, "\n");
+ LOG_TRACE("Turret ",this.netname, " used by ", actor.classname);
this.team = actor.team;
if (autocvar_g_turrets_reloadcvars == 1)
{
- FOREACH_ENTITY_FLAGS(turret_flags, TUR_FLAG_ISTURRET, {
+ IL_EACH(g_turrets, true,
+ {
load_unit_settings(it, true);
Turret tur = get_turretinfo(it.m_id);
tur.tr_think(tur, it);
// if tur_head exists, we can assume this turret re-spawned
if(!this.tur_head) {
tur.tr_precache(tur);
+ IL_PUSH(g_turrets, this);
}
entity e = find(NULL, classname, "turret_manager");
this.tur_head.owner = this;
this.tur_head.takedamage = DAMAGE_NO;
this.tur_head.solid = SOLID_NOT;
- this.tur_head.move_movetype = this.move_movetype;
+ set_movetype(this.tur_head, this.move_movetype);
if(!this.tur_defend)
if(this.target != "")
if (this.tur_defend == NULL)
{
this.target = "";
- LOG_TRACE("Turret has invalid defendpoint!\n");
+ LOG_TRACE("Turret has invalid defendpoint!");
}
}
-#ifndef SV_TURRETS_H
-#define SV_TURRETS_H
+#pragma once
entity turret_projectile(entity actor, Sound _snd, float _size, float _health, float _death, float _proj_type, float _cull, float _cli_anim);
void turret_projectile_explode(entity this);
float tvt_thadf; // turret head angle diff float, updated by a successful call to turret_validate_target
float tvt_tadf; // turret angle diff float, updated by a successful call to turret_validate_target
float tvt_dist; // turret distance, updated by a successful call to turret_validate_target
-
-#endif
*/
spawnfunc(turret_targettrigger)
{
- if(!autocvar_g_turrets) { remove(this); return; }
+ if(!autocvar_g_turrets) { delete(this); return; }
InitTrigger(this);
-#ifndef TURRET_H
-#define TURRET_H
+#pragma once
#include <common/weapons/all.qh>
CLASS(Turret, Object)
- ATTRIB(Turret, m_id, int, 0)
+ ATTRIB(Turret, m_id, int, 0);
/** short name */
- ATTRIB(Turret, netname, string, string_null)
+ ATTRIB(Turret, netname, string);
/** human readable name */
- ATTRIB(Turret, turret_name, string, _("Turret"))
+ ATTRIB(Turret, turret_name, string, _("Turret"));
/** currently a copy of the model */
- ATTRIB(Turret, mdl, string, string_null)
+ ATTRIB(Turret, mdl, string);
/** full name of model */
- ATTRIB(Turret, model, string, string_null)
+ ATTRIB(Turret, model, string);
/** full name of tur_head model */
- ATTRIB(Turret, head_model, string, string_null)
+ ATTRIB(Turret, head_model, string);
- ATTRIB(Turret, spawnflags, int, 0)
+ ATTRIB(Turret, spawnflags, int, 0);
/** turret hitbox size */
- ATTRIB(Turret, mins, vector, '-0 -0 -0')
+ ATTRIB(Turret, mins, vector, '-0 -0 -0');
/** turret hitbox size */
- ATTRIB(Turret, maxs, vector, '0 0 0')
+ ATTRIB(Turret, maxs, vector, '0 0 0');
METHOD(Turret, display, void(Turret this, void(string name, string icon) returns)) {
returns(this.turret_name, string_null);
METHOD(Turret, tr_precache, void(Turret this)) {
}
- ATTRIB(Turret, m_weapon, Weapon, WEP_Null)
+ ATTRIB(Turret, m_weapon, Weapon);
#ifdef SVQC
/** (SERVER) called when turret attacks */
METHOD(Turret, tr_attack, void(Turret this, entity it)) {
const int TNSF_ANIM = 128;
const int TNSF_FULL_UPDATE = 16777215;
-
-#endif
movelib_brake_simple(this, (autocvar_g_turrets_unit_ewheel_speed_stop));
}
-spawnfunc(turret_ewheel) { if(!turret_initialize(this, TUR_EWHEEL)) remove(this); }
+spawnfunc(turret_ewheel) { if(!turret_initialize(this, TUR_EWHEEL)) delete(this); }
METHOD(EWheel, tr_think, void(EWheel thistur, entity it))
{
e = find(NULL, targetname, it.target);
if (!e)
{
- LOG_TRACE("Initital waypoint for ewheel does NOT exsist, fix your map!\n");
+ LOG_TRACE("Initital waypoint for ewheel does NOT exsist, fix your map!");
it.target = "";
}
if (e.classname != "turret_checkpoint")
- LOG_TRACE("Warning: not a turrret path\n");
+ LOG_TRACE("Warning: not a turrret path");
else
{
METHOD(EWheel, tr_setup, void(EWheel this, entity it))
{
it.gravity = 1;
- it.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(it, MOVETYPE_BOUNCE);
it.move_time = time;
it.draw = ewheel_draw;
}
if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
if (isPlayer) {
turret_initparams(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, SND_EWheelAttack_FIRE, CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_EWheelAttack_FIRE, CH_WEAPON_B, 0);
actor.tur_shotdir_updated = w_shotdir;
actor.tur_shotorg = w_shotorg;
actor.tur_head = actor;
#ifdef SVQC
-spawnfunc(turret_flac) { if (!turret_initialize(this, TUR_FLAC)) remove(this); }
+spawnfunc(turret_flac) { if (!turret_initialize(this, TUR_FLAC)) delete(this); }
METHOD(Flac, tr_setup, void(Flac this, entity it))
{
if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
if (isPlayer) {
turret_initparams(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, SND_FlacAttack_FIRE, CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_FlacAttack_FIRE, CH_WEAPON_B, 0);
actor.tur_shotdir_updated = w_shotdir;
actor.tur_shotorg = w_shotorg;
actor.tur_head = actor;
#else
RadiusDamage (this, this.realowner, this.owner.shot_dmg, this.owner.shot_dmg, this.owner.shot_radius, this, NULL, this.owner.shot_force, this.totalfrags, NULL);
#endif
- remove(this);
+ delete(this);
}
#endif
return true;
}
-spawnfunc(turret_fusionreactor) { if (!turret_initialize(this, TUR_FUSIONREACTOR)) remove(this); }
+spawnfunc(turret_fusionreactor) { if (!turret_initialize(this, TUR_FUSIONREACTOR)) delete(this); }
METHOD(FusionReactor, tr_attack, void(FusionReactor this, entity it))
{
#ifdef SVQC
-spawnfunc(turret_hellion) { if (!turret_initialize(this, TUR_HELLION)) remove(this); }
+spawnfunc(turret_hellion) { if (!turret_initialize(this, TUR_HELLION)) delete(this); }
METHOD(Hellion, tr_think, void(Hellion thistur, entity it))
{
if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
if (isPlayer) {
turret_initparams(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, SND_HellionAttack_FIRE, CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_HellionAttack_FIRE, CH_WEAPON_B, 0);
actor.tur_shotdir_updated = w_shotdir;
actor.tur_shotorg = w_shotorg;
actor.tur_head = actor;
te_explosion (missile.origin);
setthink(missile, turret_hellion_missile_think);
missile.nextthink = time;
- missile.flags = FL_PROJECTILE;
missile.max_health = time + 9;
missile.tur_aimpos = randomvec() * 128;
missile.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_GUIDED_HEAT;
.float atime;
#endif
-spawnfunc(turret_hk) { if(!turret_initialize(this, TUR_HK)) remove(this); }
+spawnfunc(turret_hk) { if(!turret_initialize(this, TUR_HK)) delete(this); }
METHOD(HunterKiller, tr_think, void(HunterKiller thistur, entity it))
{
if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
if (isPlayer) {
turret_initparams(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, SND_HunterKillerAttack_FIRE, CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_HunterKillerAttack_FIRE, CH_WEAPON_B, 0);
actor.tur_shotdir_updated = w_shotdir;
actor.tur_shotorg = w_shotorg;
actor.tur_head = actor;
#ifdef SVQC
-spawnfunc(turret_machinegun) { if (!turret_initialize(this, TUR_MACHINEGUN)) remove(this); }
+spawnfunc(turret_machinegun) { if (!turret_initialize(this, TUR_MACHINEGUN)) delete(this); }
METHOD(MachineGunTurret, tr_setup, void(MachineGunTurret this, entity it))
{
#ifdef SVQC
-void W_MachineGun_MuzzleFlash(entity actor);
+void W_MachineGun_MuzzleFlash(entity actor, .entity weaponentity);
SOUND(MachineGunTurretAttack_FIRE, W_Sound("electro_fire"));
METHOD(MachineGunTurretAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(machinegun, sustained_refire))) {
if (isPlayer) {
turret_initparams(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, SND_MachineGunTurretAttack_FIRE, CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_MachineGunTurretAttack_FIRE, CH_WEAPON_B, 0);
actor.tur_shotdir_updated = w_shotdir;
actor.tur_shotorg = w_shotorg;
actor.tur_head = actor;
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, w_ready);
}
fireBullet (actor, actor.tur_shotorg, actor.tur_shotdir_updated, actor.shot_spread, 0, actor.shot_dmg, actor.shot_force, DEATH_TURRET_MACHINEGUN.m_id, 0);
- W_MachineGun_MuzzleFlash(actor);
- setattachment(actor.muzzle_flash, actor.tur_head, "tag_fire");
+ W_MachineGun_MuzzleFlash(actor, weaponentity);
+ setattachment(actor.(weaponentity).muzzle_flash, actor.tur_head, "tag_fire");
}
}
#ifdef SVQC
-spawnfunc(turret_mlrs) { if (!turret_initialize(this, TUR_MLRS)) remove(this); }
+spawnfunc(turret_mlrs) { if (!turret_initialize(this, TUR_MLRS)) delete(this); }
METHOD(MLRSTurret, tr_think, void(MLRSTurret thistur, entity it))
{
it.tur_head.frame = bound(0, 6 - floor(0.1 + it.ammo / it.shot_dmg), 6);
if(it.tur_head.frame < 0)
{
- LOG_TRACE("ammo:",ftos(it.ammo),"\n");
- LOG_TRACE("shot_dmg:",ftos(it.shot_dmg),"\n");
+ LOG_TRACE("ammo:",ftos(it.ammo));
+ LOG_TRACE("shot_dmg:",ftos(it.shot_dmg));
}
}
METHOD(MLRSTurret, tr_setup, void(MLRSTurret this, entity it))
if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(machinegun, sustained_refire))) {
if (isPlayer) {
turret_initparams(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, SND_MLRSTurretAttack_FIRE, CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_MLRSTurretAttack_FIRE, CH_WEAPON_B, 0);
actor.tur_shotdir_updated = w_shotdir;
actor.tur_shotorg = w_shotorg;
actor.tur_head = actor;
#ifdef SVQC
-spawnfunc(turret_phaser) { if (!turret_initialize(this, TUR_PHASER)) remove(this); }
+spawnfunc(turret_phaser) { if (!turret_initialize(this, TUR_PHASER)) delete(this); }
.int fireflag;
if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
if (isPlayer) {
turret_initparams(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, SND_PhaserTurretAttack_FIRE, CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_PhaserTurretAttack_FIRE, CH_WEAPON_B, 0);
actor.tur_shotdir_updated = w_shotdir;
actor.tur_shotorg = w_shotorg;
actor.tur_head = actor;
this.owner.fireflag = 2;
this.owner.tur_head.frame = 10;
sound (this, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM);
- remove(this);
+ delete(this);
return;
}
#ifdef SVQC
-spawnfunc(turret_plasma) { if (!turret_initialize(this, TUR_PLASMA)) remove(this); }
+spawnfunc(turret_plasma) { if (!turret_initialize(this, TUR_PLASMA)) delete(this); }
METHOD(PlasmaTurret, tr_attack, void(PlasmaTurret this, entity it))
{
#ifdef SVQC
-spawnfunc(turret_plasma_dual) { if (!turret_initialize(this, TUR_PLASMA_DUAL)) remove(this); }
+spawnfunc(turret_plasma_dual) { if (!turret_initialize(this, TUR_PLASMA_DUAL)) delete(this); }
METHOD(DualPlasmaTurret, tr_attack, void(DualPlasmaTurret thistur, entity it))
{
if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
if (isPlayer) {
turret_initparams(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, SND_PlasmaAttack_FIRE, CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_PlasmaAttack_FIRE, CH_WEAPON_B, 0);
actor.tur_shotdir_updated = w_shotdir;
actor.tur_shotorg = w_shotorg;
actor.tur_head = actor;
#ifdef SVQC
-spawnfunc(turret_tesla) { if (!turret_initialize(this, TUR_TESLA)) remove(this); }
+spawnfunc(turret_tesla) { if (!turret_initialize(this, TUR_TESLA)) delete(this); }
METHOD(TeslaCoil, tr_think, void(TeslaCoil thistur, entity it))
{
if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
if (isPlayer) {
turret_initparams(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, SND_TeslaCoilTurretAttack_FIRE, CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_TeslaCoilTurretAttack_FIRE, CH_WEAPON_B, 0);
actor.tur_shotdir_updated = w_shotdir;
actor.tur_shotorg = w_shotorg;
actor.tur_head = actor;
actor.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK;
entity t = toast(actor, e,r,d);
- remove(e);
+ delete(e);
if (t == NULL) return;
void walker_rocket_explode(entity this)
{
RadiusDamage (this, this.owner, (autocvar_g_turrets_unit_walker_rocket_damage), 0, (autocvar_g_turrets_unit_walker_rocket_radius), this, NULL, (autocvar_g_turrets_unit_walker_rocket_force), DEATH_TURRET_WALK_ROCKET.m_id, NULL);
- remove (this);
+ delete (this);
}
void walker_rocket_touch(entity this, entity toucher)
rocket.velocity = normalize((v_forward + v_up * 0.5) + (randomvec() * 0.2)) * (autocvar_g_turrets_unit_walker_rocket_speed);
rocket.angles = vectoangles(rocket.velocity);
settouch(rocket, walker_rocket_touch);
- rocket.flags = FL_PROJECTILE;
+ rocket.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, rocket);
rocket.solid = SOLID_BBOX;
rocket.max_health = time + 9;
rocket.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_GUIDED_HEAT;
#endif
}
-spawnfunc(turret_walker) { if(!turret_initialize(this, TUR_WALKER)) remove(this); }
+spawnfunc(turret_walker) { if(!turret_initialize(this, TUR_WALKER)) delete(this); }
METHOD(WalkerTurret, tr_think, void(WalkerTurret thistur, entity it))
{
e = find(NULL, targetname, it.target);
if (!e)
{
- LOG_TRACE("Initital waypoint for walker does NOT exsist, fix your map!\n");
+ LOG_TRACE("Initital waypoint for walker does NOT exsist, fix your map!");
it.target = "";
}
if (e.classname != "turret_checkpoint")
- LOG_TRACE("Warning: not a turrret path\n");
+ LOG_TRACE("Warning: not a turrret path");
else
{
#ifdef WALKER_FANCYPATHING
METHOD(WalkerTurret, tr_setup, void(WalkerTurret this, entity it))
{
it.gravity = 1;
- it.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(it, MOVETYPE_BOUNCE);
it.move_time = time;
it.draw = walker_draw;
}
if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
if (isPlayer) {
turret_initparams(actor);
- W_SetupShot_Dir(actor, v_forward, false, 0, SND_WalkerTurretAttack_FIRE, CH_WEAPON_B, 0);
+ W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_WalkerTurretAttack_FIRE, CH_WEAPON_B, 0);
actor.tur_shotdir_updated = w_shotdir;
actor.tur_shotorg = w_shotorg;
actor.tur_head = actor;
{
if(!this.tur_head)
{
- LOG_DEBUG("Call to turret_tag_fire_update with this.tur_head missing!\n");
+ LOG_DEBUG("Call to turret_tag_fire_update with this.tur_head missing!");
this.tur_shotorg = '0 0 0';
return false;
}
-#ifndef TURRETS_UTIL_H
-#define TURRETS_UTIL_H
+#pragma once
float shortangle_f(float ang1, float ang2);
float anglemods(float v);
vector angleofs(entity from, entity to);
vector angleofs3(vector from, vector from_a, entity to);
void FireImoBeam(entity this, vector start, vector end, vector smin, vector smax, float bforce, float f_dmg, float f_velfactor, float deathtype);
-
-#endif
return (p * 0x1000) + (y * 0x80) + len;
}
-void compressShortVector_init()
+STATIC_INIT(compressShortVector)
{
float l = 1;
float f = pow(2, 1/8);
mi_min = mi;
mi_max = ma;
- MapInfo_Get_ByName(mi_shortname, 0, 0);
+ MapInfo_Get_ByName(mi_shortname, 0, NULL);
if(MapInfo_Map_mins.x < MapInfo_Map_maxs.x)
{
mi_min = MapInfo_Map_mins;
if (!(tmp_cvar || tmp_value))
{
- LOG_TRACE("Error: Invalid usage of cvar_settemp(string, string); !\n");
+ LOG_TRACE("Error: Invalid usage of cvar_settemp(string, string); !");
return 0;
}
cvar_set(it.netname, it.message);
strunzone(it.netname);
strunzone(it.message);
- remove(it);
+ delete(it);
++j;
}
else
if(cvar_type(e.netname))
{
cvar_set(e.netname, e.message);
- remove(e);
+ delete(e);
++j;
}
else
return strcat(substring(theText, 0, textLengthUpToLength(theText, maxWidth - tw("..."), tw)), "...");
}
-float isGametypeInFilter(float gt, float tp, float ts, string pattern)
+float isGametypeInFilter(Gametype gt, float tp, float ts, string pattern)
{
string subpattern, subpattern2, subpattern3, subpattern4;
subpattern = strcat(",", MapInfo_Type_ToString(gt), ",");
-#ifndef COMMON_UTIL_H
-#define COMMON_UTIL_H
+#pragma once
#ifndef MENUQC
string ScoreString(float vflags, float value);
-void compressShortVector_init();
vector decompressShortVector(float data);
float compressShortVector(vector vec);
string getWrappedLine(float w, vector size, textLengthUpToWidth_widthFunction_t tw);
string getWrappedLineLen(float w, textLengthUpToLength_lenFunction_t tw);
-float isGametypeInFilter(float gt, float tp, float ts, string pattern);
+float isGametypeInFilter(entity gt, float tp, float ts, string pattern);
string swapwords(string str, float i, float j);
string shufflewords(string str);
void execute_next_frame();
void queue_to_execute_next_frame(string s);
-// for marking written-to values as unused where it's a good idea to do this
-noref float unused_float;
-
// a function f with:
// f(0) = 0
// f(1) = 1
// Returns the correct difference between two always increasing numbers
#define COMPARE_INCREASING(to,from) (to < from ? from + to + 2 : to - from)
-#endif
-#ifndef VEHICLES_ALL_H
-#define VEHICLES_ALL_H
+#pragma once
#include "vehicle.qh"
REGISTER_VEHICLE(Null, NEW(Vehicle));
#include "vehicle/_mod.inc"
-
-#endif
if(axh != NULL && !wasfreed(axh))
{
AuxiliaryXhair[i] = NULL;
- remove(axh);
+ delete(axh);
}
}
return;
entity axh = AuxiliaryXhair[i];
if(axh != NULL && !wasfreed(axh)) // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?)
- remove(axh);
+ delete(axh);
axh = spawn();
axh.draw2d = func_null;
tmpPos.x = vehicleHud_Pos.x + vehicleHud_Size.x * (96/256) - tmpSize.x;
tmpPos.y = vehicleHud_Pos.y;
tmpSize = '1 1 1' * hud_fontsize;
- drawstring(tmpPos, sprintf(_("Press %s"), getcommandkey("dropweapon", "dropweapon")), tmpSize, '1 0 0' + '0 1 1' * tmpblinkValue, hudAlpha, DRAWFLAG_NORMAL);
+ drawstring(tmpPos, sprintf(_("Press %s"), getcommandkey(_("drop weapon"), "dropweapon")), tmpSize, '1 0 0' + '0 1 1' * tmpblinkValue, hudAlpha, DRAWFLAG_NORMAL);
}
// Model
-#ifndef CL_VEHICLES_H
-#define CL_VEHICLES_H
+#pragma once
vector vehicleHud_Size;
vector vehicleHud_Pos;
void RaptorCBShellfragToss(vector _org, vector _vel, vector _ang);
#define weapon2mode STAT(VEHICLESTAT_W2MODE)
-
-#endif
this.event_damage = func_null;
RadiusDamage (this, this.realowner, this.shot_dmg, 0, this.shot_radius, this, NULL, this.shot_force, this.totalfrags, toucher);
- remove (this);
+ delete (this);
}
void vehicles_projectile_explode_think(entity this)
proj.totalfrags = _deahtype;
proj.solid = SOLID_BBOX;
set_movetype(proj, MOVETYPE_FLYMISSILE);
- proj.flags = FL_PROJECTILE;
+ proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.bot_dodge = true;
proj.bot_dodgerating = _dmg;
proj.velocity = _vel;
proj.health = _health;
}
else
- proj.flags = FL_PROJECTILE | FL_NOTARGET;
+ proj.flags |= FL_NOTARGET;
if(_mzlsound != SND_Null)
sound (this, CH_WEAPON_A, _mzlsound, VOL_BASE, ATTEN_NORM);
sound (this, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
Send_Effect(EFFECT_EXPLOSION_SMALL, randomvec() * 80 + (this.origin + '0 0 100'), '0 0 0', 1);
Send_Effect(EFFECT_EXPLOSION_SMALL, this.wp00.origin + '0 0 64', '0 0 0', 1);
- remove(this);
+ delete(this);
}
void vehicles_gib_touch(entity this, entity toucher)
{
this.alpha -= 0.1;
if(this.cnt >= time)
- remove(this);
+ delete(this);
else
this.nextthink = time + 0.1;
}
entity _slot,
int _hud,
Model _hud_model,
- bool(entity) _framefunc,
+ bool(entity,float) _framefunc,
void(entity,bool) _exitfunc, float(entity, entity) _enterfunc)
{
if(!(_owner.vehicle_flags & VHF_MULTISLOT))
if(this.waypointsprite_attached)
WaypointSprite_Kill(this.waypointsprite_attached);
- remove(this);
+ delete(this);
}
void vehicles_showwp_goaway(entity this)
if(this.waypointsprite_attached)
WaypointSprite_Kill(this.waypointsprite_attached);
- remove(this);
+ delete(this);
}
void vehicles_showwp(entity this)
void vehicle_use(entity this, entity actor, entity trigger)
{
- LOG_DEBUG("vehicle ", this.netname, " used by ", actor.classname, "\n");
+ LOG_DEBUG("vehicle ", this.netname, " used by ", actor.classname);
this.tur_head.team = actor.team;
if(this.active == ACTIVE_ACTIVE && !IS_DEAD(this) && !gameover)
{
- LOG_DEBUG("Respawning vehicle: ", this.netname, "\n");
+ LOG_DEBUG("Respawning vehicle: ", this.netname);
if(this.effects & EF_NODRAW)
{
setthink(this, vehicles_spawn);
if(vehicles_exit_running)
{
- LOG_TRACE("^1vehicles_exit already running! this is not good...\n");
+ LOG_TRACE("^1vehicles_exit already running! this is not good...");
return;
}
// initialization
void vehicles_spawn(entity this)
{
- LOG_DEBUG("Spawning vehicle: ", this.classname, "\n");
+ LOG_DEBUG("Spawning vehicle: ", this.classname);
// disown & reset
this.vehicle_hudmodel.viewmodelforclient = this;
return false;
if(!this.tur_head)
+ {
info.vr_precache(info);
+ IL_PUSH(g_vehicles, this);
+ }
if(this.targetname && this.targetname != "")
{
this.vehicle_controller = find(NULL, target, this.targetname);
if(!this.vehicle_controller)
{
- LOG_DEBUG("^1WARNING: ^7Vehicle with invalid .targetname\n");
+ LOG_DEBUG("^1WARNING: ^7Vehicle with invalid .targetname");
this.active = ACTIVE_ACTIVE;
}
else
-#ifndef VEHICLES_DEF_H
-#define VEHICLES_DEF_H
+#pragma once
#ifdef SVQC
#include <common/turrets/sv_turrets.qh>
float vehicle_altitude(entity this, float amax);
#endif
-#endif
-#ifndef VEHICLE_H
-#define VEHICLE_H
+#pragma once
CLASS(Vehicle, Object)
- ATTRIB(Vehicle, vehicleid, int, 0)
+ ATTRIB(Vehicle, vehicleid, int, 0);
/** hud icon */
- ATTRIB(Vehicle, m_icon, string, string_null)
+ ATTRIB(Vehicle, m_icon, string);
/** short name */
- ATTRIB(Vehicle, netname, string, "")
+ ATTRIB(Vehicle, netname, string, "");
/** human readable name */
- ATTRIB(Vehicle, vehicle_name, string, "Vehicle")
+ ATTRIB(Vehicle, vehicle_name, string, "Vehicle");
/** full name of model */
- ATTRIB(Vehicle, model, string, "")
+ ATTRIB(Vehicle, model, string, "");
/** currently a copy of the model */
- ATTRIB(Vehicle, mdl, string, "")
+ ATTRIB(Vehicle, mdl, string, "");
/** full name of tur_head model */
- ATTRIB(Vehicle, head_model, string, "")
+ ATTRIB(Vehicle, head_model, string, "");
/** cockpit model */
- ATTRIB(Vehicle, hud_model, string, "")
+ ATTRIB(Vehicle, hud_model, string, "");
/** tur_head model tag */
- ATTRIB(Vehicle, tag_head, string, string_null)
+ ATTRIB(Vehicle, tag_head, string);
/** hud model tag */
- ATTRIB(Vehicle, tag_hud, string, string_null)
+ ATTRIB(Vehicle, tag_hud, string);
/** cockpit model tag */
- ATTRIB(Vehicle, tag_view, string, string_null)
+ ATTRIB(Vehicle, tag_view, string);
/** player physics mod */
- ATTRIB(Vehicle, PlayerPhysplug, bool(entity), func_null)
+ ATTRIB(Vehicle, PlayerPhysplug, bool(entity,float));
/** */
- ATTRIB(Vehicle, spawnflags, int, 0)
+ ATTRIB(Vehicle, spawnflags, int, 0);
/** vehicle hitbox size */
- ATTRIB(Vehicle, mins, vector, '-0 -0 -0')
+ ATTRIB(Vehicle, mins, vector, '-0 -0 -0');
/** vehicle hitbox size */
- ATTRIB(Vehicle, maxs, vector, '0 0 0')
+ ATTRIB(Vehicle, maxs, vector, '0 0 0');
/** vehicle 3rd person view offset */
- ATTRIB(Vehicle, view_ofs, vector, '0 0 0')
+ ATTRIB(Vehicle, view_ofs, vector, '0 0 0');
/** vehicle 3rd person view distance */
- ATTRIB(Vehicle, height, float, 0)
+ ATTRIB(Vehicle, height, float, 0);
/** (BOTH) setup vehicle data */
METHOD(Vehicle, vr_setup, void(Vehicle this, entity instance)) { }
// fields:
.entity tur_head;
-
-#endif
bool autocvar_g_vehicle_bumblebee = true;
-bool bumblebee_gunner_frame(entity this)
+bool bumblebee_gunner_frame(entity this, float dt)
{
entity vehic = this.vehicle.owner;
entity gun = this.vehicle;
}
else if(!vehic.gunner1 && time >= vehic.gun1.phase) { gunner = vehic.gun1; vehic.gunner1 = player; }
else if(!vehic.gunner2 && time >= vehic.gun2.phase) { gunner = vehic.gun2; vehic.gunner2 = player; }
- else { LOG_TRACE("Vehicle is full, fail\n"); return false; }
+ else { LOG_TRACE("Vehicle is full, fail"); return false; }
player.vehicle = gunner;
player.angles = vehic.angles;
vehicles_touch(this, toucher);
}
-void bumblebee_regen(entity this)
+void bumblebee_regen(entity this, float dt)
{
if(this.gun1.delay + autocvar_g_vehicle_bumblebee_cannon_ammo_regen_pause < time)
this.gun1.vehicle_energy = min(autocvar_g_vehicle_bumblebee_cannon_ammo,
- this.gun1.vehicle_energy + autocvar_g_vehicle_bumblebee_cannon_ammo_regen * frametime);
+ this.gun1.vehicle_energy + autocvar_g_vehicle_bumblebee_cannon_ammo_regen * dt);
if(this.gun2.delay + autocvar_g_vehicle_bumblebee_cannon_ammo_regen_pause < time)
this.gun2.vehicle_energy = min(autocvar_g_vehicle_bumblebee_cannon_ammo,
- this.gun2.vehicle_energy + autocvar_g_vehicle_bumblebee_cannon_ammo_regen * frametime);
+ this.gun2.vehicle_energy + autocvar_g_vehicle_bumblebee_cannon_ammo_regen * dt);
if(this.vehicle_flags & VHF_SHIELDREGEN)
- vehicles_regen(this, this.dmg_time, vehicle_shield, autocvar_g_vehicle_bumblebee_shield, autocvar_g_vehicle_bumblebee_shield_regen_pause, autocvar_g_vehicle_bumblebee_shield_regen, frametime, true);
+ vehicles_regen(this, this.dmg_time, vehicle_shield, autocvar_g_vehicle_bumblebee_shield, autocvar_g_vehicle_bumblebee_shield_regen_pause, autocvar_g_vehicle_bumblebee_shield_regen, dt, true);
if(this.vehicle_flags & VHF_HEALTHREGEN)
- vehicles_regen(this, this.dmg_time, vehicle_health, autocvar_g_vehicle_bumblebee_health, autocvar_g_vehicle_bumblebee_health_regen_pause, autocvar_g_vehicle_bumblebee_health_regen, frametime, false);
+ vehicles_regen(this, this.dmg_time, vehicle_health, autocvar_g_vehicle_bumblebee_health, autocvar_g_vehicle_bumblebee_health_regen_pause, autocvar_g_vehicle_bumblebee_health_regen, dt, false);
if(this.vehicle_flags & VHF_ENERGYREGEN)
- vehicles_regen(this, this.wait, vehicle_energy, autocvar_g_vehicle_bumblebee_energy, autocvar_g_vehicle_bumblebee_energy_regen_pause, autocvar_g_vehicle_bumblebee_energy_regen, frametime, false);
+ vehicles_regen(this, this.wait, vehicle_energy, autocvar_g_vehicle_bumblebee_energy, autocvar_g_vehicle_bumblebee_energy_regen_pause, autocvar_g_vehicle_bumblebee_energy_regen, dt, false);
}
-bool bumblebee_pilot_frame(entity this)
+bool bumblebee_pilot_frame(entity this, float dt)
{
entity vehic = this.vehicle;
return = true;
return;
}
- bumblebee_regen(vehic);
+ bumblebee_regen(vehic, dt);
crosshair_trace(this);
else if(this.movement.y > 0)
newvel += v_right * autocvar_g_vehicle_bumblebee_speed_strafe;
ftmp = newvel * v_right;
- ftmp *= frametime * 0.1;
+ ftmp *= dt * 0.1;
vehic.angles_z = bound(-15, vehic.angles.z + ftmp, 15);
}
else
else if(PHYS_INPUT_BUTTON_JUMP(this))
newvel += v_up * autocvar_g_vehicle_bumblebee_speed_up;
- vehic.velocity += newvel * frametime;
+ vehic.velocity += newvel * dt;
this.velocity = this.movement = vehic.velocity;
autocvar_g_vehicle_bumblebee_raygun_turnlimit_sides * -1, autocvar_g_vehicle_bumblebee_raygun_turnlimit_sides, autocvar_g_vehicle_bumblebee_raygun_turnspeed);
if(!forbidWeaponUse(this))
- if((PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_ATCK2(this)) && (vehic.vehicle_energy > autocvar_g_vehicle_bumblebee_raygun_dps * sys_frametime || autocvar_g_vehicle_bumblebee_raygun == 0))
+ if((PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_ATCK2(this)) && (vehic.vehicle_energy > autocvar_g_vehicle_bumblebee_raygun_dps * PHYS_INPUT_FRAMETIME || autocvar_g_vehicle_bumblebee_raygun == 0))
{
vehic.gun3.enemy.realowner = this;
vehic.gun3.enemy.effects &= ~EF_NODRAW;
{
if(autocvar_g_vehicle_bumblebee_raygun)
{
- Damage(trace_ent, vehic, this, autocvar_g_vehicle_bumblebee_raygun_dps * sys_frametime, DEATH_GENERIC.m_id, trace_endpos, v_forward * autocvar_g_vehicle_bumblebee_raygun_fps * sys_frametime);
- vehic.vehicle_energy -= autocvar_g_vehicle_bumblebee_raygun_aps * sys_frametime;
+ Damage(trace_ent, vehic, this, autocvar_g_vehicle_bumblebee_raygun_dps * PHYS_INPUT_FRAMETIME, DEATH_GENERIC.m_id, trace_endpos, v_forward * autocvar_g_vehicle_bumblebee_raygun_fps * PHYS_INPUT_FRAMETIME);
+ vehic.vehicle_energy -= autocvar_g_vehicle_bumblebee_raygun_aps * PHYS_INPUT_FRAMETIME;
}
else
{
if(IS_VEHICLE(trace_ent))
{
if(autocvar_g_vehicle_bumblebee_healgun_sps && trace_ent.vehicle_health <= trace_ent.max_health)
- trace_ent.vehicle_shield = min(trace_ent.vehicle_shield + autocvar_g_vehicle_bumblebee_healgun_sps * frametime, trace_ent.tur_head.max_health);
+ trace_ent.vehicle_shield = min(trace_ent.vehicle_shield + autocvar_g_vehicle_bumblebee_healgun_sps * dt, trace_ent.tur_head.max_health);
if(autocvar_g_vehicle_bumblebee_healgun_hps)
- trace_ent.vehicle_health = min(trace_ent.vehicle_health + autocvar_g_vehicle_bumblebee_healgun_hps * frametime, trace_ent.max_health);
+ trace_ent.vehicle_health = min(trace_ent.vehicle_health + autocvar_g_vehicle_bumblebee_healgun_hps * dt, trace_ent.max_health);
}
else if(IS_CLIENT(trace_ent))
{
if(trace_ent.health <= autocvar_g_vehicle_bumblebee_healgun_hmax && autocvar_g_vehicle_bumblebee_healgun_hps)
- trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * frametime, autocvar_g_vehicle_bumblebee_healgun_hmax);
+ trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * dt, autocvar_g_vehicle_bumblebee_healgun_hmax);
if(trace_ent.armorvalue <= autocvar_g_vehicle_bumblebee_healgun_amax && autocvar_g_vehicle_bumblebee_healgun_aps)
- trace_ent.armorvalue = min(trace_ent.armorvalue + autocvar_g_vehicle_bumblebee_healgun_aps * frametime, autocvar_g_vehicle_bumblebee_healgun_amax);
+ trace_ent.armorvalue = min(trace_ent.armorvalue + autocvar_g_vehicle_bumblebee_healgun_aps * dt, autocvar_g_vehicle_bumblebee_healgun_amax);
- trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * frametime, autocvar_g_vehicle_bumblebee_healgun_hmax);
+ trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * dt, autocvar_g_vehicle_bumblebee_healgun_hmax);
}
else if(IS_TURRET(trace_ent))
{
if(trace_ent.health <= trace_ent.max_health && autocvar_g_vehicle_bumblebee_healgun_hps)
- trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * frametime, trace_ent.max_health);
+ trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * dt, trace_ent.max_health);
//else ..hmmm what? ammo?
trace_ent.SendFlags |= TNSF_STATUS;
float hgt;
hgt = vehicle_altitude(this, 512);
- this.velocity = (this.velocity * 0.9) + ('0 0 -1800' * (hgt / 256) * sys_frametime);
+ this.velocity = (this.velocity * 0.9) + ('0 0 -1800' * (hgt / 256) * PHYS_INPUT_FRAMETIME);
this.angles_x *= 0.95;
this.angles_z *= 0.95;
if(this.owner.deadflag == DEAD_DYING)
this.owner.deadflag = DEAD_DEAD;
- remove(this);
+ delete(this);
}
void bumblebee_dead_touch(entity this, entity toucher)
spawnfunc(vehicle_bumblebee)
{
- if(!autocvar_g_vehicle_bumblebee) { remove(this); return; }
- if(!vehicle_initialize(this, VEH_BUMBLEBEE, false)) { remove(this); return; }
+ if(!autocvar_g_vehicle_bumblebee) { delete(this); return; }
+ if(!vehicle_initialize(this, VEH_BUMBLEBEE, false)) { delete(this); return; }
}
METHOD(Bumblebee, vr_impact, void(Bumblebee thisveh, entity instance))
-#ifndef BUMBLEBEE_H
-#define BUMBLEBEE_H
+#pragma once
#ifdef CSQC
void CSQC_BUMBLE_GUN_HUD();
#endif
-
-#endif
racer_fire_rocket(player, v, v_forward, trg);
}
-bool racer_frame(entity this)
+bool racer_frame(entity this, float dt)
{
entity vehic = this.vehicle;
return = true;
return;
}
- racer_align4point(vehic, PHYS_INPUT_TIMELENGTH);
+ racer_align4point(vehic, dt);
PHYS_INPUT_BUTTON_ZOOM(this) = PHYS_INPUT_BUTTON_CROUCH(this) = false;
vehic.angles_x *= -1;
// Yaw
- float ftmp = autocvar_g_vehicle_racer_turnspeed * PHYS_INPUT_TIMELENGTH;
+ float ftmp = autocvar_g_vehicle_racer_turnspeed * dt;
ftmp = bound(-ftmp, shortangle_f(this.v_angle_y - vehic.angles_y, vehic.angles_y), ftmp);
vehic.angles_y = anglemods(vehic.angles_y + ftmp);
// Roll
- vehic.angles_z += -ftmp * autocvar_g_vehicle_racer_turnroll * PHYS_INPUT_TIMELENGTH;
+ vehic.angles_z += -ftmp * autocvar_g_vehicle_racer_turnroll * dt;
// Pitch
- ftmp = autocvar_g_vehicle_racer_pitchspeed * PHYS_INPUT_TIMELENGTH;
+ ftmp = autocvar_g_vehicle_racer_pitchspeed * dt;
ftmp = bound(-ftmp, shortangle_f(this.v_angle_x - vehic.angles_x, vehic.angles_x), ftmp);
vehic.angles_x = bound(-autocvar_g_vehicle_racer_pitchlimit, anglemods(vehic.angles_x + ftmp), autocvar_g_vehicle_racer_pitchlimit);
#endif
// Afterburn
- if (PHYS_INPUT_BUTTON_JUMP(this) && vehic.vehicle_energy >= (autocvar_g_vehicle_racer_afterburn_cost * PHYS_INPUT_TIMELENGTH))
+ if (PHYS_INPUT_BUTTON_JUMP(this) && vehic.vehicle_energy >= (autocvar_g_vehicle_racer_afterburn_cost * dt))
{
#ifdef SVQC
if(time - vehic.wait > 0.2)
if(cont & DPCONTENTS_LIQUIDSMASK)
{
- vehic.vehicle_energy -= autocvar_g_vehicle_racer_waterburn_cost * PHYS_INPUT_TIMELENGTH;
+ vehic.vehicle_energy -= autocvar_g_vehicle_racer_waterburn_cost * dt;
df += (v_forward * autocvar_g_vehicle_racer_waterburn_speed);
}
else
{
- vehic.vehicle_energy -= autocvar_g_vehicle_racer_afterburn_cost * PHYS_INPUT_TIMELENGTH;
+ vehic.vehicle_energy -= autocvar_g_vehicle_racer_afterburn_cost * dt;
df += (v_forward * autocvar_g_vehicle_racer_speed_afterburn);
}
dforce = autocvar_g_vehicle_racer_water_downforce;
df -= v_up * (vlen(vehic.velocity) * dforce);
- this.movement = vehic.velocity += df * PHYS_INPUT_TIMELENGTH;
+ this.movement = vehic.velocity += df * dt;
#ifdef SVQC
{
crosshair_trace(this);
- vehicles_locktarget(vehic, (1 / autocvar_g_vehicle_racer_rocket_locking_time) * frametime,
- (1 / autocvar_g_vehicle_racer_rocket_locking_releasetime) * frametime,
+ vehicles_locktarget(vehic, (1 / autocvar_g_vehicle_racer_rocket_locking_time) * dt,
+ (1 / autocvar_g_vehicle_racer_rocket_locking_releasetime) * dt,
autocvar_g_vehicle_racer_rocket_locked_time);
vehic.vehicle_last_trace = time + autocvar_g_vehicle_racer_thinkrate;
this.vehicle_reload2 = bound(0, 100 * ((time - vehic.lip) / (vehic.delay - vehic.lip)), 100);
if(vehic.vehicle_flags & VHF_SHIELDREGEN)
- vehicles_regen(vehic, vehic.dmg_time, vehicle_shield, autocvar_g_vehicle_racer_shield, autocvar_g_vehicle_racer_shield_regen_pause, autocvar_g_vehicle_racer_shield_regen, frametime, true);
+ vehicles_regen(vehic, vehic.dmg_time, vehicle_shield, autocvar_g_vehicle_racer_shield, autocvar_g_vehicle_racer_shield_regen_pause, autocvar_g_vehicle_racer_shield_regen, dt, true);
if(vehic.vehicle_flags & VHF_HEALTHREGEN)
- vehicles_regen(vehic, vehic.dmg_time, vehicle_health, autocvar_g_vehicle_racer_health, autocvar_g_vehicle_racer_health_regen_pause, autocvar_g_vehicle_racer_health_regen, frametime, false);
+ vehicles_regen(vehic, vehic.dmg_time, vehicle_health, autocvar_g_vehicle_racer_health, autocvar_g_vehicle_racer_health_regen_pause, autocvar_g_vehicle_racer_health_regen, dt, false);
if(vehic.vehicle_flags & VHF_ENERGYREGEN)
- vehicles_regen(vehic, vehic.wait, vehicle_energy, autocvar_g_vehicle_racer_energy, autocvar_g_vehicle_racer_energy_regen_pause, autocvar_g_vehicle_racer_energy_regen, frametime, false);
+ vehicles_regen(vehic, vehic.wait, vehicle_energy, autocvar_g_vehicle_racer_energy, autocvar_g_vehicle_racer_energy_regen_pause, autocvar_g_vehicle_racer_energy_regen, dt, false);
VEHICLE_UPDATE_PLAYER(this, vehic, health, racer);
VEHICLE_UPDATE_PLAYER(this, vehic, energy, racer);
spawnfunc(vehicle_racer)
{
- if(!autocvar_g_vehicle_racer) { remove(this); return; }
- if(!vehicle_initialize(this, VEH_RACER, false)) { remove(this); return; }
+ if(!autocvar_g_vehicle_racer) { delete(this); return; }
+ if(!vehicle_initialize(this, VEH_RACER, false)) { delete(this); return; }
}
#endif // SVQC
if(instance.owner.flagcarried)
setorigin(instance.owner.flagcarried, '-190 0 96');
#elif defined(CSQC)
- instance.move_movetype = MOVETYPE_BOUNCE;
+ set_movetype(instance, MOVETYPE_BOUNCE);
#endif
}
veh.vehicle_energy -= autocvar_g_vehicle_racer_cannon_cost;
veh.wait = time;
}
- if (isPlayer) W_SetupShot_Dir(player, v_forward, false, 0, SND_Null, CH_WEAPON_B, 0);
+ if (isPlayer) W_SetupShot_Dir(player, weaponentity, v_forward, false, 0, SND_Null, CH_WEAPON_B, 0);
vector org = w_shotorg;
vector dir = w_shotdir;
entity bolt = vehicles_projectile(veh, EFFECT_RACER_MUZZLEFLASH.eent_eff_name, SND_LASERGUN_FIRE,
}
if (fire & 2)
if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, 0.2)) {
- if (isPlayer) W_SetupShot_Dir(actor, v_forward, false, 0, SND_Null, CH_WEAPON_B, 0);
+ if (isPlayer) W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_Null, CH_WEAPON_B, 0);
racer_fire_rocket(player, w_shotorg, w_shotdir, NULL);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, 0, w_ready);
}
float hgt;
hgt = vehicle_altitude(this, 512);
- this.velocity = (this.velocity * 0.9) + ('0 0 -1800' * (hgt / 256) * sys_frametime);
+ this.velocity = (this.velocity * 0.9) + ('0 0 -1800' * (hgt / 256) * PHYS_INPUT_FRAMETIME);
this.angles_x *= 0.95;
this.angles_z *= 0.95;
this.owner = NULL;
}
-bool raptor_frame(entity this)
+bool raptor_frame(entity this, float dt)
{
entity vehic = this.vehicle;
return = true;
else if (PHYS_INPUT_BUTTON_JUMP(this))
df += v_up * autocvar_g_vehicle_raptor_speed_up;
- vehic.velocity += df * frametime;
+ vehic.velocity += df * dt;
this.velocity = this.movement = vehic.velocity;
setorigin(this, vehic.origin + '0 0 32');
else if(autocvar_g_vehicle_raptor_cannon_locktarget == 1)
{
- vehicles_locktarget(vehic, (1 / autocvar_g_vehicle_raptor_cannon_locking_time) * frametime,
- (1 / autocvar_g_vehicle_raptor_cannon_locking_releasetime) * frametime,
+ vehicles_locktarget(vehic, (1 / autocvar_g_vehicle_raptor_cannon_locking_time) * dt,
+ (1 / autocvar_g_vehicle_raptor_cannon_locking_releasetime) * dt,
autocvar_g_vehicle_raptor_cannon_locked_time);
if(vehic.lock_target != NULL)
}
if(vehic.vehicle_flags & VHF_SHIELDREGEN)
- vehicles_regen(vehic, vehic.dmg_time, vehicle_shield, autocvar_g_vehicle_raptor_shield, autocvar_g_vehicle_raptor_shield_regen_pause, autocvar_g_vehicle_raptor_shield_regen, frametime, true);
+ vehicles_regen(vehic, vehic.dmg_time, vehicle_shield, autocvar_g_vehicle_raptor_shield, autocvar_g_vehicle_raptor_shield_regen_pause, autocvar_g_vehicle_raptor_shield_regen, dt, true);
if(vehic.vehicle_flags & VHF_HEALTHREGEN)
- vehicles_regen(vehic, vehic.dmg_time, vehicle_health, autocvar_g_vehicle_raptor_health, autocvar_g_vehicle_raptor_health_regen_pause, autocvar_g_vehicle_raptor_health_regen, frametime, false);
+ vehicles_regen(vehic, vehic.dmg_time, vehicle_health, autocvar_g_vehicle_raptor_health, autocvar_g_vehicle_raptor_health_regen_pause, autocvar_g_vehicle_raptor_health_regen, dt, false);
if(vehic.vehicle_flags & VHF_ENERGYREGEN)
- vehicles_regen(vehic, vehic.cnt, vehicle_energy, autocvar_g_vehicle_raptor_energy, autocvar_g_vehicle_raptor_energy_regen_pause, autocvar_g_vehicle_raptor_energy_regen, frametime, false);
+ vehicles_regen(vehic, vehic.cnt, vehicle_energy, autocvar_g_vehicle_raptor_energy, autocvar_g_vehicle_raptor_energy_regen_pause, autocvar_g_vehicle_raptor_energy_regen, dt, false);
Weapon wep2a = WEP_RAPTOR_BOMB;
if(!forbidWeaponUse(this))
if(vehic.bomb1.cnt < time)
{
bool incoming = false;
- FOREACH_ENTITY_ENT(enemy, vehic,
+ IL_EACH(g_projectiles, it.enemy == vehic,
{
- if(it.flags & FL_PROJECTILE)
if(MISSILE_IS_TRACKING(it))
if(vdist(vehic.origin - it.origin, <, 2 * autocvar_g_vehicle_raptor_flare_range))
{
PHYS_INPUT_BUTTON_ATCK(this) = PHYS_INPUT_BUTTON_ATCK2(this) = PHYS_INPUT_BUTTON_CROUCH(this) = false;
}
-bool raptor_takeoff(entity this)
+bool raptor_takeoff(entity this, float dt)
{
entity vehic = this.vehicle;
return = true;
// Takeoff sequense
if(vehic.frame < 25)
{
- vehic.frame += 25 / (autocvar_g_vehicle_raptor_takeofftime / sys_frametime);
+ vehic.frame += 25 / (autocvar_g_vehicle_raptor_takeofftime / PHYS_INPUT_FRAMETIME);
vehic.velocity_z = min(vehic.velocity_z * 1.5, 256);
vehic.bomb1.gun1.avelocity_y = 90 + ((vehic.frame / 25) * 25000);
vehic.bomb1.gun2.avelocity_y = -vehic.bomb1.gun1.avelocity_y;
this.PlayerPhysplug = raptor_frame;
if(vehic.vehicle_flags & VHF_SHIELDREGEN)
- vehicles_regen(vehic, vehic.dmg_time, vehicle_shield, autocvar_g_vehicle_raptor_shield, autocvar_g_vehicle_raptor_shield_regen_pause, autocvar_g_vehicle_raptor_shield_regen, frametime, true);
+ vehicles_regen(vehic, vehic.dmg_time, vehicle_shield, autocvar_g_vehicle_raptor_shield, autocvar_g_vehicle_raptor_shield_regen_pause, autocvar_g_vehicle_raptor_shield_regen, dt, true);
if(vehic.vehicle_flags & VHF_HEALTHREGEN)
- vehicles_regen(vehic, vehic.dmg_time, vehicle_health, autocvar_g_vehicle_raptor_health, autocvar_g_vehicle_raptor_health_regen_pause, autocvar_g_vehicle_raptor_health_regen, frametime, false);
+ vehicles_regen(vehic, vehic.dmg_time, vehicle_health, autocvar_g_vehicle_raptor_health, autocvar_g_vehicle_raptor_health_regen_pause, autocvar_g_vehicle_raptor_health_regen, dt, false);
if(vehic.vehicle_flags & VHF_ENERGYREGEN)
- vehicles_regen(vehic, vehic.cnt, vehicle_energy, autocvar_g_vehicle_raptor_energy, autocvar_g_vehicle_raptor_energy_regen_pause, autocvar_g_vehicle_raptor_energy_regen, frametime, false);
+ vehicles_regen(vehic, vehic.cnt, vehicle_energy, autocvar_g_vehicle_raptor_energy, autocvar_g_vehicle_raptor_energy_regen_pause, autocvar_g_vehicle_raptor_energy_regen, dt, false);
vehic.bomb1.alpha = vehic.bomb2.alpha = (time - vehic.lip) / (vehic.delay - vehic.lip);
spawnfunc(vehicle_raptor)
{
- if(!autocvar_g_vehicle_raptor) { remove(this); return; }
- if(!vehicle_initialize(this, VEH_RAPTOR, false)) { remove(this); return; }
+ if(!autocvar_g_vehicle_raptor) { delete(this); return; }
+ if(!vehicle_initialize(this, VEH_RAPTOR, false)) { delete(this); return; }
}
METHOD(Raptor, vr_impact, void(Raptor thisveh, entity instance))
-#ifndef RAPTOR_H
-#define RAPTOR_H
+#pragma once
const int RSM_FIRST = 1;
const int RSM_BOMB = 1;
const int RSM_FLARE = 2;
const int RSM_LAST = 2;
-
-#endif
float t = autocvar_g_vehicle_raptor_cannon_refire * (1 + veh.misc_bulletcounter == 4);
if (fire & 1)
if (weapon_prepareattack(thiswep, player, weaponentity, false, t)) {
- if (isPlayer) W_SetupShot_Dir(player, v_forward, false, 0, SND_Null, CH_WEAPON_B, 0);
+ if (isPlayer) W_SetupShot_Dir(player, weaponentity, v_forward, false, 0, SND_Null, CH_WEAPON_B, 0);
vector org = w_shotorg;
vector dir = w_shotdir;
if (veh) {
autocvar_g_vehicle_raptor_bomblet_edgedamage,
autocvar_g_vehicle_raptor_bomblet_radius, NULL, NULL,
autocvar_g_vehicle_raptor_bomblet_force, DEATH_VH_RAPT_BOMB.m_id, NULL);
- remove(this);
+ delete(this);
}
void raptor_bomblet_touch(entity this, entity toucher)
CSQCProjectile(bomblet, true, PROJECTILE_RAPTORBOMBLET, true);
}
- remove(this);
+ delete(this);
}
void raptor_bomb_touch(entity this, entity toucher)
void raptor_flare_touch(entity this, entity toucher)
{
- remove(this);
+ delete(this);
}
void raptor_flare_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
this.health -= damage;
if(this.health <= 0)
- remove(this);
+ delete(this);
}
void raptor_flare_think(entity this)
});
if(this.tur_impacttime < time)
- remove(this);
+ delete(this);
}
#endif
this.alpha = bound(0, this.nextthink - time, 1);
if(this.alpha < ALPHA_MIN_VISIBLE)
- remove(this);
+ delete(this);
}
void RaptorCBShellfragToss(vector _org, vector _vel, vector _ang)
vector autocvar_g_vehicle_spiderbot_bouncepain = '0 0 0';
.float jump_delay;
-bool spiderbot_frame(entity this)
+bool spiderbot_frame(entity this, float dt)
{
entity vehic = this.vehicle;
return = true;
//UpdateAuxiliaryXhair(this, trace_endpos, ('1 0 0' * this.vehicle_reload2) + ('0 1 0' * (1 - this.vehicle_reload2)), 2);
// Rotate head
- float ftmp = autocvar_g_vehicle_spiderbot_head_turnspeed * sys_frametime;
+ float ftmp = autocvar_g_vehicle_spiderbot_head_turnspeed * PHYS_INPUT_FRAMETIME;
ad_y = bound(-ftmp, ad_y, ftmp);
vehic.tur_head.angles_y = bound(autocvar_g_vehicle_spiderbot_head_turnlimit * -1, vehic.tur_head.angles_y + ad_y, autocvar_g_vehicle_spiderbot_head_turnlimit);
{
// Turn Body
if(this.movement_x == 0 && this.movement_y != 0)
- ftmp = autocvar_g_vehicle_spiderbot_turnspeed_strafe * sys_frametime;
+ ftmp = autocvar_g_vehicle_spiderbot_turnspeed_strafe * PHYS_INPUT_FRAMETIME;
else
- ftmp = autocvar_g_vehicle_spiderbot_turnspeed * sys_frametime;
+ ftmp = autocvar_g_vehicle_spiderbot_turnspeed * PHYS_INPUT_FRAMETIME;
ftmp = bound(-ftmp, vehic.tur_head.angles_y, ftmp);
vehic.angles_y = anglemods(vehic.angles_y + ftmp);
vehic.velocity_z = oldvelz;
float g = ((autocvar_sv_gameplayfix_gravityunaffectedbyticrate) ? 0.5 : 1);
if(vehic.velocity_z <= 20) // not while jumping
- vehic.velocity_z -= g * sys_frametime * autocvar_sv_gravity;
+ vehic.velocity_z -= g * PHYS_INPUT_FRAMETIME * autocvar_sv_gravity;
if(IS_ONGROUND(vehic))
if(vehic.sound_nexttime < time || vehic.delay != 1)
{
vehic.velocity_z = oldvelz;
float g = ((autocvar_sv_gameplayfix_gravityunaffectedbyticrate) ? 0.5 : 1);
if(vehic.velocity_z <= 20) // not while jumping
- vehic.velocity_z -= g * sys_frametime * autocvar_sv_gravity;
+ vehic.velocity_z -= g * PHYS_INPUT_FRAMETIME * autocvar_sv_gravity;
if(IS_ONGROUND(vehic))
if(vehic.sound_nexttime < time || vehic.delay != 2)
{
else
vehicles_regen(vehic, vehic.cnt, vehicle_ammo1, autocvar_g_vehicle_spiderbot_minigun_ammo_max,
autocvar_g_vehicle_spiderbot_minigun_ammo_regen_pause,
- autocvar_g_vehicle_spiderbot_minigun_ammo_regen, frametime, false);
+ autocvar_g_vehicle_spiderbot_minigun_ammo_regen, dt, false);
spiderbot_rocket_do(vehic);
if(vehic.vehicle_flags & VHF_SHIELDREGEN)
- vehicles_regen(vehic, vehic.dmg_time, vehicle_shield, autocvar_g_vehicle_spiderbot_shield, autocvar_g_vehicle_spiderbot_shield_regen_pause, autocvar_g_vehicle_spiderbot_shield_regen, frametime, true);
+ vehicles_regen(vehic, vehic.dmg_time, vehicle_shield, autocvar_g_vehicle_spiderbot_shield, autocvar_g_vehicle_spiderbot_shield_regen_pause, autocvar_g_vehicle_spiderbot_shield_regen, dt, true);
if(vehic.vehicle_flags & VHF_HEALTHREGEN)
- vehicles_regen(vehic, vehic.dmg_time, vehicle_health, autocvar_g_vehicle_spiderbot_health, autocvar_g_vehicle_spiderbot_health_regen_pause, autocvar_g_vehicle_spiderbot_health_regen, frametime, false);
+ vehicles_regen(vehic, vehic.dmg_time, vehicle_health, autocvar_g_vehicle_spiderbot_health, autocvar_g_vehicle_spiderbot_health_regen_pause, autocvar_g_vehicle_spiderbot_health_regen, dt, false);
PHYS_INPUT_BUTTON_ATCK(this) = PHYS_INPUT_BUTTON_ATCK2(this) = false;
//this.vehicle_ammo2 = vehic.tur_head.frame;
sound (this, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
Send_Effect(EFFECT_EXPLOSION_BIG, this.origin + '0 0 100', '0 0 0', 1);
}
- remove(this);
+ delete(this);
}
}
spawnfunc(vehicle_spiderbot)
{
- if(!autocvar_g_vehicle_spiderbot) { remove(this); return; }
- if(!vehicle_initialize(this, VEH_SPIDERBOT, false)) { remove(this); return; }
+ if(!autocvar_g_vehicle_spiderbot) { delete(this); return; }
+ if(!vehicle_initialize(this, VEH_SPIDERBOT, false)) { delete(this); return; }
}
METHOD(Spiderbot, vr_impact, void(Spiderbot thisveh, entity instance))
}
#if 0
- LOG_TRACE(vtos(camera_position), "\n");
- LOG_TRACE(vtos(old_camera_angle), "\n");
- LOG_TRACE(vtos(camera_angle), "\n");
+ LOG_TRACE(vtos(camera_position));
+ LOG_TRACE(vtos(old_camera_angle));
+ LOG_TRACE(vtos(camera_angle));
#endif
freeze_org = getpropertyvec(VF_ORIGIN);
-#ifndef VIEWLOC_H
-#define VIEWLOC_H
+#pragma once
.entity viewloc;
void viewloc_SetTags(entity this);
#endif
-
-#endif
if (name == "")
{
this.model = "";
- if (this.weaponchild) remove(this.weaponchild);
+ if (this.weaponchild) delete(this.weaponchild);
this.weaponchild = NULL;
this.movedir = '0 0 0';
this.spawnorigin = '0 0 0';
}
else
{
- if (this.weaponchild) remove(this.weaponchild);
+ if (this.weaponchild) delete(this.weaponchild);
this.weaponchild = NULL;
}
}
else
{
- LOG_WARNINGF("weapon model %s does not support the 'shot' tag, will display shots TOTALLY wrong\n",
+ LOG_WARNF("weapon model %s does not support the 'shot' tag, will display shots TOTALLY wrong",
this.model);
this.movedir = '0 0 0';
}
}
else
{
- LOG_WARNINGF("weapon model %s does not support the 'shell' tag, will display casings wrong\n",
+ LOG_WARNF("weapon model %s does not support the 'shell' tag, will display casings wrong",
this.model);
this.spawnorigin = this.movedir;
}
}
else
{
- LOG_WARNINGF(
+ LOG_WARNF(
"weapon model %s does not support the 'handle' tag "
"and neither does the v_ model support the 'shot' tag, "
"will display muzzle flashes TOTALLY wrong\n",
-#ifndef WEAPONS_ALL_H
-#define WEAPONS_ALL_H
+#pragma once
#include <common/command/all.qh>
#include <common/stats.qh>
#include <common/util.qh>
-#ifdef SVQC
-#include <server/bot/aim.qh>
-#endif
-
REGISTRY(Weapons, 72) // Increase as needed. Can be up to 72.
#define Weapons_from(i) _Weapons_from(i, WEP_Null)
REGISTER_REGISTRY(Weapons)
STATIC_INIT(WeaponPickup) { FOREACH(Weapons, true, it.m_pickup = NEW(WeaponPickup, it)); }
+#ifdef SVQC
+#include <server/bot/api.qh>
+#endif
+
.WepSet m_wepset;
#define WEPSET(id) (WEP_##id.m_wepset)
#define WepSet_FromWeapon(it) ((it).m_wepset)
else
inaccessible = strcat(inaccessible, "\n", it.netname);
});
- if (inaccessible) LOG_TRACEF("Impulse limit exceeded, weapon(s) will not be directly accessible: %s\n", inaccessible);
+ if (inaccessible) LOG_TRACEF("Impulse limit exceeded, weapon(s) will not be directly accessible: %s", inaccessible);
#ifdef CSQC
FOREACH(Weapons, true, it.wr_init(it));
#endif
vector shotorg_adjust_values(vector vecs, bool y_is_right, bool visual, int algn);
void CL_WeaponEntity_SetModel(entity this, string name, bool _anim);
#endif
-
-#endif
default:
error("g_projectiles_spread_style must be 0 (sphere), 1 (flattened sphere), 2 (circle), 3 (gauss 3D), 4 (gauss plane), 5 (linear falloff), 6 (quadratic falloff), 7 (stronger falloff)!");
}
-
+
return '0 0 0';
/*
* how to derive falloff functions:
-#ifndef CALCULATIONS_H
-#define CALCULATIONS_H
+#pragma once
+
vector damage_explosion_calcpush(vector explosion_f, vector target_v, float speedfactor);
vector W_CalculateSpread(vector forward, float spread, float spreadfactor, float spreadstyle);
int W_GetGunAlignment(entity player);
-#endif
-#ifndef WEAPONS_CONFIG_H
-#define WEAPONS_CONFIG_H
+#pragma once
#ifdef SVQC
// ==========================
cvar(sprintf("g_balance_%s_%s", #wepname, #name)))) }
#endif
-#endif
-#ifndef WEAPON_H
-#define WEAPON_H
+#pragma once
+
#include <common/items/item/pickup.qh>
#include <common/stats.qh>
/** fields which are explicitly/manually set are marked with "M", fields set automatically are marked with "A" */
CLASS(Weapon, Object)
- ATTRIB(Weapon, m_id, int, 0)
+ ATTRIB(Weapon, m_id, int, 0);
/** A: WEPSET_id : WEPSET_... */
ATTRIB(Weapon, weapons, WepSet, '0 0 0');
/** M: ammotype : main ammo field */
/** M: modelname : name of model (without g_ v_ or h_ prefixes) */
ATTRIB(Weapon, mdl, string, "");
/** M: model MDL_id_ITEM */
- ATTRIB(Weapon, m_model, entity, NULL);
+ ATTRIB(Weapon, m_model, entity);
/** M: crosshair : per-weapon crosshair: "CrosshairImage Size" */
ATTRIB(Weapon, w_crosshair, string, "gfx/crosshair1");
/** A: crosshair : per-weapon crosshair size (argument two of "crosshair" field) */
/** M: wepname : human readable name */
ATTRIB(Weapon, m_name, string, "AOL CD Thrower");
- ATTRIB(Weapon, m_pickup, entity, NULL);
+ ATTRIB(Weapon, m_pickup, entity);
/** (SERVER) setup weapon data */
METHOD(Weapon, wr_setup, void(Weapon this, entity actor)) {}
/** (CLIENT) impact effect for weapon explosion */
METHOD(Weapon, wr_impacteffect, void(Weapon this, entity actor)) {}
/** (SERVER) called whenever a player dies */
- METHOD(Weapon, wr_playerdeath, void(Weapon this, entity actor)) {}
+ METHOD(Weapon, wr_playerdeath, void(Weapon this, entity actor, .entity weaponentity)) {}
/** (SERVER) logic to run when weapon is lost */
- METHOD(Weapon, wr_gonethink, void(Weapon this, entity actor)) {}
+ METHOD(Weapon, wr_gonethink, void(Weapon this, entity actor, .entity weaponentity)) {}
/** (ALL) dump weapon cvars to config in data directory (see: sv_cmd dumpweapons) */
METHOD(Weapon, wr_config, void(Weapon this)) {}
/** (CLIENT) weapon specific zoom reticle */
#include <common/items/all.qh>
CLASS(WeaponPickup, Pickup)
- ATTRIB(WeaponPickup, m_weapon, Weapon, NULL)
- ATTRIB(WeaponPickup, m_name, string, string_null)
+ ATTRIB(WeaponPickup, m_weapon, Weapon);
+ ATTRIB(WeaponPickup, m_name, string);
#ifndef MENUQC
- ATTRIB(WeaponPickup, m_sound, Sound, SND_WEAPONPICKUP)
+ ATTRIB(WeaponPickup, m_sound, Sound, SND_WEAPONPICKUP);
#endif
#ifdef SVQC
- ATTRIB(WeaponPickup, m_itemflags, int, FL_WEAPON)
+ ATTRIB(WeaponPickup, m_itemflags, int, FL_WEAPON);
float weapon_pickupevalfunc(entity player, entity item);
- ATTRIB(WeaponPickup, m_pickupevalfunc, float(entity player, entity item), weapon_pickupevalfunc)
+ ATTRIB(WeaponPickup, m_pickupevalfunc, float(entity player, entity item), weapon_pickupevalfunc);
#endif
CONSTRUCTOR(WeaponPickup, Weapon w) {
CONSTRUCT(WeaponPickup);
{
bool b = Item_GiveTo(item, player);
if (b) {
- LOG_TRACEF("entity %i picked up %s\n", player, this.m_name);
+ LOG_TRACEF("entity %i picked up %s", player, this.m_name);
}
return b;
}
string W_Sound(string w_snd);
string W_Model(string w_mdl);
-
-#endif
#ifndef IMPLEMENTATION
CLASS(Arc, Weapon)
-/* ammotype */ ATTRIB(Arc, ammo_field, .int, ammo_cells)
-/* impulse */ ATTRIB(Arc, impulse, int, 3)
+/* ammotype */ ATTRIB(Arc, ammo_field, .int, ammo_cells);
+/* impulse */ ATTRIB(Arc, impulse, int, 3);
/* flags */ ATTRIB(Arc, spawnflags, int, WEP_FLAG_NORMAL);
/* rating */ ATTRIB(Arc, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
/* color */ ATTRIB(Arc, wpcolor, vector, '1 1 1');
#endif
#ifdef SVQC
.entity arc_beam;
-.bool arc_BUTTON_ATCK_prev; // for better animation control
+.bool arc_BUTTON_ATCK_prev[MAX_WEAPONSLOTS]; // for better animation control
.float beam_prev;
.float beam_initialized;
.float beam_bursting;
void Reset_ArcBeam(entity player, vector forward)
{
- if (!player.arc_beam) {
- return;
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ if(!player.(weaponentity).arc_beam)
+ continue;
+ player.(weaponentity).arc_beam.beam_dir = forward;
+ player.(weaponentity).arc_beam.beam_teleporttime = time;
}
- player.arc_beam.beam_dir = forward;
- player.arc_beam.beam_teleporttime = time;
}
-float Arc_GetHeat_Percent(entity player)
+float Arc_GetHeat_Percent(entity player, .entity weaponentity)
{
if ( WEP_CVAR(arc, overheat_max) <= 0 || WEP_CVAR(arc, overheat_max) <= 0 )
{
return 0;
}
- if ( player.arc_beam )
- return player.arc_beam.beam_heat/WEP_CVAR(arc, overheat_max);
+ if ( player.(weaponentity).arc_beam )
+ return player.(weaponentity).arc_beam.beam_heat/WEP_CVAR(arc, overheat_max);
if ( player.arc_overheat > time )
{
return 0;
}
-void Arc_Player_SetHeat(entity player)
+void Arc_Player_SetHeat(entity player, .entity weaponentity)
{
- player.arc_heat_percent = Arc_GetHeat_Percent(player);
+ player.arc_heat_percent = Arc_GetHeat_Percent(player, weaponentity);
//dprint("Heat: ",ftos(player.arc_heat_percent*100),"%\n");
}
this.event_damage = func_null;
RadiusDamage(this, this.realowner, WEP_CVAR(arc, bolt_damage), WEP_CVAR(arc, bolt_edgedamage), WEP_CVAR(arc, bolt_radius), NULL, NULL, WEP_CVAR(arc, bolt_force), this.projectiledeathtype, directhitentity);
- remove(this);
+ delete(this);
}
void W_Arc_Bolt_Explode_use(entity this, entity actor, entity trigger)
this.use(this, NULL, toucher);
}
-void W_Arc_Attack_Bolt(Weapon thiswep, entity actor)
+void W_Arc_Attack_Bolt(Weapon thiswep, entity actor, .entity weaponentity)
{
entity missile;
W_DecreaseAmmo(thiswep, actor, WEP_CVAR(arc, bolt_ammo));
- W_SetupShot(actor, false, 2, SND_LASERGUN_FIRE, CH_WEAPON_A, WEP_CVAR(arc, bolt_damage));
+ W_SetupShot(actor, weaponentity, false, 2, SND_LASERGUN_FIRE, CH_WEAPON_A, WEP_CVAR(arc, bolt_damage));
Send_Effect(EFFECT_ARC_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
void W_Arc_Beam_Think(entity this)
{
- if(this != this.owner.arc_beam)
+ .entity weaponentity = this.weaponentity_fld;
+ if(this != this.owner.(weaponentity).arc_beam)
{
- remove(this);
+ delete(this);
return;
}
-
float burst = 0;
if( (PHYS_INPUT_BUTTON_ATCK2(this.owner) && !WEP_CVAR(arc, bolt)) || this.beam_bursting)
{
}
}
- if(this == this.owner.arc_beam) { this.owner.arc_beam = NULL; }
+ if(this == this.owner.(weaponentity).arc_beam) { this.owner.(weaponentity).arc_beam = NULL; }
entity own = this.owner;
Weapon w = WEP_ARC;
if(!w.wr_checkammo1(w, own) && !w.wr_checkammo2(w, own))
// note: this doesn't force the switch
W_SwitchToOtherWeapon(own);
}
- remove(this);
+ delete(this);
return;
}
W_SetupShot_Range(
this.owner,
+ weaponentity, // TODO
true,
0,
SND_Null,
this.nextthink = time;
}
-void W_Arc_Beam(float burst, entity actor)
+void W_Arc_Beam(float burst, entity actor, .entity weaponentity)
{
// only play fire sound if 1 sec has passed since player let go the fire button
if(time - actor.beam_prev > 1)
sound(actor, CH_WEAPON_A, SND_ARC_FIRE, VOL_BASE, ATTN_NORM);
- entity beam = actor.arc_beam = new(W_Arc_Beam);
+ entity beam = actor.(weaponentity).arc_beam = new(W_Arc_Beam);
+ beam.weaponentity_fld = weaponentity;
beam.solid = SOLID_NOT;
setthink(beam, W_Arc_Beam_Think);
beam.owner = actor;
getthink(beam)(beam);
}
-void Arc_Smoke(entity actor)
+void Arc_Smoke(entity actor, .entity weaponentity)
{
makevectors(actor.v_angle);
- W_SetupShot_Range(actor,true,0,SND_Null,0,0,0);
+ W_SetupShot_Range(actor,weaponentity,true,0,SND_Null,0,0,0);
vector smoke_origin = w_shotorg + actor.velocity*frametime;
if ( actor.arc_overheat > time )
}
}
}
- else if ( actor.arc_beam && WEP_CVAR(arc, overheat_max) > 0 &&
- actor.arc_beam.beam_heat > WEP_CVAR(arc, overheat_min) )
+ else if ( actor.(weaponentity).arc_beam && WEP_CVAR(arc, overheat_max) > 0 &&
+ actor.(weaponentity).arc_beam.beam_heat > WEP_CVAR(arc, overheat_min) )
{
- if ( random() < (actor.arc_beam.beam_heat-WEP_CVAR(arc, overheat_min)) /
+ if ( random() < (actor.(weaponentity).arc_beam.beam_heat-WEP_CVAR(arc, overheat_min)) /
( WEP_CVAR(arc, overheat_max)-WEP_CVAR(arc, overheat_min) ) )
Send_Effect(EFFECT_ARC_SMOKE, smoke_origin, '0 0 0', 1 );
}
}
METHOD(Arc, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
- Arc_Player_SetHeat(actor);
- Arc_Smoke(actor);
+ Arc_Player_SetHeat(actor, weaponentity);
+ Arc_Smoke(actor, weaponentity);
bool beam_fire2 = ((fire & 2) && !WEP_CVAR(arc, bolt));
+ int slot = weaponslot(weaponentity);
if (time >= actor.arc_overheat)
- if ((fire & 1) || beam_fire2 || actor.arc_beam.beam_bursting)
+ if ((fire & 1) || beam_fire2 || actor.(weaponentity).arc_beam.beam_bursting)
{
- if(actor.arc_BUTTON_ATCK_prev)
+ if(actor.arc_BUTTON_ATCK_prev[slot])
{
#if 0
if(actor.animstate_startframe == actor.anim_shoot.x && actor.animstate_numframes == actor.anim_shoot.y)
weapon_thinkf(actor, weaponentity, WFRAME_DONTCHANGE, WEP_CVAR(arc, beam_animtime), w_ready);
}
- if((!actor.arc_beam) || wasfreed(actor.arc_beam))
+ if((!actor.(weaponentity).arc_beam) || wasfreed(actor.(weaponentity).arc_beam))
{
if(weapon_prepareattack(thiswep, actor, weaponentity, boolean(beam_fire2), 0))
{
- W_Arc_Beam(boolean(beam_fire2), actor);
+ W_Arc_Beam(boolean(beam_fire2), actor, weaponentity);
- if(!actor.arc_BUTTON_ATCK_prev)
+ if(!actor.arc_BUTTON_ATCK_prev[slot])
{
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(arc, beam_animtime), w_ready);
- actor.arc_BUTTON_ATCK_prev = true;
+ actor.arc_BUTTON_ATCK_prev[slot] = true;
}
}
}
{
if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(arc, bolt_refire)))
{
- W_Arc_Attack_Bolt(thiswep, actor);
+ W_Arc_Attack_Bolt(thiswep, actor, weaponentity);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(arc, bolt_refire), w_ready);
}
}
- if(actor.arc_BUTTON_ATCK_prev)
+ if(actor.arc_BUTTON_ATCK_prev[slot])
{
sound(actor, CH_WEAPON_A, SND_ARC_STOP, VOL_BASE, ATTN_NORM);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(arc, beam_animtime), w_ready);
- int slot = weaponslot(weaponentity);
ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(arc, beam_refire) * W_WeaponRateFactor(actor);
}
- actor.arc_BUTTON_ATCK_prev = false;
+ actor.arc_BUTTON_ATCK_prev[slot] = false;
#if 0
if(fire & 2)
weapon_dropevent_item.arc_cooldown = actor.arc_cooldown;
actor.arc_overheat = 0;
actor.arc_cooldown = 0;
- actor.arc_BUTTON_ATCK_prev = false;
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ actor.arc_BUTTON_ATCK_prev[slot] = false;
}
METHOD(Arc, wr_pickup, void(entity thiswep, entity actor))
{
{
actor.arc_overheat = 0;
actor.arc_cooldown = 0;
- actor.arc_BUTTON_ATCK_prev = false;
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ actor.arc_BUTTON_ATCK_prev[slot] = false;
}
-METHOD(Arc, wr_playerdeath, void(entity thiswep, entity actor))
+METHOD(Arc, wr_playerdeath, void(entity thiswep, entity actor, .entity weaponentity))
{
actor.arc_overheat = 0;
actor.arc_cooldown = 0;
- actor.arc_BUTTON_ATCK_prev = false;
+ int slot = weaponslot(weaponentity);
+ actor.arc_BUTTON_ATCK_prev[slot] = false;
}
#endif
#ifdef CSQC
void Remove_ArcBeam(entity this)
{
- remove(this.beam_muzzleentity);
+ delete(this.beam_muzzleentity);
sound(this, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM);
}
#ifndef IMPLEMENTATION
CLASS(Blaster, Weapon)
-/* ammotype */ //ATTRIB(Blaster, ammo_field, .int, ammo_none)
-/* impulse */ ATTRIB(Blaster, impulse, int, 1)
+/* ammotype */ //ATTRIB(Blaster, ammo_field, .int, ammo_none);
+/* impulse */ ATTRIB(Blaster, impulse, int, 1);
/* flags */ ATTRIB(Blaster, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH);
/* rating */ ATTRIB(Blaster, bot_pickupbasevalue, float, 0);
/* color */ ATTRIB(Blaster, wpcolor, vector, '1 0.5 0.5');
toucher
);
- remove(this);
+ delete(this);
}
void W_Blaster_Think(entity this)
void W_Blaster_Attack(
entity actor,
+ .entity weaponentity,
float atk_deathtype,
float atk_shotangle,
float atk_damage,
{
vector s_forward = v_forward * cos(atk_shotangle * DEG2RAD) + v_up * sin(atk_shotangle * DEG2RAD);
- W_SetupShot_Dir(actor, s_forward, false, 3, SND_LASERGUN_FIRE, CH_WEAPON_B, atk_damage);
+ W_SetupShot_Dir(actor, weaponentity, s_forward, false, 3, SND_LASERGUN_FIRE, CH_WEAPON_B, atk_damage);
Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
entity missile = new(blasterbolt);
settouch(missile, W_Blaster_Touch);
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
missile.missile_flags = MIF_SPLASH;
missile.projectiledeathtype = atk_deathtype;
setthink(missile, W_Blaster_Think);
{
W_Blaster_Attack(
actor,
+ weaponentity,
WEP_BLASTER.m_id,
WEP_CVAR_PRI(blaster, shotangle),
WEP_CVAR_PRI(blaster, damage),
{
W_Blaster_Attack(
actor,
+ weaponentity,
WEP_BLASTER.m_id | HITTYPE_SECONDARY,
WEP_CVAR_SEC(blaster, shotangle),
WEP_CVAR_SEC(blaster, damage),
#ifndef IMPLEMENTATION
CLASS(Crylink, Weapon)
-/* ammotype */ ATTRIB(Crylink, ammo_field, .int, ammo_cells)
-/* impulse */ ATTRIB(Crylink, impulse, int, 6)
+/* ammotype */ ATTRIB(Crylink, ammo_field, .int, ammo_cells);
+/* impulse */ ATTRIB(Crylink, impulse, int, 6);
/* flags */ ATTRIB(Crylink, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH);
/* rating */ ATTRIB(Crylink, bot_pickupbasevalue, float, BOT_PICKUP_RATING_MID);
/* color */ ATTRIB(Crylink, wpcolor, vector, '1 0.5 1');
void W_Crylink_Reset(entity this)
{
W_Crylink_Dequeue(this);
- remove(this);
+ delete(this);
}
// force projectile to explode
float isprimary = !(e.projectiledeathtype & HITTYPE_SECONDARY);
- RadiusDamage(e, e.realowner, WEP_CVAR_BOTH(crylink, isprimary, damage) * a, WEP_CVAR_BOTH(crylink, isprimary, edgedamage) * a, WEP_CVAR_BOTH(crylink, isprimary, radius),
+ RadiusDamage(e, e.realowner, WEP_CVAR_BOTH(crylink, isprimary, damage) * a, WEP_CVAR_BOTH(crylink, isprimary, edgedamage) * a, WEP_CVAR_BOTH(crylink, isprimary, radius),
NULL, NULL, WEP_CVAR_BOTH(crylink, isprimary, force) * a, e.projectiledeathtype, directhitentity);
W_Crylink_LinkExplode(e.queuenext, e2, directhitentity);
e.classname = "spike_oktoremove";
- remove(e);
+ delete(e);
}
// adjust towards center
}
}
}
- remove(this);
+ delete(this);
}
float W_Crylink_Touch_WouldHitFriendly(entity projectile, float rad)
this.realowner.crylink_lastgroup = NULL;
W_Crylink_LinkExplode(this.queuenext, this, toucher);
this.classname = "spike_oktoremove";
- remove(this);
+ delete(this);
return;
}
else if(finalhit)
{
// just unlink
W_Crylink_Dequeue(this);
- remove(this);
+ delete(this);
return;
}
this.cnt = this.cnt - 1;
void W_Crylink_Fadethink(entity this)
{
W_Crylink_Dequeue(this);
- remove(this);
+ delete(this);
}
-void W_Crylink_Attack(Weapon thiswep, entity actor)
+void W_Crylink_Attack(Weapon thiswep, entity actor, .entity weaponentity)
{
float counter, shots;
entity proj, prevproj, firstproj;
if(WEP_CVAR_PRI(crylink, joinexplode))
maxdmg += WEP_CVAR_PRI(crylink, joinexplode_damage);
- W_SetupShot(actor, false, 2, SND_CRYLINK_FIRE, CH_WEAPON_A, maxdmg);
+ W_SetupShot(actor, weaponentity, false, 2, SND_CRYLINK_FIRE, CH_WEAPON_A, maxdmg);
forward = v_forward;
right = v_right;
up = v_up;
//proj.glow_size = 20;
proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.missile_flags = MIF_SPLASH;
CSQCProjectile(proj, true, (proj.cnt ? PROJECTILE_CRYLINK_BOUNCING : PROJECTILE_CRYLINK), true);
}
}
-void W_Crylink_Attack2(Weapon thiswep, entity actor)
+void W_Crylink_Attack2(Weapon thiswep, entity actor, .entity weaponentity)
{
float counter, shots;
entity proj, prevproj, firstproj;
if(WEP_CVAR_SEC(crylink, joinexplode))
maxdmg += WEP_CVAR_SEC(crylink, joinexplode_damage);
- W_SetupShot(actor, false, 2, SND_CRYLINK_FIRE2, CH_WEAPON_A, maxdmg);
+ W_SetupShot(actor, weaponentity, false, 2, SND_CRYLINK_FIRE2, CH_WEAPON_A, maxdmg);
forward = v_forward;
right = v_right;
up = v_up;
//proj.glow_size = 20;
proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.missile_flags = MIF_SPLASH;
CSQCProjectile(proj, true, (proj.cnt ? PROJECTILE_CRYLINK_BOUNCING : PROJECTILE_CRYLINK), true);
if(actor.crylink_waitrelease != 1)
if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(crylink, refire)))
{
- W_Crylink_Attack(thiswep, actor);
+ W_Crylink_Attack(thiswep, actor, weaponentity);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(crylink, animtime), w_ready);
}
}
if(actor.crylink_waitrelease != 2)
if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(crylink, refire)))
{
- W_Crylink_Attack2(thiswep, actor);
+ W_Crylink_Attack2(thiswep, actor, weaponentity);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(crylink, animtime), w_ready);
}
}
}
METHOD(Crylink, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
{
- W_Reload(actor, min(WEP_CVAR_PRI(crylink, ammo), WEP_CVAR_SEC(crylink, ammo)), SND_RELOAD);
+ W_Reload(actor, weaponentity, min(WEP_CVAR_PRI(crylink, ammo), WEP_CVAR_SEC(crylink, ammo)), SND_RELOAD);
}
METHOD(Crylink, wr_suicidemessage, Notification(entity thiswep))
{
#ifndef IMPLEMENTATION
CLASS(Devastator, Weapon)
-/* ammotype */ ATTRIB(Devastator, ammo_field, .int, ammo_rockets)
-/* impulse */ ATTRIB(Devastator, impulse, int, 9)
+/* ammotype */ ATTRIB(Devastator, ammo_field, .int, ammo_rockets);
+/* impulse */ ATTRIB(Devastator, impulse, int, 9);
/* flags */ ATTRIB(Devastator, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH);
/* rating */ ATTRIB(Devastator, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
/* color */ ATTRIB(Devastator, wpcolor, vector, '1 1 0');
REGISTER_WEAPON(DEVASTATOR, devastator, NEW(Devastator));
#ifdef SVQC
-.float rl_release;
+.float rl_release[MAX_WEAPONSLOTS];
.float rl_detonate_later;
#endif
#endif
{
if(this.realowner && this.realowner.lastrocket == this)
{
- this.realowner.lastrocket = NULL;
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ if(this.realowner.(weaponentity).lastrocket == this)
+ this.realowner.(weaponentity).lastrocket = NULL;
+ }
// this.realowner.rl_release = 1;
}
}
PS(this.realowner).m_switchweapon = w_getbestweapon(this.realowner);
}
}
- remove(this);
+ delete(this);
}
void W_Devastator_Explode_think(entity this)
PS(this.realowner).m_switchweapon = w_getbestweapon(this.realowner);
}
}
- remove(this);
+ delete(this);
}
void W_Devastator_RemoteExplode(entity this, .entity weaponentity)
{
if(!IS_DEAD(this.realowner))
- if(this.realowner.lastrocket)
+ if(this.realowner.(weaponentity).lastrocket)
{
if((this.spawnshieldtime >= 0)
? (time >= this.spawnshieldtime) // timer
// laser guided, or remote detonation
if(PS(this.realowner).m_weapon == WEP_DEVASTATOR)
{
- if(this == this.realowner.lastrocket)
- if(!this.realowner.rl_release)
+ .entity weaponentity = this.weaponentity_fld;
+ int slot = weaponslot(weaponentity);
+
+ if(this == this.realowner.(weaponentity).lastrocket)
+ if(!this.realowner.rl_release[slot])
if(!PHYS_INPUT_BUTTON_ATCK2(this))
if(WEP_CVAR(devastator, guiderate))
if(time > this.pushltime)
}
}
- .entity weaponentity = weaponentities[0]; // TODO: unhardcode
if(this.rl_detonate_later)
W_Devastator_RemoteExplode(this, weaponentity);
}
W_PrepareExplosionByDamage(this, attacker, W_Devastator_Explode_think);
}
-void W_Devastator_Attack(Weapon thiswep, entity actor)
+void W_Devastator_Attack(Weapon thiswep, entity actor, .entity weaponentity)
{
W_DecreaseAmmo(thiswep, actor, WEP_CVAR(devastator, ammo));
- W_SetupShot_ProjectileSize(actor, '-3 -3 -3', '3 3 3', false, 5, SND_ROCKET_FIRE, CH_WEAPON_A, WEP_CVAR(devastator, damage));
+ W_SetupShot_ProjectileSize(actor, weaponentity, '-3 -3 -3', '3 3 3', false, 5, SND_ROCKET_FIRE, CH_WEAPON_A, WEP_CVAR(devastator, damage));
Send_Effect(EFFECT_ROCKET_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
entity missile = WarpZone_RefSys_SpawnSameRefSys(actor);
+ missile.weaponentity_fld = weaponentity;
missile.owner = missile.realowner = actor;
- actor.lastrocket = missile;
+ actor.(weaponentity).lastrocket = missile;
if(WEP_CVAR(devastator, detonatedelay) >= 0)
missile.spawnshieldtime = time + WEP_CVAR(devastator, detonatedelay);
else
missile.nextthink = time;
missile.cnt = time + WEP_CVAR(devastator, lifetime);
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
missile.missile_flags = MIF_SPLASH;
CSQCProjectile(missile, WEP_CVAR(devastator, guiderate) == 0 && WEP_CVAR(devastator, speedaccel) == 0, PROJECTILE_ROCKET, false); // because of fly sound
setmodel(flash, MDL_DEVASTATOR_MUZZLEFLASH); // precision set below
SUB_SetFade(flash, time, 0.1);
flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
- W_AttachToShotorg(actor, flash, '5 0 0');
+ W_AttachToShotorg(actor, weaponentity, flash, '5 0 0');
// common properties
MUTATOR_CALLHOOK(EditProjectile, actor, missile);
if(WEP_CVAR(devastator, reload_ammo) && actor.clip_load < WEP_CVAR(devastator, ammo)) { // forced reload
thiswep.wr_reload(thiswep, actor, weaponentity);
} else {
+ int slot = weaponslot(weaponentity);
if(fire & 1)
{
- if(actor.rl_release || WEP_CVAR(devastator, guidestop))
+ if(actor.rl_release[slot] || WEP_CVAR(devastator, guidestop))
if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(devastator, refire)))
{
- W_Devastator_Attack(thiswep, actor);
+ W_Devastator_Attack(thiswep, actor, weaponentity);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(devastator, animtime), w_ready);
- actor.rl_release = 0;
+ actor.rl_release[slot] = 0;
}
}
else
- actor.rl_release = 1;
+ actor.rl_release[slot] = 1;
if(fire & 2)
if(PS(actor).m_switchweapon == WEP_DEVASTATOR)
}
METHOD(Devastator, wr_setup, void(entity thiswep, entity actor))
{
- actor.rl_release = 1;
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ actor.rl_release[slot] = 1;
}
METHOD(Devastator, wr_checkammo1, bool(entity thiswep, entity actor))
{
}
METHOD(Devastator, wr_resetplayer, void(entity thiswep, entity actor))
{
- actor.lastrocket = NULL; // stop rocket guiding, no revenge from the grave!
- actor.rl_release = 0;
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ actor.(weaponentity).lastrocket = NULL; // stop rocket guiding, no revenge from the grave!
+ actor.rl_release[slot] = 0;
+ }
}
METHOD(Devastator, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
{
- W_Reload(actor, WEP_CVAR(devastator, ammo), SND_RELOAD);
+ W_Reload(actor, weaponentity, WEP_CVAR(devastator, ammo), SND_RELOAD);
}
METHOD(Devastator, wr_suicidemessage, Notification(entity thiswep))
{
#ifndef IMPLEMENTATION
CLASS(Electro, Weapon)
-/* ammotype */ ATTRIB(Electro, ammo_field, .int, ammo_cells)
-/* impulse */ ATTRIB(Electro, impulse, int, 5)
+/* ammotype */ ATTRIB(Electro, ammo_field, .int, ammo_cells);
+/* impulse */ ATTRIB(Electro, impulse, int, 5);
/* flags */ ATTRIB(Electro, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH);
/* rating */ ATTRIB(Electro, bot_pickupbasevalue, float, BOT_PICKUP_RATING_MID);
/* color */ ATTRIB(Electro, wpcolor, vector, '0 0.5 1');
NULL
);
- remove(this);
+ delete(this);
}
void W_Electro_Explode(entity this, entity directhitentity)
);
}
- remove(this);
+ delete(this);
}
void W_Electro_Explode_use(entity this, entity actor, entity trigger)
W_Electro_Explode(this, toucher);
}
+
+void sys_phys_update_single(entity this);
+
void W_Electro_Bolt_Think(entity this)
{
+ // sys_phys_update_single(this);
if(time >= this.ltime)
{
this.use(this, NULL, NULL);
{ this.nextthink = min(time + WEP_CVAR_PRI(electro, midaircombo_interval), this.ltime); }
}
else { this.nextthink = this.ltime; }
+ // this.nextthink = time;
}
-void W_Electro_Attack_Bolt(Weapon thiswep, entity actor)
+void W_Electro_Attack_Bolt(Weapon thiswep, entity actor, .entity weaponentity)
{
entity proj;
W_SetupShot_ProjectileSize(
actor,
+ weaponentity,
'0 0 -3',
'0 0 -3',
false,
proj.projectiledeathtype = WEP_ELECTRO.m_id;
setorigin(proj, w_shotorg);
+ // if (IS_CSQC)
set_movetype(proj, MOVETYPE_FLY);
W_SetupProjVelocity_PRI(proj, electro);
proj.angles = vectoangles(proj.velocity);
settouch(proj, W_Electro_TouchExplode);
setsize(proj, '0 0 -3', '0 0 -3');
proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.missile_flags = MIF_SPLASH;
CSQCProjectile(proj, true, PROJECTILE_ELECTRO_BEAM, true);
MUTATOR_CALLHOOK(EditProjectile, actor, proj);
+ // proj.com_phys_pos = proj.origin;
+ // proj.com_phys_vel = proj.velocity;
}
void W_Electro_Orb_Stick(entity this, entity to)
newproj.use = this.use;
newproj.flags = this.flags;
- remove(this);
+ delete(this);
if(to)
SetMovetypeFollow(this, to);
}
}
-void W_Electro_Attack_Orb(Weapon thiswep, entity actor)
+void W_Electro_Attack_Orb(Weapon thiswep, entity actor, .entity weaponentity)
{
W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(electro, ammo));
W_SetupShot_ProjectileSize(
actor,
+ weaponentity,
'-4 -4 -4',
'4 4 4',
false,
proj.health = WEP_CVAR_SEC(electro, health);
proj.event_damage = W_Electro_Orb_Damage;
proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.damagedbycontents = (WEP_CVAR_SEC(electro, damagedbycontents));
proj.bouncefactor = WEP_CVAR_SEC(electro, bouncefactor);
if(PHYS_INPUT_BUTTON_ATCK2(actor))
if(weapon_prepareattack(thiswep, actor, weaponentity, true, -1))
{
- W_Electro_Attack_Orb(WEP_ELECTRO, actor);
+ W_Electro_Attack_Orb(WEP_ELECTRO, actor, weaponentity);
actor.electro_count -= 1;
weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(electro, animtime), W_Electro_CheckAttack);
return;
{
if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire)))
{
- W_Electro_Attack_Bolt(thiswep, actor);
+ W_Electro_Attack_Bolt(thiswep, actor, weaponentity);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
}
}
if(time >= actor.electro_secondarytime)
if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(electro, refire)))
{
- W_Electro_Attack_Orb(thiswep, actor);
+ W_Electro_Attack_Orb(thiswep, actor, weaponentity);
actor.electro_count = WEP_CVAR_SEC(electro, count);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(electro, animtime), W_Electro_CheckAttack);
actor.electro_secondarytime = time + WEP_CVAR_SEC(electro, refire2) * W_WeaponRateFactor(actor);
}
METHOD(Electro, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
{
- W_Reload(actor, min(WEP_CVAR_PRI(electro, ammo), WEP_CVAR_SEC(electro, ammo)), SND_RELOAD);
+ W_Reload(actor, weaponentity, min(WEP_CVAR_PRI(electro, ammo), WEP_CVAR_SEC(electro, ammo)), SND_RELOAD);
}
METHOD(Electro, wr_suicidemessage, Notification(entity thiswep))
{
#ifndef IMPLEMENTATION
CLASS(Fireball, Weapon)
-/* ammotype */ //ATTRIB(Fireball, ammo_field, .int, ammo_none)
-/* impulse */ ATTRIB(Fireball, impulse, int, 9)
+/* ammotype */ //ATTRIB(Fireball, ammo_field, .int, ammo_none);
+/* impulse */ ATTRIB(Fireball, impulse, int, 9);
/* flags */ ATTRIB(Fireball, spawnflags, int, WEP_FLAG_SUPERWEAPON | WEP_TYPE_SPLASH);
/* rating */ ATTRIB(Fireball, bot_pickupbasevalue, float, BOT_PICKUP_RATING_MID);
/* color */ ATTRIB(Fireball, wpcolor, vector, '1 0.5 0');
#ifdef SVQC
.float bot_primary_fireballmooth; // whatever a mooth is
.vector fireball_impactvec;
-.float fireball_primarytime;
+.float fireball_primarytime[MAX_WEAPONSLOTS];
#endif
#endif
#ifdef IMPLEMENTATION
}
}
- remove(this);
+ delete(this);
}
void W_Fireball_Explode_think(entity this)
}
}
-void W_Fireball_Attack1(entity actor)
+void W_Fireball_Attack1(entity actor, .entity weaponentity)
{
- entity proj;
-
- W_SetupShot_ProjectileSize(actor, '-16 -16 -16', '16 16 16', false, 2, SND_FIREBALL_FIRE2, CH_WEAPON_A, WEP_CVAR_PRI(fireball, damage) + WEP_CVAR_PRI(fireball, bfgdamage));
+ W_SetupShot_ProjectileSize(actor, weaponentity, '-16 -16 -16', '16 16 16', false, 2, SND_FIREBALL_FIRE2, CH_WEAPON_A, WEP_CVAR_PRI(fireball, damage) + WEP_CVAR_PRI(fireball, bfgdamage));
Send_Effect(EFFECT_FIREBALL_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
- proj = new(plasma_prim);
+ entity proj = new(plasma_prim);
proj.owner = proj.realowner = actor;
proj.bot_dodge = true;
proj.bot_dodgerating = WEP_CVAR_PRI(fireball, damage);
settouch(proj, W_Fireball_TouchExplode);
setsize(proj, '-16 -16 -16', '16 16 16');
proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.missile_flags = MIF_SPLASH | MIF_PROXY;
CSQCProjectile(proj, true, PROJECTILE_FIREBALL, true);
MUTATOR_CALLHOOK(EditProjectile, actor, proj);
}
-void W_Fireball_AttackEffect(entity actor, float i, vector f_diff)
+void W_Fireball_AttackEffect(entity actor, .entity weaponentity, float i, vector f_diff)
{
- W_SetupShot_ProjectileSize(actor, '-16 -16 -16', '16 16 16', false, 0, SND_Null, 0, 0);
+ W_SetupShot_ProjectileSize(actor, weaponentity, '-16 -16 -16', '16 16 16', false, 0, SND_Null, 0, 0);
w_shotorg += f_diff.x * v_up + f_diff.y * v_right;
Send_Effect(EFFECT_FIREBALL_PRE_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
}
void W_Fireball_Attack1_Frame4(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
- W_Fireball_Attack1(actor);
+ W_Fireball_Attack1(actor, weaponentity);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), w_ready);
}
void W_Fireball_Attack1_Frame3(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
- W_Fireball_AttackEffect(actor, 0, '+1.25 +3.75 0');
+ W_Fireball_AttackEffect(actor, weaponentity, 0, '+1.25 +3.75 0');
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), W_Fireball_Attack1_Frame4);
}
void W_Fireball_Attack1_Frame2(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
- W_Fireball_AttackEffect(actor, 0, '-1.25 +3.75 0');
+ W_Fireball_AttackEffect(actor, weaponentity, 0, '-1.25 +3.75 0');
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), W_Fireball_Attack1_Frame3);
}
void W_Fireball_Attack1_Frame1(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
- W_Fireball_AttackEffect(actor, 1, '+1.25 -3.75 0');
+ W_Fireball_AttackEffect(actor, weaponentity, 1, '+1.25 -3.75 0');
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), W_Fireball_Attack1_Frame2);
}
void W_Fireball_Attack1_Frame0(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
- W_Fireball_AttackEffect(actor, 0, '-1.25 -3.75 0');
+ W_Fireball_AttackEffect(actor, weaponentity, 0, '-1.25 -3.75 0');
sound(actor, CH_WEAPON_SINGLE, SND_FIREBALL_PREFIRE2, VOL_BASE, ATTEN_NORM);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), W_Fireball_Attack1_Frame1);
}
{
if(time > this.pushltime)
{
- remove(this);
+ delete(this);
return;
}
if(toucher.takedamage == DAMAGE_AIM)
if(Fire_AddDamage(toucher, this.realowner, WEP_CVAR_SEC(fireball, damage), WEP_CVAR_SEC(fireball, damagetime), this.projectiledeathtype) >= 0)
{
- remove(this);
+ delete(this);
return;
}
this.projectiledeathtype |= HITTYPE_BOUNCE;
}
-void W_Fireball_Attack2(entity actor)
+void W_Fireball_Attack2(entity actor, .entity weaponentity)
{
entity proj;
vector f_diff;
f_diff = '+1.25 +3.75 0';
break;
}
- W_SetupShot_ProjectileSize(actor, '-4 -4 -4', '4 4 4', false, 2, SND_FIREBALL_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(fireball, damage));
+ W_SetupShot_ProjectileSize(actor, weaponentity, '-4 -4 -4', '4 4 4', false, 2, SND_FIREBALL_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(fireball, damage));
traceline(w_shotorg, w_shotorg + f_diff_x * v_up + f_diff_y * v_right, MOVE_NORMAL, actor);
w_shotorg = trace_endpos;
proj.angles = vectoangles(proj.velocity);
proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_ARC;
CSQCProjectile(proj, true, PROJECTILE_FIREMINE, true);
{
if(fire & 1)
{
- if(time >= actor.fireball_primarytime)
+ int slot = weaponslot(weaponentity);
+ if(time >= actor.fireball_primarytime[slot])
if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(fireball, refire)))
{
W_Fireball_Attack1_Frame0(thiswep, actor, weaponentity, fire);
- actor.fireball_primarytime = time + WEP_CVAR_PRI(fireball, refire2) * W_WeaponRateFactor(actor);
+ actor.fireball_primarytime[slot] = time + WEP_CVAR_PRI(fireball, refire2) * W_WeaponRateFactor(actor);
}
}
else if(fire & 2)
{
if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(fireball, refire)))
{
- W_Fireball_Attack2(actor);
+ W_Fireball_Attack2(actor, weaponentity);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(fireball, animtime), w_ready);
}
}
}
METHOD(Fireball, wr_resetplayer, void(entity thiswep, entity actor))
{
- actor.fireball_primarytime = time;
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ actor.fireball_primarytime[slot] = time;
}
METHOD(Fireball, wr_suicidemessage, Notification(entity thiswep))
{
#ifndef IMPLEMENTATION
CLASS(Hagar, Weapon)
-/* ammotype */ ATTRIB(Hagar, ammo_field, .int, ammo_rockets)
-/* impulse */ ATTRIB(Hagar, impulse, int, 8)
+/* ammotype */ ATTRIB(Hagar, ammo_field, .int, ammo_rockets);
+/* impulse */ ATTRIB(Hagar, impulse, int, 8);
/* flags */ ATTRIB(Hagar, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH);
/* rating */ ATTRIB(Hagar, bot_pickupbasevalue, float, BOT_PICKUP_RATING_MID);
/* color */ ATTRIB(Hagar, wpcolor, vector, '1 1 0.5');
this.event_damage = func_null;
RadiusDamage(this, this.realowner, WEP_CVAR_PRI(hagar, damage), WEP_CVAR_PRI(hagar, edgedamage), WEP_CVAR_PRI(hagar, radius), NULL, NULL, WEP_CVAR_PRI(hagar, force), this.projectiledeathtype, directhitentity);
- remove(this);
+ delete(this);
}
void W_Hagar_Explode_use(entity this, entity actor, entity trigger)
this.event_damage = func_null;
RadiusDamage(this, this.realowner, WEP_CVAR_SEC(hagar, damage), WEP_CVAR_SEC(hagar, edgedamage), WEP_CVAR_SEC(hagar, radius), NULL, NULL, WEP_CVAR_SEC(hagar, force), this.projectiledeathtype, directhitentity);
- remove(this);
+ delete(this);
}
void W_Hagar_Explode2_use(entity this, entity actor, entity trigger)
}
}
-void W_Hagar_Attack(Weapon thiswep, entity actor)
+void W_Hagar_Attack(Weapon thiswep, entity actor, .entity weaponentity)
{
entity missile;
W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(hagar, ammo));
- W_SetupShot(actor, false, 2, SND_HAGAR_FIRE, CH_WEAPON_A, WEP_CVAR_PRI(hagar, damage));
+ W_SetupShot(actor, weaponentity, false, 2, SND_HAGAR_FIRE, CH_WEAPON_A, WEP_CVAR_PRI(hagar, damage));
Send_Effect(EFFECT_HAGAR_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
missile.angles = vectoangles(missile.velocity);
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
missile.missile_flags = MIF_SPLASH;
CSQCProjectile(missile, true, PROJECTILE_HAGAR, true);
MUTATOR_CALLHOOK(EditProjectile, actor, missile);
}
-void W_Hagar_Attack2(Weapon thiswep, entity actor)
+void W_Hagar_Attack2(Weapon thiswep, entity actor, .entity weaponentity)
{
entity missile;
W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(hagar, ammo));
- W_SetupShot(actor, false, 2, SND_HAGAR_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(hagar, damage));
+ W_SetupShot(actor, weaponentity, false, 2, SND_HAGAR_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(hagar, damage));
Send_Effect(EFFECT_HAGAR_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
missile.angles = vectoangles(missile.velocity);
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
missile.missile_flags = MIF_SPLASH;
CSQCProjectile(missile, true, PROJECTILE_HAGAR_BOUNCING, true);
weapon_prepareattack_do(actor, weaponentity, true, WEP_CVAR_SEC(hagar, refire));
- W_SetupShot(actor, false, 2, SND_HAGAR_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(hagar, damage));
+ W_SetupShot(actor, weaponentity, false, 2, SND_HAGAR_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(hagar, damage));
Send_Effect(EFFECT_HAGAR_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
forward = v_forward;
missile.angles = vectoangles(missile.velocity);
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
CSQCProjectile(missile, true, PROJECTILE_HAGAR, true);
return;
}
- W_Hagar_Attack(thiswep, actor);
+ W_Hagar_Attack(thiswep, actor, weaponentity);
int slot = weaponslot(weaponentity);
ATTACK_FINISHED(actor, slot) = time + WEP_CVAR_PRI(hagar, refire) * W_WeaponRateFactor(actor);
{
if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(hagar, refire)))
{
- W_Hagar_Attack2(thiswep, actor);
+ W_Hagar_Attack2(thiswep, actor, weaponentity);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(hagar, refire), w_ready);
}
}
}
-METHOD(Hagar, wr_gonethink, void(entity thiswep, entity actor))
+METHOD(Hagar, wr_gonethink, void(entity thiswep, entity actor, .entity weaponentity))
{
// we lost the weapon and want to prepare switching away
if(actor.hagar_load)
{
- .entity weaponentity = weaponentities[0]; // TODO: unhardcode
- actor.(weaponentity).state = WS_READY;
- W_Hagar_Attack2_Load_Release(actor, weaponentity);
+ actor.(weaponentity).state = WS_READY;
+ W_Hagar_Attack2_Load_Release(actor, weaponentity);
}
}
METHOD(Hagar, wr_setup, void(entity thiswep, entity actor))
{
actor.hagar_load = 0;
}
-METHOD(Hagar, wr_playerdeath, void(entity thiswep, entity actor))
+METHOD(Hagar, wr_playerdeath, void(entity thiswep, entity actor, .entity weaponentity))
{
- .entity weaponentity = weaponentities[0]; // TODO: unhardcode
// if we have any rockets loaded when we die, release them
if(actor.hagar_load && WEP_CVAR_SEC(hagar, load_releasedeath))
- W_Hagar_Attack2_Load_Release(actor, weaponentity);
+ W_Hagar_Attack2_Load_Release(actor, weaponentity);
}
METHOD(Hagar, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
{
if(!actor.hagar_load) // require releasing loaded rockets first
- W_Reload(actor, min(WEP_CVAR_PRI(hagar, ammo), WEP_CVAR_SEC(hagar, ammo)), SND_RELOAD);
+ W_Reload(actor, weaponentity, min(WEP_CVAR_PRI(hagar, ammo), WEP_CVAR_SEC(hagar, ammo)), SND_RELOAD);
}
METHOD(Hagar, wr_suicidemessage, Notification(entity thiswep))
{
#ifndef IMPLEMENTATION
CLASS(HLAC, Weapon)
-/* ammotype */ ATTRIB(HLAC, ammo_field, .int, ammo_cells)
-/* impulse */ ATTRIB(HLAC, impulse, int, 6)
+/* ammotype */ ATTRIB(HLAC, ammo_field, .int, ammo_cells);
+/* impulse */ ATTRIB(HLAC, impulse, int, 6);
/* flags */ ATTRIB(HLAC, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH);
/* rating */ ATTRIB(HLAC, bot_pickupbasevalue, float, BOT_PICKUP_RATING_MID);
/* color */ ATTRIB(HLAC, wpcolor, vector, '0 1 0');
RadiusDamage(this, this.realowner, WEP_CVAR_BOTH(hlac, isprimary, damage), WEP_CVAR_BOTH(hlac, isprimary, edgedamage), WEP_CVAR_BOTH(hlac, isprimary, radius), NULL, NULL, WEP_CVAR_BOTH(hlac, isprimary, force), this.projectiledeathtype, toucher);
- remove(this);
+ delete(this);
}
-void W_HLAC_Attack(Weapon thiswep, entity actor)
+void W_HLAC_Attack(Weapon thiswep, entity actor, .entity weaponentity)
{
entity missile;
float spread;
if(actor.crouch)
spread = spread * WEP_CVAR_PRI(hlac, spread_crouchmod);
- W_SetupShot(actor, false, 3, SND_LASERGUN_FIRE, CH_WEAPON_A, WEP_CVAR_PRI(hlac, damage));
+ W_SetupShot(actor, weaponentity, false, 3, SND_LASERGUN_FIRE, CH_WEAPON_A, WEP_CVAR_PRI(hlac, damage));
Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
if(!autocvar_g_norecoil)
{
missile.nextthink = time + WEP_CVAR_PRI(hlac, lifetime);
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
missile.projectiledeathtype = WEP_HLAC.m_id;
CSQCProjectile(missile, true, PROJECTILE_HLAC, true);
MUTATOR_CALLHOOK(EditProjectile, actor, missile);
}
-void W_HLAC_Attack2(entity actor)
+void W_HLAC_Attack2(entity actor, .entity weaponentity)
{
entity missile;
float spread;
if(actor.crouch)
spread = spread * WEP_CVAR_SEC(hlac, spread_crouchmod);
- W_SetupShot(actor, false, 3, SND_LASERGUN_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(hlac, damage));
+ W_SetupShot(actor, weaponentity, false, 3, SND_LASERGUN_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(hlac, damage));
Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
missile = new(hlacbolt);
missile.nextthink = time + WEP_CVAR_SEC(hlac, lifetime);
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
missile.missile_flags = MIF_SPLASH;
missile.projectiledeathtype = WEP_HLAC.m_id | HITTYPE_SECONDARY;
int slot = weaponslot(weaponentity);
ATTACK_FINISHED(actor, slot) = time + WEP_CVAR_PRI(hlac, refire) * W_WeaponRateFactor(actor);
- W_HLAC_Attack(WEP_HLAC, actor);
+ W_HLAC_Attack(WEP_HLAC, actor, weaponentity);
actor.misc_bulletcounter = actor.misc_bulletcounter + 1;
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(hlac, refire), W_HLAC_Attack_Frame);
}
}
}
-void W_HLAC_Attack2_Frame(Weapon thiswep, entity actor)
+void W_HLAC_Attack2_Frame(Weapon thiswep, entity actor, .entity weaponentity)
{
float i;
W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(hlac, ammo));
for(i=WEP_CVAR_SEC(hlac, shots);i>0;--i)
- W_HLAC_Attack2(actor);
+ W_HLAC_Attack2(actor, weaponentity);
if(!autocvar_g_norecoil)
{
if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(hlac, refire)))
{
actor.misc_bulletcounter = 0;
- W_HLAC_Attack(thiswep, actor);
+ W_HLAC_Attack(thiswep, actor, weaponentity);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(hlac, refire), W_HLAC_Attack_Frame);
}
}
{
if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(hlac, refire)))
{
- W_HLAC_Attack2_Frame(thiswep, actor);
+ W_HLAC_Attack2_Frame(thiswep, actor, weaponentity);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(hlac, animtime), w_ready);
}
}
}
METHOD(HLAC, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
{
- W_Reload(actor, min(WEP_CVAR_PRI(hlac, ammo), WEP_CVAR_SEC(hlac, ammo)), SND_RELOAD);
+ W_Reload(actor, weaponentity, min(WEP_CVAR_PRI(hlac, ammo), WEP_CVAR_SEC(hlac, ammo)), SND_RELOAD);
}
METHOD(HLAC, wr_suicidemessage, Notification(entity thiswep))
{
#ifndef IMPLEMENTATION
CLASS(Hook, Weapon)
-/* ammotype */ ATTRIB(Hook, ammo_field, .int, ammo_fuel)
-/* impulse */ ATTRIB(Hook, impulse, int, 0)
+/* ammotype */ ATTRIB(Hook, ammo_field, .int, ammo_fuel);
+/* impulse */ ATTRIB(Hook, impulse, int, 0);
/* flags */ ATTRIB(Hook, spawnflags, int, WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH);
/* rating */ ATTRIB(Hook, bot_pickupbasevalue, float, 0);
/* color */ ATTRIB(Hook, wpcolor, vector, '0 0.5 0');
/* wepimg */ ATTRIB(Hook, model2, string, "weaponhook");
/* refname */ ATTRIB(Hook, netname, string, "hook");
/* wepname */ ATTRIB(Hook, m_name, string, _("Grappling Hook"));
- ATTRIB(Hook, ammo_factor, float, 1)
+ ATTRIB(Hook, ammo_factor, float, 1);
#define X(BEGIN, P, END, class, prefix) \
BEGIN(class) \
if(dt < this.dmg_duration)
this.nextthink = time + 0.05; // soon
else
- remove(this);
+ delete(this);
}
void W_Hook_Explode2(entity this)
this.use(this, NULL, NULL);
}
-void W_Hook_Attack2(Weapon thiswep, entity actor)
+void W_Hook_Attack2(Weapon thiswep, entity actor, .entity weaponentity)
{
//W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(hook, ammo)); // WEAPONTODO: Figure out how to handle ammo with hook secondary (gravitybomb)
- W_SetupShot(actor, false, 4, SND_HOOKBOMB_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(hook, damage));
+ W_SetupShot(actor, weaponentity, false, 4, SND_HOOKBOMB_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(hook, damage));
entity gren = new(hookbomb);
gren.owner = gren.realowner = actor;
gren.angles = '0 0 0';
gren.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, gren);
CSQCProjectile(gren, true, PROJECTILE_HOOKBOMB, true);
{
if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(hook, refire)))
{
- W_Hook_Attack2(thiswep, actor);
+ W_Hook_Attack2(thiswep, actor, weaponentity);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(hook, animtime), w_ready);
}
}
#ifndef IMPLEMENTATION
CLASS(MachineGun, Weapon)
-/* ammotype */ ATTRIB(MachineGun, ammo_field, .int, ammo_nails)
-/* impulse */ ATTRIB(MachineGun, impulse, int, 3)
+/* ammotype */ ATTRIB(MachineGun, ammo_field, .int, ammo_nails);
+/* impulse */ ATTRIB(MachineGun, impulse, int, 3);
/* flags */ ATTRIB(MachineGun, spawnflags, int, WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN);
/* rating */ ATTRIB(MachineGun, bot_pickupbasevalue, float, BOT_PICKUP_RATING_MID);
/* color */ ATTRIB(MachineGun, wpcolor, vector, '1 1 0');
}
-void W_MachineGun_MuzzleFlash(entity actor)
+void W_MachineGun_MuzzleFlash(entity actor, .entity weaponentity)
{
- if(actor.muzzle_flash == NULL)
- actor.muzzle_flash = spawn();
+ entity wepent = actor.(weaponentity);
+
+ if(wepent.muzzle_flash == NULL)
+ wepent.muzzle_flash = spawn();
// muzzle flash for 1st person view
- setmodel(actor.muzzle_flash, MDL_MACHINEGUN_MUZZLEFLASH); // precision set below
-
- actor.muzzle_flash.scale = 0.75;
- setthink(actor.muzzle_flash, W_MachineGun_MuzzleFlash_Think);
- actor.muzzle_flash.nextthink = time + 0.02;
- actor.muzzle_flash.frame = 2;
- actor.muzzle_flash.alpha = 0.75;
- actor.muzzle_flash.angles_z = random() * 180;
- actor.muzzle_flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
- actor.muzzle_flash.owner = actor.muzzle_flash.realowner = actor;
+ setmodel(wepent.muzzle_flash, MDL_MACHINEGUN_MUZZLEFLASH); // precision set below
+
+ wepent.muzzle_flash.scale = 0.75;
+ setthink(wepent.muzzle_flash, W_MachineGun_MuzzleFlash_Think);
+ wepent.muzzle_flash.nextthink = time + 0.02;
+ wepent.muzzle_flash.frame = 2;
+ wepent.muzzle_flash.alpha = 0.75;
+ wepent.muzzle_flash.angles_z = random() * 180;
+ wepent.muzzle_flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
+ wepent.muzzle_flash.owner = wepent.muzzle_flash.realowner = wepent;
}
void W_MachineGun_Attack(Weapon thiswep, int deathtype, entity actor, .entity weaponentity)
{
- W_SetupShot(actor, true, 0, SND_UZI_FIRE, CH_WEAPON_A, ((actor.misc_bulletcounter == 1) ? WEP_CVAR(machinegun, first_damage) : WEP_CVAR(machinegun, sustained_damage)));
+ W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, ((actor.misc_bulletcounter == 1) ? WEP_CVAR(machinegun, first_damage) : WEP_CVAR(machinegun, sustained_damage)));
if(!autocvar_g_norecoil)
{
actor.punchangle_x = random() - 0.5;
Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
- W_MachineGun_MuzzleFlash(actor);
- W_AttachToShotorg(actor, actor.muzzle_flash, '5 0 0');
+ W_MachineGun_MuzzleFlash(actor, weaponentity);
+ W_AttachToShotorg(actor, weaponentity, actor.(weaponentity).muzzle_flash, '5 0 0');
// casing code
if(autocvar_g_casings >= 2)
{
makevectors(actor.v_angle); // for some reason, this is lost
- SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor);
+ SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor, weaponentity);
}
if(actor.misc_bulletcounter == 1)
W_DecreaseAmmo(WEP_MACHINEGUN, actor, WEP_CVAR(machinegun, sustained_ammo));
- W_SetupShot(actor, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR(machinegun, sustained_damage));
+ W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR(machinegun, sustained_damage));
if(!autocvar_g_norecoil)
{
actor.punchangle_x = random() - 0.5;
Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
- W_MachineGun_MuzzleFlash(actor);
- W_AttachToShotorg(actor, actor.muzzle_flash, '5 0 0');
+ W_MachineGun_MuzzleFlash(actor, weaponentity);
+ W_AttachToShotorg(actor, weaponentity, actor.(weaponentity).muzzle_flash, '5 0 0');
if(autocvar_g_casings >= 2) // casing code
{
makevectors(actor.v_angle); // for some reason, this is lost
- SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor);
+ SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor, weaponentity);
}
int slot = weaponslot(weaponentity);
void W_MachineGun_Attack_Burst(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
- W_SetupShot(actor, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR(machinegun, sustained_damage));
+ W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR(machinegun, sustained_damage));
if(!autocvar_g_norecoil)
{
actor.punchangle_x = random() - 0.5;
Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
- W_MachineGun_MuzzleFlash(actor);
- W_AttachToShotorg(actor, actor.muzzle_flash, '5 0 0');
+ W_MachineGun_MuzzleFlash(actor, weaponentity);
+ W_AttachToShotorg(actor, weaponentity, actor.(weaponentity).muzzle_flash, '5 0 0');
if(autocvar_g_casings >= 2) // casing code
{
makevectors(actor.v_angle); // for some reason, this is lost
- SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor);
+ SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor, weaponentity);
}
actor.misc_bulletcounter = actor.misc_bulletcounter + 1;
}
METHOD(MachineGun, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
{
- W_Reload(actor, min(max(WEP_CVAR(machinegun, sustained_ammo), WEP_CVAR(machinegun, first_ammo)), WEP_CVAR(machinegun, burst_ammo)), SND_RELOAD);
+ W_Reload(actor, weaponentity, min(max(WEP_CVAR(machinegun, sustained_ammo), WEP_CVAR(machinegun, first_ammo)), WEP_CVAR(machinegun, burst_ammo)), SND_RELOAD);
}
METHOD(MachineGun, wr_suicidemessage, Notification(entity thiswep))
{
#ifndef IMPLEMENTATION
CLASS(MineLayer, Weapon)
-/* ammotype */ ATTRIB(MineLayer, ammo_field, .int, ammo_rockets)
-/* impulse */ ATTRIB(MineLayer, impulse, int, 4)
+/* ammotype */ ATTRIB(MineLayer, ammo_field, .int, ammo_rockets);
+/* impulse */ ATTRIB(MineLayer, impulse, int, 4);
/* flags */ ATTRIB(MineLayer, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH);
/* rating */ ATTRIB(MineLayer, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
/* color */ ATTRIB(MineLayer, wpcolor, vector, '0.75 1 0');
// in order for mines to face properly when sticking to the ground, they must be a server side entity rather than a csqc projectile
entity newmine = spawn();
+ IL_PUSH(g_mines, newmine);
newmine.classname = this.classname;
newmine.bot_dodge = this.bot_dodge;
newmine.nextthink = time;
newmine.cnt = this.cnt;
newmine.flags = this.flags;
+ IL_PUSH(g_projectiles, newmine);
- remove(this);
+ delete(this);
if(to)
SetMovetypeFollow(newmine, to);
if(!w.wr_checkammo1(w, own))
{
own.cnt = WEP_MINE_LAYER.m_id;
- int slot = 0; // TODO: unhardcode
+ .entity weaponentity = this.weaponentity_fld;
+ int slot = weaponslot(weaponentity);
ATTACK_FINISHED(own, slot) = time;
PS(own).m_switchweapon = w_getbestweapon(own);
}
}
this.realowner.minelayer_mines -= 1;
- remove(this);
+ delete(this);
}
void W_MineLayer_Explode_think(entity this)
if(!w.wr_checkammo1(w, own))
{
own.cnt = WEP_MINE_LAYER.m_id;
- int slot = 0; // TODO: unhardcode
+ .entity weaponentity = this.weaponentity_fld;
+ int slot = weaponslot(weaponentity);
ATTACK_FINISHED(own, slot) = time;
PS(own).m_switchweapon = w_getbestweapon(own);
}
}
this.realowner.minelayer_mines -= 1;
- remove(this);
+ delete(this);
}
void W_MineLayer_RemoteExplode(entity this)
int W_MineLayer_Count(entity e)
{
int minecount = 0;
- entity mine;
- for(mine = NULL; (mine = find(mine, classname, "mine")); ) if(mine.realowner == e)
+ IL_EACH(g_mines, it.realowner == e,
+ {
minecount += 1;
+ });
return minecount;
}
W_PrepareExplosionByDamage(this, attacker, W_MineLayer_Explode_think);
}
-void W_MineLayer_Attack(Weapon thiswep, entity actor)
+void W_MineLayer_Attack(Weapon thiswep, entity actor, .entity weaponentity)
{
entity mine;
entity flash;
W_DecreaseAmmo(thiswep, actor, WEP_CVAR(minelayer, ammo));
- W_SetupShot_ProjectileSize(actor, '-4 -4 -4', '4 4 4', false, 5, SND_MINE_FIRE, CH_WEAPON_A, WEP_CVAR(minelayer, damage));
+ W_SetupShot_ProjectileSize(actor, weaponentity, '-4 -4 -4', '4 4 4', false, 5, SND_MINE_FIRE, CH_WEAPON_A, WEP_CVAR(minelayer, damage));
Send_Effect(EFFECT_ROCKET_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
mine = WarpZone_RefSys_SpawnSameRefSys(actor);
+ mine.weaponentity_fld = weaponentity;
+ IL_PUSH(g_mines, mine);
mine.owner = mine.realowner = actor;
if(WEP_CVAR(minelayer, detonatedelay) >= 0)
mine.spawnshieldtime = time + WEP_CVAR(minelayer, detonatedelay);
mine.nextthink = time;
mine.cnt = (WEP_CVAR(minelayer, lifetime) - WEP_CVAR(minelayer, lifetime_countdown));
mine.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, mine);
mine.missile_flags = MIF_SPLASH | MIF_ARC | MIF_PROXY;
if(mine.cnt > 0) { mine.cnt += time; }
setmodel(flash, MDL_MINELAYER_MUZZLEFLASH); // precision set below
SUB_SetFade(flash, time, 0.1);
flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
- W_AttachToShotorg(actor, flash, '5 0 0');
+ W_AttachToShotorg(actor, weaponentity, flash, '5 0 0');
// common properties
actor.minelayer_mines = W_MineLayer_Count(actor);
}
-float W_MineLayer_PlacedMines(entity this, float detonate)
+bool W_MineLayer_PlacedMines(entity this, bool detonate)
{
- entity mine;
- float minfound = 0;
+ bool minfound = false;
- for(mine = NULL; (mine = find(mine, classname, "mine")); ) if(mine.realowner == this)
+ IL_EACH(g_mines, it.realowner == this,
{
if(detonate)
{
- if(!mine.minelayer_detonate)
+ if(!it.minelayer_detonate)
{
- mine.minelayer_detonate = true;
- minfound = 1;
+ it.minelayer_detonate = true;
+ minfound = true;
}
}
else
- minfound = 1;
- }
+ minfound = true;
+ });
return minfound;
}
teamdamage = 0;
enemydamage = 0;
- FOREACH_ENTITY_ENT(realowner, actor,
+ IL_EACH(g_mines, it.realowner == actor,
{
- if(it.classname != "mine") continue;
-
entity mine = it;
FOREACH_ENTITY_FLOAT(bot_attack, true,
{
desirabledamage = desirabledamage - teamdamage;
makevectors(actor.v_angle);
- FOREACH_ENTITY_ENT(realowner, actor,
+ IL_EACH(g_mines, it.realowner == actor,
{
- if(it.classname != "mine") continue;
-
if(skill > 9) // normal players only do this for the target they are tracking
{
entity mine = it;
{
if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(minelayer, refire)))
{
- W_MineLayer_Attack(thiswep, actor);
+ W_MineLayer_Attack(thiswep, actor, weaponentity);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(minelayer, animtime), w_ready);
}
}
}
METHOD(MineLayer, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
{
- W_Reload(actor, WEP_CVAR(minelayer, ammo), SND_RELOAD);
+ W_Reload(actor, weaponentity, WEP_CVAR(minelayer, ammo), SND_RELOAD);
}
METHOD(MineLayer, wr_suicidemessage, Notification(entity thiswep))
{
#ifndef IMPLEMENTATION
CLASS(Mortar, Weapon)
-/* ammotype */ ATTRIB(Mortar, ammo_field, .int, ammo_rockets)
-/* impulse */ ATTRIB(Mortar, impulse, int, 4)
+/* ammotype */ ATTRIB(Mortar, ammo_field, .int, ammo_rockets);
+/* impulse */ ATTRIB(Mortar, impulse, int, 4);
/* flags */ ATTRIB(Mortar, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH);
/* rating */ ATTRIB(Mortar, bot_pickupbasevalue, float, BOT_PICKUP_RATING_MID);
/* color */ ATTRIB(Mortar, wpcolor, vector, '1 0 0');
RadiusDamage(this, this.realowner, WEP_CVAR_PRI(mortar, damage), WEP_CVAR_PRI(mortar, edgedamage), WEP_CVAR_PRI(mortar, radius), NULL, NULL, WEP_CVAR_PRI(mortar, force), this.projectiledeathtype, directhitentity);
- remove(this);
+ delete(this);
}
void W_Mortar_Grenade_Explode_use(entity this, entity actor, entity trigger)
RadiusDamage(this, this.realowner, WEP_CVAR_SEC(mortar, damage), WEP_CVAR_SEC(mortar, edgedamage), WEP_CVAR_SEC(mortar, radius), NULL, NULL, WEP_CVAR_SEC(mortar, force), this.projectiledeathtype, directhitentity);
- remove(this);
+ delete(this);
}
void W_Mortar_Grenade_Explode2_use(entity this, entity actor, entity trigger)
}
}
-void W_Mortar_Attack(Weapon thiswep, entity actor)
+void W_Mortar_Attack(Weapon thiswep, entity actor, .entity weaponentity)
{
- entity gren;
-
W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(mortar, ammo));
- W_SetupShot_ProjectileSize(actor, '-3 -3 -3', '3 3 3', false, 4, SND_GRENADE_FIRE, CH_WEAPON_A, WEP_CVAR_PRI(mortar, damage));
+ W_SetupShot_ProjectileSize(actor, weaponentity, '-3 -3 -3', '3 3 3', false, 4, SND_GRENADE_FIRE, CH_WEAPON_A, WEP_CVAR_PRI(mortar, damage));
w_shotdir = v_forward; // no TrueAim for grenades please
Send_Effect(EFFECT_GRENADE_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
- gren = new(grenade);
+ entity gren = new(grenade);
gren.owner = gren.realowner = actor;
gren.bot_dodge = true;
gren.bot_dodgerating = WEP_CVAR_PRI(mortar, damage);
gren.angles = vectoangles(gren.velocity);
gren.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, gren);
if(WEP_CVAR_PRI(mortar, type) == 0 || WEP_CVAR_PRI(mortar, type) == 2)
CSQCProjectile(gren, true, PROJECTILE_GRENADE, true);
MUTATOR_CALLHOOK(EditProjectile, actor, gren);
}
-void W_Mortar_Attack2(Weapon thiswep, entity actor)
+void W_Mortar_Attack2(Weapon thiswep, entity actor, .entity weaponentity)
{
entity gren;
W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(mortar, ammo));
- W_SetupShot_ProjectileSize(actor, '-3 -3 -3', '3 3 3', false, 4, SND_GRENADE_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(mortar, damage));
+ W_SetupShot_ProjectileSize(actor, weaponentity, '-3 -3 -3', '3 3 3', false, 4, SND_GRENADE_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(mortar, damage));
w_shotdir = v_forward; // no TrueAim for grenades please
Send_Effect(EFFECT_GRENADE_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
gren.angles = vectoangles(gren.velocity);
gren.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, gren);
if(WEP_CVAR_SEC(mortar, type) == 0 || WEP_CVAR_SEC(mortar, type) == 2)
CSQCProjectile(gren, true, PROJECTILE_GRENADE, true);
{
if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(mortar, refire)))
{
- W_Mortar_Attack(thiswep, actor);
+ W_Mortar_Attack(thiswep, actor, weaponentity);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(mortar, animtime), w_ready);
}
}
}
else if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(mortar, refire)))
{
- W_Mortar_Attack2(thiswep, actor);
+ W_Mortar_Attack2(thiswep, actor, weaponentity);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(mortar, animtime), w_ready);
}
}
}
METHOD(Mortar, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
{
- W_Reload(actor, min(WEP_CVAR_PRI(mortar, ammo), WEP_CVAR_SEC(mortar, ammo)), SND_RELOAD); // WEAPONTODO
+ W_Reload(actor, weaponentity, min(WEP_CVAR_PRI(mortar, ammo), WEP_CVAR_SEC(mortar, ammo)), SND_RELOAD); // WEAPONTODO
}
METHOD(Mortar, wr_suicidemessage, Notification(entity thiswep))
{
#ifndef IMPLEMENTATION
CLASS(PortoLaunch, Weapon)
-/* ammotype */ ATTRIB(PortoLaunch, ammo_field, .int, ammo_none)
-/* impulse */ ATTRIB(PortoLaunch, impulse, int, 0)
+/* ammotype */ ATTRIB(PortoLaunch, ammo_field, .int, ammo_none);
+/* impulse */ ATTRIB(PortoLaunch, impulse, int, 0);
/* flags */ ATTRIB(PortoLaunch, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_SUPERWEAPON);
/* rating */ ATTRIB(PortoLaunch, bot_pickupbasevalue, float, 0);
/* color */ ATTRIB(PortoLaunch, wpcolor, vector, '0.5 0.5 0.5');
}
this.realowner.porto_current = NULL;
- remove(this);
+ delete(this);
}
string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vector velo);
}
}
}
- remove(this);
+ delete(this);
}
void W_Porto_Remove(entity p)
{
trace_plane_normal = '0 0 0';
if(this.realowner.playerid != this.playerid)
- remove(this);
+ delete(this);
else
W_Porto_Fail(this, 0);
}
if(this.realowner.playerid != this.playerid)
{
sound(this, CH_SHOTS, SND_PORTO_UNSUPPORTED, VOL_BASE, ATTEN_NORM);
- remove(this);
+ delete(this);
}
else if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK || trace_dphitcontents & DPCONTENTS_PLAYERCLIP)
{
}
}
-void W_Porto_Attack(entity actor, float type)
+void W_Porto_Attack(entity actor, .entity weaponentity, float type)
{
entity gren;
- W_SetupShot(actor, false, 4, SND_PORTO_FIRE, CH_WEAPON_A, 0);
+ W_SetupShot(actor, weaponentity, false, 4, SND_PORTO_FIRE, CH_WEAPON_A, 0);
// always shoot from the eye
w_shotdir = v_forward;
w_shotorg = actor.origin + actor.view_ofs + ((w_shotorg - actor.origin - actor.view_ofs) * v_forward) * v_forward;
gren.angles = vectoangles(gren.velocity);
gren.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, gren);
gren.portal_id = time;
actor.porto_current = gren;
if(!actor.porto_forbidden)
if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(porto, refire)))
{
- W_Porto_Attack(actor, 0);
+ W_Porto_Attack(actor, weaponentity, 0);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(porto, animtime), w_ready);
}
if(!actor.porto_forbidden)
if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(porto, refire)))
{
- W_Porto_Attack(actor, 1);
+ W_Porto_Attack(actor, weaponentity, 1);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(porto, animtime), w_ready);
}
}
if(!actor.porto_forbidden)
if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(porto, refire)))
{
- W_Porto_Attack(actor, -1);
+ W_Porto_Attack(actor, weaponentity, -1);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(porto, animtime), w_ready);
}
}
#endif
#ifdef CSQC
METHOD(PortoLaunch, wr_impacteffect, void(entity this, entity actor)) {
- LOG_WARNING("Since when does Porto send DamageInfo?\n");
+ LOG_WARN("Since when does Porto send DamageInfo?");
}
#endif
#endif
#ifndef IMPLEMENTATION
CLASS(Rifle, Weapon)
-/* ammotype */ ATTRIB(Rifle, ammo_field, .int, ammo_nails)
-/* impulse */ ATTRIB(Rifle, impulse, int, 7)
+/* ammotype */ ATTRIB(Rifle, ammo_field, .int, ammo_nails);
+/* impulse */ ATTRIB(Rifle, impulse, int, 7);
/* flags */ ATTRIB(Rifle, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN);
/* rating */ ATTRIB(Rifle, bot_pickupbasevalue, float, BOT_PICKUP_RATING_MID);
/* color */ ATTRIB(Rifle, wpcolor, vector, '0.5 1 0');
spawnfunc(weapon_campingrifle) { spawnfunc_weapon_rifle(this); }
spawnfunc(weapon_sniperrifle) { spawnfunc_weapon_rifle(this); }
-void W_Rifle_FireBullet(Weapon thiswep, float pSpread, float pDamage, float pForce, float pSolidPenetration, float pAmmo, int deathtype, float pTracer, float pShots, Sound pSound, entity actor)
+void W_Rifle_FireBullet(Weapon thiswep, .entity weaponentity, float pSpread, float pDamage, float pForce, float pSolidPenetration, float pAmmo, int deathtype, float pTracer, float pShots, Sound pSound, entity actor)
{
float i;
W_DecreaseAmmo(thiswep, actor, pAmmo);
- W_SetupShot(actor, true, 2, pSound, CH_WEAPON_A, pDamage * pShots);
+ W_SetupShot(actor, weaponentity, true, 2, pSound, CH_WEAPON_A, pDamage * pShots);
Send_Effect(EFFECT_RIFLE_MUZZLEFLASH, w_shotorg, w_shotdir * 2000, 1);
if(autocvar_g_casings >= 2)
{
makevectors(actor.v_angle); // for some reason, this is lost
- SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor);
+ SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor, weaponentity);
}
}
-void W_Rifle_Attack(entity actor)
+void W_Rifle_Attack(entity actor, .entity weaponentity)
{
- W_Rifle_FireBullet(WEP_RIFLE, WEP_CVAR_PRI(rifle, spread), WEP_CVAR_PRI(rifle, damage), WEP_CVAR_PRI(rifle, force), WEP_CVAR_PRI(rifle, solidpenetration), WEP_CVAR_PRI(rifle, ammo), WEP_RIFLE.m_id, WEP_CVAR_PRI(rifle, tracer), WEP_CVAR_PRI(rifle, shots), SND_CAMPINGRIFLE_FIRE, actor);
+ W_Rifle_FireBullet(WEP_RIFLE, weaponentity, WEP_CVAR_PRI(rifle, spread), WEP_CVAR_PRI(rifle, damage), WEP_CVAR_PRI(rifle, force), WEP_CVAR_PRI(rifle, solidpenetration), WEP_CVAR_PRI(rifle, ammo), WEP_RIFLE.m_id, WEP_CVAR_PRI(rifle, tracer), WEP_CVAR_PRI(rifle, shots), SND_CAMPINGRIFLE_FIRE, actor);
}
-void W_Rifle_Attack2(entity actor)
+void W_Rifle_Attack2(entity actor, .entity weaponentity)
{
- W_Rifle_FireBullet(WEP_RIFLE, WEP_CVAR_SEC(rifle, spread), WEP_CVAR_SEC(rifle, damage), WEP_CVAR_SEC(rifle, force), WEP_CVAR_SEC(rifle, solidpenetration), WEP_CVAR_SEC(rifle, ammo), WEP_RIFLE.m_id | HITTYPE_SECONDARY, WEP_CVAR_SEC(rifle, tracer), WEP_CVAR_SEC(rifle, shots), SND_CAMPINGRIFLE_FIRE2, actor);
+ W_Rifle_FireBullet(WEP_RIFLE, weaponentity, WEP_CVAR_SEC(rifle, spread), WEP_CVAR_SEC(rifle, damage), WEP_CVAR_SEC(rifle, force), WEP_CVAR_SEC(rifle, solidpenetration), WEP_CVAR_SEC(rifle, ammo), WEP_RIFLE.m_id | HITTYPE_SECONDARY, WEP_CVAR_SEC(rifle, tracer), WEP_CVAR_SEC(rifle, shots), SND_CAMPINGRIFLE_FIRE2, actor);
}
-.void(entity actor) rifle_bullethail_attackfunc;
+.void(entity actor, .entity weaponentity) rifle_bullethail_attackfunc;
.WFRAME rifle_bullethail_frame;
.float rifle_bullethail_animtime;
.float rifle_bullethail_refire;
PS(actor).m_switchweapon = sw;
if(r)
{
- actor.rifle_bullethail_attackfunc(actor);
+ actor.rifle_bullethail_attackfunc(actor, weaponentity);
weapon_thinkf(actor, weaponentity, actor.rifle_bullethail_frame, actor.rifle_bullethail_animtime, W_Rifle_BulletHail_Continue);
}
else
}
}
-void W_Rifle_BulletHail(entity actor, .entity weaponentity, float mode, void(entity actor) AttackFunc, WFRAME fr, float animtime, float refire)
+void W_Rifle_BulletHail(entity actor, .entity weaponentity, float mode, void(entity actor, .entity weaponentity) AttackFunc, WFRAME fr, float animtime, float refire)
{
// if we get here, we have at least one bullet to fire
- AttackFunc(actor);
+ AttackFunc(actor, weaponentity);
if(mode)
{
// continue hail
}
METHOD(Rifle, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
{
- W_Reload(actor, min(WEP_CVAR_PRI(rifle, ammo), WEP_CVAR_SEC(rifle, ammo)), SND_RELOAD);
+ W_Reload(actor, weaponentity, min(WEP_CVAR_PRI(rifle, ammo), WEP_CVAR_SEC(rifle, ammo)), SND_RELOAD);
}
METHOD(Rifle, wr_suicidemessage, Notification(entity thiswep))
{
#ifndef IMPLEMENTATION
CLASS(Seeker, Weapon)
-/* ammotype */ ATTRIB(Seeker, ammo_field, .int, ammo_rockets)
-/* impulse */ ATTRIB(Seeker, impulse, int, 8)
+/* ammotype */ ATTRIB(Seeker, ammo_field, .int, ammo_rockets);
+/* impulse */ ATTRIB(Seeker, impulse, int, 8);
/* flags */ ATTRIB(Seeker, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH);
/* rating */ ATTRIB(Seeker, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
/* color */ ATTRIB(Seeker, wpcolor, vector, '0.5 1 0');
this.event_damage = func_null;
RadiusDamage(this, this.realowner, WEP_CVAR(seeker, missile_damage), WEP_CVAR(seeker, missile_edgedamage), WEP_CVAR(seeker, missile_radius), NULL, NULL, WEP_CVAR(seeker, missile_force), this.projectiledeathtype, directhitentity);
- remove(this);
+ delete(this);
}
void W_Seeker_Missile_Explode_think(entity this)
}
*/
-void W_Seeker_Fire_Missile(Weapon thiswep, entity actor, vector f_diff, entity m_target)
+void W_Seeker_Fire_Missile(Weapon thiswep, entity actor, .entity weaponentity, vector f_diff, entity m_target)
{
- entity missile;
-
W_DecreaseAmmo(thiswep, actor, WEP_CVAR(seeker, missile_ammo));
makevectors(actor.v_angle);
- W_SetupShot_ProjectileSize(actor, '-2 -2 -2', '2 2 2', false, 2, SND_SEEKER_FIRE, CH_WEAPON_A, 0);
+ W_SetupShot_ProjectileSize(actor, weaponentity, '-2 -2 -2', '2 2 2', false, 2, SND_SEEKER_FIRE, CH_WEAPON_A, 0);
w_shotorg += f_diff;
Send_Effect(EFFECT_SEEKER_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
//actor.detornator = false;
- missile = new(seeker_missile);
+ entity missile = new(seeker_missile);
missile.owner = missile.realowner = actor;
missile.bot_dodge = true;
missile.bot_dodgerating = WEP_CVAR(seeker, missile_damage);
setorigin(missile, w_shotorg);
setsize(missile, '-4 -4 -4', '4 4 4');
set_movetype(missile, MOVETYPE_FLYMISSILE);
- missile.flags = FL_PROJECTILE;
+ missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
missile.missile_flags = MIF_SPLASH | MIF_GUIDED_TAG;
W_SetupProjVelocity_UP_PRE(missile, seeker, missile_);
RadiusDamage(this, this.realowner, WEP_CVAR(seeker, flac_damage), WEP_CVAR(seeker, flac_edgedamage), WEP_CVAR(seeker, flac_radius), NULL, NULL, WEP_CVAR(seeker, flac_force), this.projectiledeathtype, directhitentity);
- remove(this);
+ delete(this);
}
void W_Seeker_Flac_Touch(entity this, entity toucher)
W_Seeker_Flac_Explode(this, trigger);
}
-void W_Seeker_Fire_Flac(Weapon thiswep, entity actor)
+void W_Seeker_Fire_Flac(Weapon thiswep, entity actor, .entity weaponentity)
{
entity missile;
vector f_diff;
f_diff = '+1.25 +3.75 0';
break;
}
- W_SetupShot_ProjectileSize(actor, '-2 -2 -2', '2 2 2', false, 2, SND_FLAC_FIRE, CH_WEAPON_A, WEP_CVAR(seeker, flac_damage));
+ W_SetupShot_ProjectileSize(actor, weaponentity, '-2 -2 -2', '2 2 2', false, 2, SND_FLAC_FIRE, CH_WEAPON_A, WEP_CVAR(seeker, flac_damage));
w_shotorg += f_diff;
Send_Effect(EFFECT_HAGAR_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
set_movetype(missile, MOVETYPE_FLY);
missile.projectiledeathtype = WEP_SEEKER.m_id;
missile.projectiledeathtype = WEP_SEEKER.m_id | HITTYPE_SECONDARY;
- missile.flags = FL_PROJECTILE;
+ missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
missile.missile_flags = MIF_SPLASH;
// csqc projectiles
return NULL;
}
-void W_Seeker_Attack(entity actor)
+void W_Seeker_Attack(entity actor, .entity weaponentity)
{
entity tracker, closest_target;
if((!closest_target) || ((trace_fraction < 1) && (trace_ent != closest_target)))
closest_target = NULL;
- W_Seeker_Fire_Missile(WEP_SEEKER, actor, '0 0 0', closest_target);
+ W_Seeker_Fire_Missile(WEP_SEEKER, actor, weaponentity, '0 0 0', closest_target);
}
void W_Seeker_Vollycontroller_Think(entity this) // TODO: Merge this with W_Seeker_Attack
Weapon thiswep = WEP_SEEKER;
if((!(this.realowner.items & IT_UNLIMITED_AMMO) && this.realowner.(thiswep.ammo_field) < WEP_CVAR(seeker, missile_ammo)) || (this.cnt <= -1) || (IS_DEAD(this.realowner)) || (PS(this.realowner).m_switchweapon != WEP_SEEKER))
{
- remove(this);
+ delete(this);
return;
}
oldenemy = own.enemy;
own.enemy = this.enemy;
+ .entity weaponentity = this.weaponentity_fld;
c = own.cnt % 4;
switch(c)
{
case 0:
- W_Seeker_Fire_Missile(WEP_SEEKER, own, '-1.25 -3.75 0', own.enemy);
+ W_Seeker_Fire_Missile(WEP_SEEKER, own, weaponentity, '-1.25 -3.75 0', own.enemy); // TODO
break;
case 1:
- W_Seeker_Fire_Missile(WEP_SEEKER, own, '+1.25 -3.75 0', own.enemy);
+ W_Seeker_Fire_Missile(WEP_SEEKER, own, weaponentity, '+1.25 -3.75 0', own.enemy); // TODO
break;
case 2:
- W_Seeker_Fire_Missile(WEP_SEEKER, own, '-1.25 +3.75 0', own.enemy);
+ W_Seeker_Fire_Missile(WEP_SEEKER, own, weaponentity, '-1.25 +3.75 0', own.enemy); // TODO
break;
case 3:
default:
- W_Seeker_Fire_Missile(WEP_SEEKER, own, '+1.25 +3.75 0', own.enemy);
+ W_Seeker_Fire_Missile(WEP_SEEKER, own, weaponentity, '+1.25 +3.75 0', own.enemy); // TODO
break;
}
if(this)
{
WaypointSprite_Kill(this.tag_target.wps_tag_tracker);
- remove(this);
+ delete(this);
}
return;
}
// return;
Damage_DamageInfo(this.origin, 0, 0, 0, this.velocity, WEP_SEEKER.m_id | HITTYPE_BOUNCE, 0, this);
- remove(this);
+ delete(this);
}
void W_Seeker_Tag_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{
//sprint(this.realowner, strcat("You just tagged ^2", toucher.netname, "^7 with a tracking device!\n"));
e = new(tag_tracker);
+ e.weaponentity_fld = this.weaponentity_fld;
e.cnt = WEP_CVAR(seeker, missile_count);
e.owner = this.owner;
e.realowner = this.realowner;
}
}
- remove(this);
+ delete(this);
return;
}
-void W_Seeker_Fire_Tag(Weapon thiswep, entity actor)
+void W_Seeker_Fire_Tag(Weapon thiswep, entity actor, .entity weaponentity)
{
- entity missile;
W_DecreaseAmmo(thiswep, actor, WEP_CVAR(seeker, tag_ammo));
- W_SetupShot_ProjectileSize(actor, '-2 -2 -2', '2 2 2', false, 2, SND_TAG_FIRE, CH_WEAPON_A, WEP_CVAR(seeker, missile_damage) * WEP_CVAR(seeker, missile_count));
+ W_SetupShot_ProjectileSize(actor, weaponentity, '-2 -2 -2', '2 2 2', false, 2, SND_TAG_FIRE, CH_WEAPON_A, WEP_CVAR(seeker, missile_damage) * WEP_CVAR(seeker, missile_count));
- missile = new(seeker_tag);
+ entity missile = new(seeker_tag);
+ missile.weaponentity_fld = weaponentity;
missile.owner = missile.realowner = actor;
missile.bot_dodge = true;
missile.bot_dodgerating = 50;
setorigin(missile, w_shotorg);
setsize(missile, '-2 -2 -2', '2 2 2');
- missile.flags = FL_PROJECTILE;
+ missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
//missile.missile_flags = MIF_..?;
set_movetype(missile, MOVETYPE_FLY);
{
if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(seeker, missile_refire)))
{
- W_Seeker_Attack(actor);
+ W_Seeker_Attack(actor, weaponentity);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(seeker, missile_animtime), w_ready);
}
}
{
if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(seeker, tag_refire)))
{
- W_Seeker_Fire_Tag(thiswep, actor);
+ W_Seeker_Fire_Tag(thiswep, actor, weaponentity);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(seeker, tag_animtime), w_ready);
}
}
{
if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(seeker, tag_refire)))
{
- W_Seeker_Fire_Tag(thiswep, actor);
+ W_Seeker_Fire_Tag(thiswep, actor, weaponentity);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(seeker, tag_animtime), w_ready);
}
}
{
if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(seeker, flac_refire)))
{
- W_Seeker_Fire_Flac(thiswep, actor);
+ W_Seeker_Fire_Flac(thiswep, actor, weaponentity);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(seeker, flac_animtime), w_ready);
}
}
}
METHOD(Seeker, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
{
- W_Reload(actor, min(WEP_CVAR(seeker, missile_ammo), WEP_CVAR(seeker, tag_ammo)), SND_RELOAD);
+ W_Reload(actor, weaponentity, min(WEP_CVAR(seeker, missile_ammo), WEP_CVAR(seeker, tag_ammo)), SND_RELOAD);
}
METHOD(Seeker, wr_suicidemessage, Notification(entity thiswep))
{
#ifndef IMPLEMENTATION
CLASS(Shockwave, Weapon)
-/* ammotype */ //ATTRIB(Shockwave, ammo_field, .int, ammo_none)
-/* impulse */ ATTRIB(Shockwave, impulse, int, 2)
-/* flags */ ATTRIB(Shockwave, spawnflags, int, WEP_FLAG_NORMAL | WEP_TYPE_HITSCAN | WEP_FLAG_CANCLIMB | WEP_TYPE_MELEE_SEC);
+/* ammotype */ //ATTRIB(Shockwave, ammo_field, .int, ammo_none);
+/* impulse */ ATTRIB(Shockwave, impulse, int, 2);
+/* flags */ ATTRIB(Shockwave, spawnflags, int, WEP_TYPE_HITSCAN | WEP_FLAG_CANCLIMB | WEP_TYPE_MELEE_SEC);
/* rating */ ATTRIB(Shockwave, bot_pickupbasevalue, float, BOT_PICKUP_RATING_LOW);
/* color */ ATTRIB(Shockwave, wpcolor, vector, '0.5 0.25 0');
/* modelname */ ATTRIB(Shockwave, mdl, string, "shotgun");
// check to see if we can still continue, otherwise give up now
if(IS_DEAD(this.realowner) && WEP_CVAR(shockwave, melee_no_doubleslap))
{
- remove(this);
+ delete(this);
return;
}
}
else
{
- remove(this);
+ delete(this);
return;
}
}
if(time >= this.cnt + meleetime)
{
// melee is finished
- remove(this);
+ delete(this);
return;
}
else
meleetemp.owner = meleetemp.realowner = actor;
setthink(meleetemp, W_Shockwave_Melee_Think);
meleetemp.nextthink = time + WEP_CVAR(shockwave, melee_delay) * W_WeaponRateFactor(actor);
- W_SetupShot_Range(actor, true, 0, SND_Null, 0, WEP_CVAR(shockwave, melee_damage), WEP_CVAR(shockwave, melee_range));
+ W_SetupShot_Range(actor, weaponentity, true, 0, SND_Null, 0, WEP_CVAR(shockwave, melee_damage), WEP_CVAR(shockwave, melee_range));
}
// SHOCKWAVE ATTACK MODE
WriteByte(MSG_BROADCAST, etof(actor));
}
-void W_Shockwave_Attack(entity actor)
+void W_Shockwave_Attack(entity actor, .entity weaponentity)
{
// declarations
float multiplier, multiplier_from_accuracy, multiplier_from_distance;
float i, queue = 0;
// set up the shot direction
- W_SetupShot(actor, true, 3, SND_LASERGUN_FIRE, CH_WEAPON_B, WEP_CVAR(shockwave, blast_damage));
+ W_SetupShot(actor, weaponentity, true, 3, SND_LASERGUN_FIRE, CH_WEAPON_B, WEP_CVAR(shockwave, blast_damage));
vector attack_endpos = (w_shotorg + (w_shotdir * WEP_CVAR(shockwave, blast_distance)));
WarpZone_TraceLine(w_shotorg, attack_endpos, MOVE_NOMONSTERS, actor);
vector attack_hitpos = trace_endpos;
{
if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(shockwave, blast_animtime)))
{
- W_Shockwave_Attack(actor);
+ W_Shockwave_Attack(actor, weaponentity);
actor.shockwave_blasttime = time + WEP_CVAR(shockwave, blast_refire) * W_WeaponRateFactor(actor);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(shockwave, blast_animtime), w_ready);
}
else if(fire & 2)
{
//if(actor.clip_load >= 0) // we are not currently reloading
- if(!actor.crouch) // no crouchmelee please
if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR(shockwave, melee_refire)))
{
// attempt forcing playback of the anim by switching to another anim (that we never play) here...
{
// fading/removal control
float a = bound(0, (SW_MAXALPHA - ((time - this.sw_time) / SW_FADETIME)), SW_MAXALPHA);
- if(a < ALPHA_MIN_VISIBLE) { remove(this); }
+ if(a < ALPHA_MIN_VISIBLE) { delete(this); }
// WEAPONTODO: save this only once when creating the entity
vector sw_color = entcs_GetColor(this.sv_entnum - 1); // GetTeamRGB(entcs_GetTeam(this.sv_entnum));
#ifndef IMPLEMENTATION
CLASS(Shotgun, Weapon)
-/* ammotype */ ATTRIB(Shotgun, ammo_field, .int, ammo_shells)
-/* impulse */ ATTRIB(Shotgun, impulse, int, 2)
+/* ammotype */ ATTRIB(Shotgun, ammo_field, .int, ammo_shells);
+/* impulse */ ATTRIB(Shotgun, impulse, int, 2);
/* flags */ ATTRIB(Shotgun, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_TYPE_MELEE_SEC);
/* rating */ ATTRIB(Shotgun, bot_pickupbasevalue, float, BOT_PICKUP_RATING_LOW);
/* color */ ATTRIB(Shotgun, wpcolor, vector, '0.5 0.25 0');
#ifdef SVQC
spawnfunc(weapon_shotgun) { weapon_defaultspawnfunc(this, WEP_SHOTGUN); }
-void W_Shotgun_Attack(Weapon thiswep, entity actor, float isprimary)
+void W_Shotgun_Attack(Weapon thiswep, entity actor, .entity weaponentity, float isprimary)
{
- float sc;
- entity flash;
-
W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(shotgun, ammo));
- W_SetupShot(actor, true, 5, SND_SHOTGUN_FIRE, ((isprimary) ? CH_WEAPON_A : CH_WEAPON_SINGLE), WEP_CVAR_PRI(shotgun, damage) * WEP_CVAR_PRI(shotgun, bullets));
- for(sc = 0;sc < WEP_CVAR_PRI(shotgun, bullets);sc = sc + 1)
+ W_SetupShot(actor, weaponentity, true, 5, SND_SHOTGUN_FIRE, ((isprimary) ? CH_WEAPON_A : CH_WEAPON_SINGLE), WEP_CVAR_PRI(shotgun, damage) * WEP_CVAR_PRI(shotgun, bullets));
+ for(int sc = 0;sc < WEP_CVAR_PRI(shotgun, bullets);sc = sc + 1)
fireBullet(actor, w_shotorg, w_shotdir, WEP_CVAR_PRI(shotgun, spread), WEP_CVAR_PRI(shotgun, solidpenetration), WEP_CVAR_PRI(shotgun, damage), WEP_CVAR_PRI(shotgun, force), WEP_SHOTGUN.m_id, 0);
Send_Effect(EFFECT_SHOTGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, WEP_CVAR_PRI(shotgun, ammo));
if(autocvar_g_casings >= 1)
{
makevectors(actor.v_angle); // for some reason, this is lost
- for(sc = 0;sc < WEP_CVAR_PRI(shotgun, ammo);sc = sc + 1)
- SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 30) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 1, actor);
+ //for(int sc = 0;sc < WEP_CVAR_PRI(shotgun, ammo);sc = sc + 1)
+ SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 30) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 1, actor, weaponentity);
}
// muzzle flash for 1st person view
- flash = spawn();
+ entity flash = spawn();
setmodel(flash, MDL_SHOTGUN_MUZZLEFLASH); // precision set below
setthink(flash, SUB_Remove);
flash.nextthink = time + 0.06;
flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
- W_AttachToShotorg(actor, flash, '5 0 0');
+ W_AttachToShotorg(actor, weaponentity, flash, '5 0 0');
}
.float swing_prev;
// check to see if we can still continue, otherwise give up now
if(IS_DEAD(this.realowner) && WEP_CVAR_SEC(shotgun, melee_no_doubleslap))
{
- remove(this);
+ delete(this);
return;
}
}
else
{
- remove(this);
+ delete(this);
return;
}
}
if(time >= this.cnt + meleetime)
{
// melee is finished
- remove(this);
+ delete(this);
return;
}
else
meleetemp.realowner = actor;
setthink(meleetemp, W_Shotgun_Melee_Think);
meleetemp.nextthink = time + WEP_CVAR_SEC(shotgun, melee_delay) * W_WeaponRateFactor(actor);
- W_SetupShot_Range(actor, true, 0, SND_Null, 0, WEP_CVAR_SEC(shotgun, damage), WEP_CVAR_SEC(shotgun, melee_range));
+ W_SetupShot_Range(actor, weaponentity, true, 0, SND_Null, 0, WEP_CVAR_SEC(shotgun, damage), WEP_CVAR_SEC(shotgun, melee_range));
}
// alternate secondary weapon frames
}
sound(actor, CH_WEAPON_SINGLE, SND_Null, VOL_BASE, ATTN_NORM); // kill previous sound
- W_Shotgun_Attack(WEP_SHOTGUN, actor, true); // actually is secondary, but we trick the last shot into playing full reload sound
+ W_Shotgun_Attack(WEP_SHOTGUN, actor, weaponentity, true); // actually is secondary, but we trick the last shot into playing full reload sound
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), w_ready);
}
void W_Shotgun_Attack3_Frame1(Weapon thiswep, entity actor, .entity weaponentity, int fire)
return;
}
- W_Shotgun_Attack(WEP_SHOTGUN, actor, false);
+ W_Shotgun_Attack(WEP_SHOTGUN, actor, weaponentity, false);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), W_Shotgun_Attack3_Frame2);
}
-.float shotgun_primarytime;
+.float shotgun_primarytime[MAX_WEAPONSLOTS];
METHOD(Shotgun, wr_aim, void(entity thiswep, entity actor))
{
{
if(fire & 1)
{
- if(time >= actor.shotgun_primarytime) // handle refire separately so the secondary can be fired straight after a primary
+ int slot = weaponslot(weaponentity);
+ if(time >= actor.shotgun_primarytime[slot]) // handle refire separately so the secondary can be fired straight after a primary
{
if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(shotgun, animtime)))
{
- W_Shotgun_Attack(thiswep, actor, true);
- actor.shotgun_primarytime = time + WEP_CVAR_PRI(shotgun, refire) * W_WeaponRateFactor(actor);
+ W_Shotgun_Attack(thiswep, actor, weaponentity, true);
+ actor.shotgun_primarytime[slot] = time + WEP_CVAR_PRI(shotgun, refire) * W_WeaponRateFactor(actor);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(shotgun, animtime), w_ready);
}
}
}
else if((fire & 2) && WEP_CVAR(shotgun, secondary) == 2)
{
- if(time >= actor.shotgun_primarytime) // handle refire separately so the secondary can be fired straight after a primary
+ int slot = weaponslot(weaponentity);
+ if(time >= actor.shotgun_primarytime[slot]) // handle refire separately so the secondary can be fired straight after a primary
{
if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_SEC(shotgun, alt_animtime)))
{
- W_Shotgun_Attack(thiswep, actor, false);
- actor.shotgun_primarytime = time + WEP_CVAR_SEC(shotgun, alt_refire) * W_WeaponRateFactor(actor);
+ W_Shotgun_Attack(thiswep, actor, weaponentity, false);
+ actor.shotgun_primarytime[slot] = time + WEP_CVAR_SEC(shotgun, alt_refire) * W_WeaponRateFactor(actor);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), W_Shotgun_Attack3_Frame1);
}
}
}
}
if(actor.clip_load >= 0) // we are not currently reloading
- if(!actor.crouch) // no crouchmelee please
if(WEP_CVAR(shotgun, secondary) == 1)
if(((fire & 1) && actor.(thiswep.ammo_field) <= 0 && !(actor.items & IT_UNLIMITED_WEAPON_AMMO)) || (fire & 2))
if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(shotgun, refire)))
}
METHOD(Shotgun, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
{
- W_Reload(actor, WEP_CVAR_PRI(shotgun, ammo), SND_RELOAD); // WEAPONTODO
+ W_Reload(actor, weaponentity, WEP_CVAR_PRI(shotgun, ammo), SND_RELOAD); // WEAPONTODO
}
METHOD(Shotgun, wr_suicidemessage, Notification(entity thiswep))
{
#ifndef IMPLEMENTATION
CLASS(Tuba, Weapon)
-/* impulse */ ATTRIB(Tuba, impulse, int, 1)
+/* impulse */ ATTRIB(Tuba, impulse, int, 1);
/* flags */ ATTRIB(Tuba, spawnflags, int, WEP_FLAG_HIDDEN | WEP_TYPE_SPLASH);
/* rating */ ATTRIB(Tuba, bot_pickupbasevalue, float, BOT_PICKUP_RATING_MID);
/* color */ ATTRIB(Tuba, wpcolor, vector, '0 1 0');
}
}
}
- remove(this);
+ delete(this);
}
int W_Tuba_GetNote(entity pl, int hittype)
});
}
-void W_Tuba_NoteOn(entity actor, float hittype)
+void W_Tuba_NoteOn(entity actor, .entity weaponentity, float hittype)
{
vector o;
float n;
- W_SetupShot(actor, false, 2, SND_Null, 0, WEP_CVAR(tuba, damage));
+ W_SetupShot(actor, weaponentity, false, 2, SND_Null, 0, WEP_CVAR(tuba, damage));
n = W_Tuba_GetNote(actor, hittype);
if (fire & 1)
if (weapon_prepareattack(this, actor, weaponentity, false, WEP_CVAR(tuba, refire)))
{
- W_Tuba_NoteOn(actor, 0);
+ W_Tuba_NoteOn(actor, weaponentity, 0);
weapon_thinkf(actor, weaponentity, WFRAME_IDLE, WEP_CVAR(tuba, animtime), w_ready);
}
if (fire & 2)
if (weapon_prepareattack(this, actor, weaponentity, true, WEP_CVAR(tuba, refire)))
{
- W_Tuba_NoteOn(actor, HITTYPE_SECONDARY);
+ W_Tuba_NoteOn(actor, weaponentity, HITTYPE_SECONDARY);
weapon_thinkf(actor, weaponentity, WFRAME_IDLE, WEP_CVAR(tuba, animtime), w_ready);
}
if (actor.tuba_note)
break;
}
tuba_instrument_send(actor, actor.tuba_instrument);
- W_SetupShot(actor, false, 0, SND_Null, 0, 0);
+ W_SetupShot(actor, weaponentity, false, 0, SND_Null, 0, 0);
Send_Effect(EFFECT_TELEPORT, w_shotorg, '0 0 0', 1);
actor.(weaponentity).state = WS_INUSE;
weapon_thinkf(actor, weaponentity, WFRAME_RELOAD, 0.5, w_ready);
sound(this, CH_TUBA_SINGLE, SND_Null, 0, 0);
if (this.enemy) {
sound(this.enemy, CH_TUBA_SINGLE, SND_Null, 0, 0);
- remove(this.enemy);
+ delete(this.enemy);
}
- remove(this);
+ delete(this);
} else {
tubasound(this, 0);
}
Tuba_PitchStep = autocvar_g_balance_tuba_pitchstep;
if (Tuba_PitchStep) {
if (!checkextension("DP_SND_SOUND7_WIP2") && !checkextension("DP_SND_SOUND7")) {
- LOG_WARNING("requested pitch shifting, but not supported by this engine build");
+ LOG_WARN("requested pitch shifting, but not supported by this engine build");
Tuba_PitchStep = 0;
}
}
#ifndef IMPLEMENTATION
CLASS(Vaporizer, Weapon)
-/* ammotype */ ATTRIB(Vaporizer, ammo_field, .int, ammo_cells)
-/* impulse */ ATTRIB(Vaporizer, impulse, int, 7)
+/* ammotype */ ATTRIB(Vaporizer, ammo_field, .int, ammo_cells);
+/* impulse */ ATTRIB(Vaporizer, impulse, int, 7);
/* flags */ ATTRIB(Vaporizer, spawnflags, int, WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_FLAG_SUPERWEAPON | WEP_TYPE_HITSCAN);
/* rating */ ATTRIB(Vaporizer, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
/* color */ ATTRIB(Vaporizer, wpcolor, vector, '0.5 1 1');
WarpZone_TrailParticles(NULL, particleeffectnum(((this.cnt) ? EFFECT_VAPORIZER_HIT(this.team) : EFFECT_VAPORIZER(this.team))), this.vorg1, this.vorg2);
this.draw = func_null;
this.drawmask = MASK_NORMAL;
- remove(this);
+ delete(this);
}
return true;
dmgent.owner = dmgent.realowner = actor;
setorigin(dmgent, loc);
RadiusDamage (dmgent, actor, autocvar_g_rm_damage, autocvar_g_rm_edgedamage, autocvar_g_rm_radius, NULL, NULL, autocvar_g_rm_force, WEP_DEVASTATOR.m_id | HITTYPE_SPLASH, other);
- remove(dmgent);
+ delete(dmgent);
}
-void W_Vaporizer_Attack(Weapon thiswep, entity actor)
+void W_Vaporizer_Attack(Weapon thiswep, entity actor, .entity weaponentity)
{
bool flying = IsFlying(actor); // do this BEFORE to make the trace values from FireRailgunBullet last
float vaporizer_damage = ((WEP_CVAR_PRI(vaporizer, damage) > 0) ? WEP_CVAR_PRI(vaporizer, damage) : 10000);
- W_SetupShot(actor, true, 0, SND_Null, CH_WEAPON_A, vaporizer_damage);
+ W_SetupShot(actor, weaponentity, true, 0, SND_Null, CH_WEAPON_A, vaporizer_damage);
// handle sound separately so we can change the volume
// added bonus: no longer plays the strength sound (strength gives no bonus to instakill anyway)
sound (actor, CH_WEAPON_A, SND_MINSTANEXFIRE, VOL_BASE * 0.8, ATTEN_NORM);
this.event_damage = func_null;
this.takedamage = DAMAGE_NO;
RadiusDamage (this, this.realowner, this.rm_damage, this.rm_edmg, autocvar_g_rm_laser_radius, NULL, NULL, this.rm_force, this.projectiledeathtype, other);
- remove(this);
+ delete(this);
}
void W_RocketMinsta_Laser_Explode_use(entity this, entity actor, entity trigger)
PROJECTILE_TOUCH(this, toucher);
//W_RocketMinsta_Laser_Explode ();
RadiusDamage(this, this.realowner, this.rm_damage, this.rm_edmg, autocvar_g_rm_laser_radius, NULL, NULL, this.rm_force, this.projectiledeathtype, toucher);
- remove(this);
+ delete(this);
}
-void W_RocketMinsta_Attack2(entity actor)
+void W_RocketMinsta_Attack2(entity actor, .entity weaponentity)
{
makevectors(actor.v_angle);
Weapon w = PS(actor).m_weapon;
PS(actor).m_weapon = WEP_ELECTRO;
- W_SetupShot_ProjectileSize (actor, '0 0 -3', '0 0 -3', false, 2, SND_CRYLINK_FIRE, CH_WEAPON_A, autocvar_g_rm_laser_damage);
+ W_SetupShot_ProjectileSize (actor, weaponentity, '0 0 -3', '0 0 -3', false, 2, SND_CRYLINK_FIRE, CH_WEAPON_A, autocvar_g_rm_laser_damage);
PS(actor).m_weapon = w;
Send_Effect(EFFECT_ELECTRO_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
settouch(proj, W_RocketMinsta_Laser_Touch);
setsize(proj, '0 0 -3', '0 0 -3');
proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.missile_flags = MIF_SPLASH;
CSQCProjectile(proj, true, PROJECTILE_ROCKETMINSTA_LASER, true);
}
}
-void W_RocketMinsta_Attack3 (entity actor)
+void W_RocketMinsta_Attack3 (entity actor, .entity weaponentity)
{
makevectors(actor.v_angle);
Weapon w = PS(actor).m_weapon;
PS(actor).m_weapon = WEP_ELECTRO;
- W_SetupShot_ProjectileSize (actor, '0 0 -3', '0 0 -3', false, 2, SND_ELECTRO_FIRE2, CH_WEAPON_A, autocvar_g_rm_laser_damage);
+ W_SetupShot_ProjectileSize (actor, weaponentity, '0 0 -3', '0 0 -3', false, 2, SND_ELECTRO_FIRE2, CH_WEAPON_A, autocvar_g_rm_laser_damage);
PS(actor).m_weapon = w;
Send_Effect(EFFECT_ELECTRO_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
settouch(proj, W_RocketMinsta_Laser_Touch);
setsize(proj, '0 0 -3', '0 0 -3');
proj.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, proj);
proj.missile_flags = MIF_SPLASH;
CSQCProjectile(proj, true, PROJECTILE_ROCKETMINSTA_LASER, true);
{
if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(vaporizer, refire)))
{
- W_Vaporizer_Attack(thiswep, actor);
+ W_Vaporizer_Attack(thiswep, actor, weaponentity);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(vaporizer, animtime), w_ready);
}
}
actor.jump_interval = time + autocvar_g_rm_laser_refire;
actor.jump_interval2 = time + autocvar_g_rm_laser_rapid_delay;
damage_goodhits = 0;
- W_RocketMinsta_Attack2(actor);
+ W_RocketMinsta_Attack2(actor, weaponentity);
}
else if(rapid && actor.jump_interval2 <= time && actor.held_down)
{
actor.jump_interval2 = time + autocvar_g_rm_laser_rapid_refire;
damage_goodhits = 0;
- W_RocketMinsta_Attack3(actor);
+ W_RocketMinsta_Attack3(actor, weaponentity);
//weapon_thinkf(actor, WFRAME_FIRE2, autocvar_g_rm_laser_rapid_animtime, w_ready);
}
}
PS(actor).m_weapon = WEP_BLASTER;
W_Blaster_Attack(
actor,
+ weaponentity,
WEP_BLASTER.m_id | HITTYPE_SECONDARY,
WEP_CVAR_SEC(vaporizer, shotangle),
WEP_CVAR_SEC(vaporizer, damage),
else
used_ammo = vaporizer_ammo;
- W_Reload(actor, used_ammo, SND_RELOAD);
+ W_Reload(actor, weaponentity, used_ammo, SND_RELOAD);
}
METHOD(Vaporizer, wr_suicidemessage, Notification(entity thiswep))
{
#ifndef IMPLEMENTATION
CLASS(Vortex, Weapon)
-/* ammotype */ ATTRIB(Vortex, ammo_field, .int, ammo_cells)
-/* impulse */ ATTRIB(Vortex, impulse, int, 7)
+/* ammotype */ ATTRIB(Vortex, ammo_field, .int, ammo_cells);
+/* impulse */ ATTRIB(Vortex, impulse, int, 7);
/* flags */ ATTRIB(Vortex, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN);
/* rating */ ATTRIB(Vortex, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
/* color */ ATTRIB(Vortex, wpcolor, vector, '0.5 1 1');
}
}
-void W_Vortex_Attack(Weapon thiswep, entity actor, float issecondary)
+void W_Vortex_Attack(Weapon thiswep, entity actor, .entity weaponentity, float issecondary)
{
float mydmg, myforce, mymindist, mymaxdist, myhalflife, myforcehalflife, myammo, charge;
mydmg *= charge;
myforce *= charge;
- W_SetupShot(actor, true, 5, SND_NEXFIRE, CH_WEAPON_A, mydmg);
+ W_SetupShot(actor, weaponentity, true, 5, SND_NEXFIRE, CH_WEAPON_A, mydmg);
if(charge > WEP_CVAR(vortex, charge_animlimit) && WEP_CVAR(vortex, charge_animlimit)) // if the Vortex is overcharged, we play an extra sound
{
sound(actor, CH_WEAPON_B, SND_NEXCHARGE, VOL_BASE * (charge - 0.5 * WEP_CVAR(vortex, charge_animlimit)) / (1 - 0.5 * WEP_CVAR(vortex, charge_animlimit)), ATTN_NORM);
{
if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(vortex, refire)))
{
- W_Vortex_Attack(thiswep, actor, 0);
+ W_Vortex_Attack(thiswep, actor, weaponentity, 0);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(vortex, animtime), w_ready);
}
}
{
if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_SEC(vortex, refire)))
{
- W_Vortex_Attack(thiswep, actor, 1);
+ W_Vortex_Attack(thiswep, actor, weaponentity, 1);
weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_SEC(vortex, animtime), w_ready);
}
}
}
METHOD(Vortex, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
{
- W_Reload(actor, min(WEP_CVAR_PRI(vortex, ammo), WEP_CVAR_SEC(vortex, ammo)), SND_RELOAD);
+ W_Reload(actor, weaponentity, min(WEP_CVAR_PRI(vortex, ammo), WEP_CVAR_SEC(vortex, ammo)), SND_RELOAD);
}
METHOD(Vortex, wr_suicidemessage, Notification(entity thiswep))
{
-#ifndef CSPROGSDEFS_H
-#define CSPROGSDEFS_H
+#pragma once
#pragma noref 1
#define use use1
.void(entity this, entity actor, entity trigger) use;
#define touch move_touch
-
-#endif
# SVQC
+Main loop:
+* SV_Physics()
+ * StartFrame()
+ * if (force_retouch)
+ * foreach entity:
+ * .touch()
+ * foreach client:
+ * PlayerPreThink()
+ * .think()
+ * PlayerPostThink()
+ * foreach nonclient:
+ * .think()
+ * EndFrame()
+
+
```
.entity clientcamera;
// self
void SV_ParseClientCommand(string cmd);
+// qcstatus server field
+string worldstatus;
+.string clientstatus;
+
```
# MENUQC
-#ifndef DPEXTENSIONS_H
-#define DPEXTENSIONS_H
+#pragma once
#pragma noref 1
#define buf_create _buf_create
#pragma noref 0
-
-#endif
-#ifndef KEYCODES_H
-#define KEYCODES_H
+#pragma once
#pragma noref 1
//#undef float
#pragma noref 0
-
-#endif
-#ifndef MENUDEFS_H
-#define MENUDEFS_H
+#pragma once
#pragma noref 1
bool(entity ent) wasfreed = #353;
#pragma noref 0
-
-#endif
-#ifndef PROGSDEFS_H
-#define PROGSDEFS_H
+#pragma once
#pragma noref 1
#define use use1
.void(entity this, entity actor, entity trigger) use;
-
-#endif
### listening
entity listener = new_pure(someListener);
- listener.evt_$event = void(entity this) { code; };
- subscribe(listener, $event);
+ subscribe(listener, $event, void(entity this) { code; });
-/** Components always interpolate from the previous state */
-#define COMPONENT(com) \
- void com_##com##_interpolate(entity it, float a); \
- .bool com_##com
-
-#define FOREACH_COMPONENT(com, body) FOREACH_ENTITY_FLOAT(com_##com, true, body)
-
-
-#define EVENT(T, args) .bool evt_##T##_listener; .void args evt_##T
-
-#define emit(T, ...) \
- MACRO_BEGIN \
- FOREACH_ENTITY_FLOAT_ORDERED(evt_##T##_listener, true, it.evt_##T(__VA_ARGS__)); \
- MACRO_END
-
-#define subscribe(listener, T) \
- MACRO_BEGIN \
- listener.evt_##T##_listener = true; \
- MACRO_END
-
-
-/**
- * framelimit 0 is no limit, interpolation does not apply
- * framerate below minfps will result in less than 100% speed
- */
-#define SYSTEM(sys, frameLimit, minfps) \
- void sys_##sys##_update(entity this, float dt); \
- float autocvar_xon_sys_##sys##_dt = ((frameLimit) ? (1 / (frameLimit)) : 0); \
- float autocvar_xon_sys_##sys##_minfps = (1 / (1 / (minfps)))
-
-#define SYSTEM_UPDATE(sys) \
- MACRO_BEGIN \
- static float t = 0; \
- float dt = autocvar_xon_sys_##sys##_dt; \
- float minfps = autocvar_xon_sys_##sys##_minfps; \
- static float accumulator = 0; \
- float a = 0; \
- if (dt) { \
- accumulator += min(frametime, 1 / (minfps)); \
- } else { \
- accumulator += frametime; \
- dt = accumulator; \
- a = 1; \
- } \
- while (accumulator >= dt) \
- { \
- time = t; \
- FOREACH_COMPONENT(sys, sys_##sys##_update(it, dt)); \
- t += dt; \
- accumulator -= dt; \
- } \
- if (!a) a = accumulator / dt; \
- FOREACH_COMPONENT(sys, com_##sys##_interpolate(it, a)); \
- MACRO_END
-
+#include "_lib.qh"
#include "_mod.inc"
#include "components/_mod.inc"
--- /dev/null
+#pragma once
+
+/** Components always interpolate from the previous state */
+#define COMPONENT(com) \
+ void com_##com##_interpolate(entity it, float a); \
+ .bool com_##com
+
+#define FOREACH_COMPONENT(com, body) FOREACH_ENTITY_FLOAT(com_##com, true, body)
+
+
+#define EVENT(T, args) .bool evt_##T##_listener; .void args evt_##T
+
+#define emit(T, ...) \
+ MACRO_BEGIN \
+ FOREACH_ENTITY_FLOAT_ORDERED(evt_##T##_listener, true, it.evt_##T(__VA_ARGS__)); \
+ MACRO_END
+
+#define subscribe(listener, T, fn) \
+ MACRO_BEGIN \
+ listener.evt_##T = (fn); \
+ listener.evt_##T##_listener = true; \
+ MACRO_END
+
+
+/**
+ * framelimit 0 is no limit, interpolation does not apply
+ * framerate below minfps will result in less than 100% speed
+ */
+#define SYSTEM(sys, frameLimit, minfps) \
+ void sys_##sys##_update(entity this, float dt); \
+ float autocvar_xon_sys_##sys##_dt = ((frameLimit) ? (1 / (frameLimit)) : 0); \
+ float autocvar_xon_sys_##sys##_minfps = (1 / (1 / (minfps)))
+
+#define SYSTEM_UPDATE(sys) \
+ MACRO_BEGIN \
+ static float t = 0; \
+ float dt = autocvar_xon_sys_##sys##_dt; \
+ float minfps = autocvar_xon_sys_##sys##_minfps; \
+ static float accumulator = 0; \
+ float a = 0; \
+ if (dt) { \
+ accumulator += min(frametime, 1 / (minfps)); \
+ } else { \
+ accumulator += frametime; \
+ dt = accumulator; \
+ a = 1; \
+ } \
+ while (accumulator >= dt) \
+ { \
+ time = t; \
+ FOREACH_COMPONENT(sys, sys_##sys##_update(it, dt)); \
+ t += dt; \
+ accumulator -= dt; \
+ } \
+ if (!a) a = accumulator / dt; \
+ FOREACH_COMPONENT(sys, com_##sys##_interpolate(it, a)); \
+ MACRO_END
#pragma once
COMPONENT(in);
-.vector com_in_move;
+.vector com_in_move, com_in_move_prev;
.vector com_in_angles;
.bool com_in_jump;
+.bool com_in_crouch;
.vector com_phys_pos, com_phys_pos_prev;
.vector com_phys_ang, com_phys_ang_prev;
.vector com_phys_vel;
+.float com_phys_vel_max;
+.float com_phys_vel_max_air;
+.float com_phys_vel_max_air_strafe;
.vector com_phys_acc;
+.float com_phys_acc_rate;
+.float com_phys_acc_rate_air;
+.float com_phys_acc_rate_air_strafe;
+.float com_phys_acc_rate_air_stop;
+.float com_phys_friction;
+
+.vector com_phys_gravity;
+.float com_phys_gravity_factor;
+// TODO: remove
+.bool com_phys_ground;
+.bool com_phys_air;
+.bool com_phys_ladder;
+.bool com_phys_vel_2d;
+.bool com_phys_water;
+.bool com_phys_friction_air;
+.bool move_qcphysics;
// generated file; do not modify
+#include <ecs/events/physics.qc>
// generated file; do not modify
+#include <ecs/events/physics.qh>
--- /dev/null
+#include "physics.qh"
--- /dev/null
+#pragma once
+
+EVENT(phys_land, (entity this));
// generated file; do not modify
+#include <ecs/systems/input.qc>
#include <ecs/systems/physics.qc>
+#ifdef CSQC
+ #include <ecs/systems/cl_physics.qc>
+#endif
+#ifdef SVQC
+ #include <ecs/systems/sv_physics.qc>
+#endif
// generated file; do not modify
+#include <ecs/systems/input.qh>
#include <ecs/systems/physics.qh>
--- /dev/null
+#include "physics.qh"
+
+void sys_phys_fix(entity this, float dt)
+{
+ this.team = myteam + 1; // is this correct?
+ PHYS_WATERJUMP_TIME(this) -= dt;
+ this.oldmovement = this.movement;
+ this.movement = PHYS_INPUT_MOVEVALUES(this);
+ this.items = STAT(ITEMS, this);
+ this.spectatorspeed = STAT(SPECTATORSPEED, this);
+ if (!(PHYS_INPUT_BUTTON_JUMP(this))) // !jump
+ UNSET_JUMP_HELD(this); // canjump = true
+ PM_ClientMovement_UpdateStatus(this);
+}
+
+bool sys_phys_override(entity this, float dt)
+{
+ // no vehicle prediction
+ return hud != HUD_NORMAL;
+}
+
+void sys_phys_monitor(entity this, float dt) {}
+
+void sys_phys_ai(entity this) {}
+
+void sys_phys_pregame_hold(entity this) {}
+
+void sys_phys_spectator_control(entity this) {}
+
+void sys_phys_fixspeed(entity this, float maxspeed_mod) {}
--- /dev/null
+#include "input.qh"
+
+void sys_in_update(entity this, float dt)
+{
+ this.com_in_jump = PHYS_INPUT_BUTTON_JUMP(this);
+ this.com_in_crouch = PHYS_INPUT_BUTTON_CROUCH(this);
+}
--- /dev/null
+#pragma once
+
+SYSTEM(in, 30, 10);
#include "physics.qh"
+#include "input.qh"
+
+.int disableclientprediction;
+
+void sys_phys_simulate(entity this, float dt);
+void sys_phys_simulate_simple(entity this, float dt);
void sys_phys_update(entity this, float dt)
{
- PM_Main(this);
+ if (!IS_CLIENT(this)) {
+ sys_phys_simulate_simple(this, dt);
+ return;
+ }
+ sys_in_update(this, dt);
+
+ sys_phys_fix(this, dt);
+ if (sys_phys_override(this, dt)) { return; } sys_phys_monitor(this, dt);
+
+ this.buttons_old = PHYS_INPUT_BUTTON_MASK(this);
+ this.movement_old = this.movement;
+ this.v_angle_old = this.v_angle;
+
+ sys_phys_ai(this);
+
+ sys_phys_pregame_hold(this);
+
+ if (IS_SVQC) {
+ if (this.move_movetype == MOVETYPE_NONE) { return; }
+ // when we get here, disableclientprediction cannot be 2
+ this.disableclientprediction = (this.move_qcphysics) ? -1 : 0;
+ }
+
+ viewloc_PlayerPhysics(this);
+
+ PM_check_frozen(this);
+
+ PM_check_blocked(this);
+
+ float maxspeed_mod = (!this.in_swamp) ? 1 : this.swamp_slowdown; // cvar("g_balance_swamp_moverate");
+
+// conveyors: first fix velocity
+ if (this.conveyor.state) { this.velocity -= this.conveyor.movedir; }
+ MUTATOR_CALLHOOK(PlayerPhysics, this, dt);
+
+ if (!IS_PLAYER(this)) {
+ sys_phys_spectator_control(this);
+ maxspeed_mod = this.spectatorspeed;
+ }
+ sys_phys_fixspeed(this, maxspeed_mod);
+
+ if (IS_DEAD(this)) {
+ // handle water here
+ vector midpoint = ((this.absmin + this.absmax) * 0.5);
+ if (pointcontents(midpoint) == CONTENT_WATER) {
+ this.velocity = this.velocity * 0.5;
+
+ // do we want this?
+ // if(pointcontents(midpoint + '0 0 2') == CONTENT_WATER)
+ // { this.velocity_z = 70; }
+ }
+ goto end;
+ }
+
+ if (IS_SVQC && !PHYS_FIXANGLE(this)) { this.angles = '0 1 0' * this.v_angle.y; }
+ if (IS_PLAYER(this)) {
+ if (IS_ONGROUND(this)) {
+ PM_check_hitground(this);
+ PM_Footsteps(this);
+ } else if (IsFlying(this)) {
+ this.wasFlying = true;
+ }
+ CheckPlayerJump(this);
+ }
+
+ if (this.flags & FL_WATERJUMP) {
+ this.velocity_x = this.movedir.x;
+ this.velocity_y = this.movedir.y;
+ if (this.waterlevel == WATERLEVEL_NONE
+ || time > PHYS_TELEPORT_TIME(this)
+ || PHYS_WATERJUMP_TIME(this) <= 0
+ ) {
+ this.flags &= ~FL_WATERJUMP;
+ PHYS_TELEPORT_TIME(this) = 0;
+ PHYS_WATERJUMP_TIME(this) = 0;
+ }
+ } else if (MUTATOR_CALLHOOK(PM_Physics, this, maxspeed_mod, dt)) {
+ // handled
+ } else if (this.move_movetype == MOVETYPE_NOCLIP
+ || this.move_movetype == MOVETYPE_FLY
+ || this.move_movetype == MOVETYPE_FLY_WORLDONLY
+ || MUTATOR_CALLHOOK(IsFlying, this)) {
+ this.com_phys_friction = PHYS_FRICTION(this);
+ this.com_phys_vel_max = PHYS_MAXSPEED(this) * maxspeed_mod;
+ this.com_phys_acc_rate = PHYS_ACCELERATE(this) * maxspeed_mod;
+ this.com_phys_friction_air = true;
+ sys_phys_simulate(this, dt);
+ this.com_phys_friction_air = false;
+ } else if (this.waterlevel >= WATERLEVEL_SWIMMING) {
+ this.com_phys_vel_max = PHYS_MAXSPEED(this) * maxspeed_mod;
+ this.com_phys_acc_rate = PHYS_ACCELERATE(this) * maxspeed_mod;
+ this.com_phys_water = true;
+ sys_phys_simulate(this, dt);
+ this.com_phys_water = false;
+ } else if (time < this.ladder_time) {
+ this.com_phys_friction = PHYS_FRICTION(this);
+ this.com_phys_vel_max = PHYS_MAXSPEED(this) * maxspeed_mod;
+ this.com_phys_acc_rate = PHYS_ACCELERATE(this) * maxspeed_mod;
+ this.com_phys_gravity = '0 0 -1' * PHYS_GRAVITY(this) * dt;
+ if (PHYS_ENTGRAVITY(this)) { this.com_phys_gravity *= PHYS_ENTGRAVITY(this); }
+ this.com_phys_ladder = true;
+ this.com_phys_friction_air = true;
+ sys_phys_simulate(this, dt);
+ this.com_phys_friction_air = false;
+ this.com_phys_ladder = false;
+ this.com_phys_gravity = '0 0 0';
+ } else if (ITEMS_STAT(this) & IT_USING_JETPACK) {
+ PM_jetpack(this, maxspeed_mod, dt);
+ } else if (IS_ONGROUND(this)) {
+ if (!WAS_ONGROUND(this)) {
+ emit(phys_land, this);
+ if (this.lastground < time - 0.3) {
+ this.velocity *= (1 - PHYS_FRICTION_ONLAND(this));
+ }
+ }
+ this.com_phys_vel_max = PHYS_MAXSPEED(this) * maxspeed_mod;
+ this.com_phys_gravity = '0 0 -1' * PHYS_GRAVITY(this) * dt;
+ if (PHYS_ENTGRAVITY(this)) { this.com_phys_gravity *= PHYS_ENTGRAVITY(this); }
+ this.com_phys_ground = true;
+ this.com_phys_vel_2d = true;
+ sys_phys_simulate(this, dt);
+ this.com_phys_vel_2d = false;
+ this.com_phys_ground = false;
+ this.com_phys_gravity = '0 0 0';
+ } else {
+ this.com_phys_acc_rate_air = PHYS_AIRACCELERATE(this) * min(maxspeed_mod, 1);
+ this.com_phys_acc_rate_air_stop = PHYS_AIRSTOPACCELERATE(this) * maxspeed_mod;
+ this.com_phys_acc_rate_air_strafe = PHYS_AIRSTRAFEACCELERATE(this) * maxspeed_mod;
+ this.com_phys_vel_max_air_strafe = PHYS_MAXAIRSTRAFESPEED(this) * maxspeed_mod;
+ this.com_phys_vel_max_air = PHYS_MAXAIRSPEED(this) * maxspeed_mod;
+ this.com_phys_vel_max = PHYS_MAXAIRSPEED(this) * min(maxspeed_mod, 1);
+ this.com_phys_air = true;
+ this.com_phys_vel_2d = true;
+ sys_phys_simulate(this, dt);
+ this.com_phys_vel_2d = false;
+ this.com_phys_air = false;
+ }
+
+ LABEL(end)
+ if (IS_ONGROUND(this)) { this.lastground = time; }
+// conveyors: then break velocity again
+ if (this.conveyor.state) { this.velocity += this.conveyor.movedir; }
+ this.lastflags = this.flags;
+
+ this.lastclassname = this.classname;
+}
+
+/** for players */
+void sys_phys_simulate(entity this, float dt)
+{
+ const vector g = -this.com_phys_gravity;
+ const bool jump = this.com_in_jump;
+
+ if (!this.com_phys_ground && !this.com_phys_air) {
+ // noclipping
+ // flying
+ // on a spawnfunc_func_ladder
+ // swimming in spawnfunc_func_water
+ // swimming
+ UNSET_ONGROUND(this);
+
+ if (this.com_phys_friction_air) {
+ this.velocity_z += g.z / 2;
+ this.velocity = this.velocity * (1 - dt * this.com_phys_friction);
+ this.velocity_z += g.z / 2;
+ }
+ }
+
+ if (this.com_phys_water) {
+ // water jump only in certain situations
+ // this mimics quakeworld code
+ if (jump && this.waterlevel == WATERLEVEL_SWIMMING && this.velocity_z >= -180 && !this.viewloc) {
+ vector yawangles = '0 1 0' * this.v_angle.y;
+ makevectors(yawangles);
+ vector forward = v_forward;
+ vector spot = this.origin + 24 * forward;
+ spot_z += 8;
+ traceline(spot, spot, MOVE_NOMONSTERS, this);
+ if (trace_startsolid) {
+ spot_z += 24;
+ traceline(spot, spot, MOVE_NOMONSTERS, this);
+ if (!trace_startsolid) {
+ this.velocity = forward * 50;
+ this.velocity_z = 310;
+ UNSET_ONGROUND(this);
+ SET_JUMP_HELD(this);
+ }
+ }
+ }
+ }
+ makevectors(vmul(this.v_angle, (this.com_phys_vel_2d ? '0 1 0' : '1 1 1')));
+ // wishvel = v_forward * this.movement.x + v_right * this.movement.y + v_up * this.movement.z;
+ vector wishvel = v_forward * this.movement.x
+ + v_right * this.movement.y
+ + '0 0 1' * this.movement.z * (this.com_phys_vel_2d ? 0 : 1);
+ if (this.com_phys_water) {
+ if (PHYS_INPUT_BUTTON_CROUCH(this)) {
+ wishvel.z = -PHYS_MAXSPEED(this);
+ }
+ if (this.viewloc) {
+ wishvel.z = -160; // drift anyway
+ } else if (wishvel == '0 0 0') {
+ wishvel = '0 0 -60'; // drift towards bottom
+ }
+ }
+ if (this.com_phys_ladder) {
+ if (this.viewloc) {
+ wishvel.z = this.oldmovement.x;
+ }
+ if (this.ladder_entity.classname == "func_water") {
+ float f = vlen(wishvel);
+ if (f > this.ladder_entity.speed) {
+ wishvel *= (this.ladder_entity.speed / f);
+ }
+
+ this.watertype = this.ladder_entity.skin;
+ f = this.ladder_entity.origin_z + this.ladder_entity.maxs_z;
+ if ((this.origin_z + this.view_ofs_z) < f) {
+ this.waterlevel = WATERLEVEL_SUBMERGED;
+ } else if ((this.origin_z + (this.mins_z + this.maxs_z) * 0.5) < f) {
+ this.waterlevel = WATERLEVEL_SWIMMING;
+ } else if ((this.origin_z + this.mins_z + 1) < f) {
+ this.waterlevel = WATERLEVEL_WETFEET;
+ } else {
+ this.waterlevel = WATERLEVEL_NONE;
+ this.watertype = CONTENT_EMPTY;
+ }
+ }
+ }
+ // acceleration
+ const vector wishdir = normalize(wishvel);
+ float wishspeed = min(vlen(wishvel), this.com_phys_vel_max);
+
+ if (this.com_phys_air) {
+ if ((IS_SVQC && time >= PHYS_TELEPORT_TIME(this))
+ || (IS_CSQC && PHYS_WATERJUMP_TIME(this) <= 0)) {
+ // apply air speed limit
+ float airaccelqw = PHYS_AIRACCEL_QW(this);
+ float wishspeed0 = wishspeed;
+ const float maxairspd = this.com_phys_vel_max;
+ wishspeed = min(wishspeed, maxairspd);
+ if (IS_DUCKED(this)) {
+ wishspeed *= 0.5;
+ }
+ float airaccel = this.com_phys_acc_rate_air;
+
+ float accelerating = (this.velocity * wishdir > 0);
+ float wishspeed2 = wishspeed;
+
+ // CPM: air control
+ if (PHYS_AIRSTOPACCELERATE(this)) {
+ vector curdir = normalize(vec2(this.velocity));
+ airaccel += (this.com_phys_acc_rate_air_stop - airaccel) * max(0, -(curdir * wishdir));
+ }
+ // note that for straight forward jumping:
+ // step = accel * dt * wishspeed0;
+ // accel = bound(0, wishspeed - vel_xy_current, step) * accelqw + step * (1 - accelqw);
+ // -->
+ // dv/dt = accel * maxspeed (when slow)
+ // dv/dt = accel * maxspeed * (1 - accelqw) (when fast)
+ // log dv/dt = logaccel + logmaxspeed (when slow)
+ // log dv/dt = logaccel + logmaxspeed + log(1 - accelqw) (when fast)
+ float strafity = IsMoveInDirection(this.movement, -90) + IsMoveInDirection(this.movement, +90); // if one is nonzero, other is always zero
+ if (PHYS_MAXAIRSTRAFESPEED(this)) {
+ wishspeed =
+ min(wishspeed,
+ GeomLerp(this.com_phys_vel_max_air, strafity, this.com_phys_vel_max_air_strafe));
+ }
+ if (PHYS_AIRSTRAFEACCELERATE(this)) {
+ airaccel = GeomLerp(airaccel, strafity, this.com_phys_acc_rate_air_strafe);
+ }
+ if (PHYS_AIRSTRAFEACCEL_QW(this)) {
+ airaccelqw =
+ (((strafity > 0.5 ? PHYS_AIRSTRAFEACCEL_QW(this) : PHYS_AIRACCEL_QW(this)) >= 0) ? +1 : -1)
+ *
+ (1 - GeomLerp(1 - fabs(PHYS_AIRACCEL_QW(this)), strafity, 1 - fabs(PHYS_AIRSTRAFEACCEL_QW(this))));
+ }
+ // !CPM
+
+ if (PHYS_WARSOWBUNNY_TURNACCEL(this) && accelerating && this.movement.y == 0 && this.movement.x != 0) {
+ PM_AirAccelerate(this, dt, wishdir, wishspeed2);
+ } else {
+ float sidefric = maxairspd ? (PHYS_AIRACCEL_SIDEWAYS_FRICTION(this) / maxairspd) : 0;
+ PM_Accelerate(this, dt, wishdir, wishspeed, wishspeed0, airaccel, airaccelqw,
+ PHYS_AIRACCEL_QW_STRETCHFACTOR(this), sidefric, PHYS_AIRSPEEDLIMIT_NONQW(this));
+ }
+
+ if (PHYS_AIRCONTROL(this)) {
+ CPM_PM_Aircontrol(this, dt, wishdir, wishspeed2);
+ }
+ }
+ } else {
+ if (this.com_phys_ground && IS_DUCKED(this)) { wishspeed *= 0.5; }
+ if (this.com_phys_water) {
+ wishspeed *= 0.7;
+
+ // if (PHYS_WATERJUMP_TIME(this) <= 0) // TODO: use
+ {
+ // water friction
+ float f = 1 - dt * PHYS_FRICTION(this);
+ f = min(max(0, f), 1);
+ this.velocity *= f;
+
+ f = wishspeed - this.velocity * wishdir;
+ if (f > 0) {
+ float accelspeed = min(PHYS_ACCELERATE(this) * dt * wishspeed, f);
+ this.velocity += accelspeed * wishdir;
+ }
+
+ // holding jump button swims upward slowly
+ if (jump && !this.viewloc) {
+ // was:
+ // lava: 50
+ // slime: 80
+ // water: 100
+ // idea: double those
+ this.velocity_z = 200;
+ if (this.waterlevel >= WATERLEVEL_SUBMERGED) {
+ this.velocity_z = PHYS_MAXSPEED(this) * 0.7;
+ }
+ }
+ }
+ if (this.viewloc) {
+ const float addspeed = wishspeed - this.velocity * wishdir;
+ if (addspeed > 0) {
+ const float accelspeed = min(PHYS_ACCELERATE(this) * dt * wishspeed, addspeed);
+ this.velocity += accelspeed * wishdir;
+ }
+ } else {
+ // water acceleration
+ PM_Accelerate(this, dt, wishdir, wishspeed, wishspeed, this.com_phys_acc_rate, 1, 0, 0, 0);
+ }
+ return;
+ }
+ if (this.com_phys_ground) {
+ // apply edge friction
+ const float f2 = vlen2(vec2(this.velocity));
+ if (f2 > 0) {
+ trace_dphitq3surfaceflags = 0;
+ tracebox(this.origin, this.mins, this.maxs, this.origin - '0 0 1', MOVE_NOMONSTERS, this);
+ // TODO: apply edge friction
+ // apply ground friction
+ const int realfriction = (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK)
+ ? PHYS_FRICTION_SLICK(this)
+ : PHYS_FRICTION(this);
+
+ float f = sqrt(f2);
+ f = 1 - dt * realfriction
+ * ((f < PHYS_STOPSPEED(this)) ? (PHYS_STOPSPEED(this) / f) : 1);
+ f = max(0, f);
+ this.velocity *= f;
+ /*
+ Mathematical analysis time!
+
+ Our goal is to invert this mess.
+
+ For the two cases we get:
+ v = v0 * (1 - dt * (PHYS_STOPSPEED(this) / v0) * PHYS_FRICTION(this))
+ = v0 - dt * PHYS_STOPSPEED(this) * PHYS_FRICTION(this)
+ v0 = v + dt * PHYS_STOPSPEED(this) * PHYS_FRICTION(this)
+ and
+ v = v0 * (1 - dt * PHYS_FRICTION(this))
+ v0 = v / (1 - dt * PHYS_FRICTION(this))
+
+ These cases would be chosen ONLY if:
+ v0 < PHYS_STOPSPEED(this)
+ v + dt * PHYS_STOPSPEED(this) * PHYS_FRICTION(this) < PHYS_STOPSPEED(this)
+ v < PHYS_STOPSPEED(this) * (1 - dt * PHYS_FRICTION(this))
+ and, respectively:
+ v0 >= PHYS_STOPSPEED(this)
+ v / (1 - dt * PHYS_FRICTION(this)) >= PHYS_STOPSPEED(this)
+ v >= PHYS_STOPSPEED(this) * (1 - dt * PHYS_FRICTION(this))
+ */
+ }
+ const float addspeed = wishspeed - this.velocity * wishdir;
+ if (addspeed > 0) {
+ const float accelspeed = min(PHYS_ACCELERATE(this) * dt * wishspeed, addspeed);
+ this.velocity += accelspeed * wishdir;
+ }
+ return;
+ }
+
+ if (IS_CSQC ? PHYS_WATERJUMP_TIME(this) <= 0 : time >= PHYS_TELEPORT_TIME(this)) {
+ PM_Accelerate(this, dt, wishdir, wishspeed, wishspeed, this.com_phys_acc_rate, 1, 0, 0, 0);
+ }
+ }
+}
+
+.entity groundentity;
+/** for other entities */
+void sys_phys_simulate_simple(entity this, float dt)
+{
+ vector mn = this.mins;
+ vector mx = this.maxs;
+
+ vector g = '0 0 0';
+ if (this.com_phys_gravity_factor && !g) g = '0 0 -1' * PHYS_GRAVITY(NULL);
+
+ vector acc = this.com_phys_acc;
+ vector vel = this.com_phys_vel;
+ vector pos = this.com_phys_pos;
+
+ // SV_Physics_Toss
+
+ vel += g * dt;
+
+ this.angles += dt * this.avelocity;
+ float movetime = dt;
+ for (int i = 0; i < MAX_CLIP_PLANES && movetime > 0; i++) {
+ vector push = vel * movetime;
+ vector p0 = pos;
+ vector p1 = p0 + push;
+ // SV_PushEntity
+ tracebox(p0, mn, mx, p1, MOVE_NORMAL, this);
+ if (!trace_startsolid) {
+ bool hit = trace_fraction < 1;
+ pos = trace_endpos;
+ entity ent = trace_ent;
+ // SV_LinkEdict_TouchAreaGrid
+ if (this.solid != SOLID_NOT) {
+ FOREACH_ENTITY_RADIUS_ORDERED(0.5 * (this.absmin + this.absmax), 0.5 * vlen(this.absmax - this.absmin), true, {
+ if (it.solid != SOLID_TRIGGER || it == this) continue;
+ if (gettouch(it) && boxesoverlap(it.absmin, it.absmax, this.absmin, this.absmax)) {
+ // SV_LinkEdict_TouchAreaGrid_Call
+ trace_allsolid = false;
+ trace_startsolid = false;
+ trace_fraction = 1;
+ trace_inwater = false;
+ trace_inopen = true;
+ trace_endpos = it.origin;
+ trace_plane_normal = '0 0 1';
+ trace_plane_dist = 0;
+ trace_ent = this;
+ trace_dpstartcontents = 0;
+ trace_dphitcontents = 0;
+ trace_dphitq3surfaceflags = 0;
+ trace_dphittexturename = string_null;
+ gettouch(it)(this, it);
+ vel = this.velocity;
+ }
+ });
+ }
+ if (hit && this.solid >= SOLID_TRIGGER && (!IS_ONGROUND(this) || this.groundentity != ent)) {
+ // SV_Impact (ent, trace);
+ tracebox(p0, mn, mx, p1, MOVE_NORMAL, this);
+ void(entity, entity) touched = gettouch(this);
+ if (touched && this.solid != SOLID_NOT) {
+ touched(ent, this);
+ }
+ void(entity, entity) touched2 = gettouch(ent);
+ if (this && ent && touched2 && ent.solid != SOLID_NOT) {
+ trace_endpos = ent.origin;
+ trace_plane_normal *= -1;
+ trace_plane_dist *= -1;
+ trace_ent = this;
+ trace_dpstartcontents = 0;
+ trace_dphitcontents = 0;
+ trace_dphitq3surfaceflags = 0;
+ trace_dphittexturename = string_null;
+ touched2(this, ent);
+ }
+ }
+ }
+ // end SV_PushEntity
+ if (wasfreed(this)) { return; }
+ tracebox(p0, mn, mx, p1, MOVE_NORMAL, this);
+ if (trace_fraction == 1) { break; }
+ movetime *= 1 - min(1, trace_fraction);
+ ClipVelocity(vel, trace_plane_normal, vel, 1);
+ }
+
+ this.com_phys_acc = acc;
+ this.com_phys_vel = vel;
+ this.com_phys_pos = pos;
+ setorigin(this, this.com_phys_pos);
+}
+
+void sys_phys_update_single(entity this)
+{
+ sys_phys_simulate_simple(this, frametime);
}
#pragma once
SYSTEM(phys, 30, 10);
+
+void sys_phys_fix(entity this, float dt);
+bool sys_phys_override(entity this, float dt);
+void sys_phys_monitor(entity this, float dt);
+void sys_phys_pregame_hold(entity this);
+void sys_phys_ai(entity this);
+void sys_phys_spectator_control(entity this);
+void sys_phys_fixspeed(entity this, float maxspeed_mod);
--- /dev/null
+#include "physics.qh"
+
+void sys_phys_fix(entity this, float dt)
+{
+ WarpZone_PlayerPhysics_FixVAngle(this);
+ Physics_UpdateStats(this, PHYS_HIGHSPEED(this));
+}
+
+bool sys_phys_override(entity this, float dt)
+{
+ int buttons = PHYS_INPUT_BUTTON_MASK(this);
+ if (PM_check_specialcommand(this, buttons)) { return true; }
+ if (this.PlayerPhysplug && this.PlayerPhysplug(this, dt)) { return true; }
+ return false;
+}
+
+void sys_phys_monitor(entity this, float dt)
+{
+ int buttons = PHYS_INPUT_BUTTON_MASK(this);
+ anticheat_physics(this);
+ if (sv_maxidle > 0) {
+ if (buttons != this.buttons_old
+ || this.movement != this.movement_old
+ || this.v_angle != this.v_angle_old) { this.parm_idlesince = time; }
+ }
+ PM_check_nickspam(this);
+ PM_check_punch(this, dt);
+}
+
+void sys_phys_ai(entity this)
+{
+ if (!IS_BOT_CLIENT(this)) { return; }
+ if (playerdemo_read(this)) { return; }
+ bot_think(this);
+}
+
+void sys_phys_pregame_hold(entity this)
+{
+ if (!IS_PLAYER(this)) { return; }
+ const bool allowed_to_move = (time >= game_starttime);
+ if (!allowed_to_move) {
+ this.velocity = '0 0 0';
+ set_movetype(this, MOVETYPE_NONE);
+ this.disableclientprediction = 2;
+ } else if (this.disableclientprediction == 2) {
+ if (this.move_movetype == MOVETYPE_NONE) { set_movetype(this, MOVETYPE_WALK); }
+ this.disableclientprediction = 0;
+ }
+}
+
+void sys_phys_spectator_control(entity this)
+{
+ float maxspeed_mod = autocvar_sv_spectator_speed_multiplier;
+ if (!this.spectatorspeed) { this.spectatorspeed = maxspeed_mod; }
+ if ((this.impulse >= 1 && this.impulse <= 19)
+ || (this.impulse >= 200 && this.impulse <= 209)
+ || (this.impulse >= 220 && this.impulse <= 229)
+ ) {
+ if (this.lastclassname != STR_PLAYER) {
+ if (this.impulse == 10
+ || this.impulse == 15
+ || this.impulse == 18
+ || (this.impulse >= 200 && this.impulse <= 209)
+ ) { this.spectatorspeed = bound(1, this.spectatorspeed + 0.5, 5); } else if (this.impulse == 11) {
+ this.spectatorspeed = maxspeed_mod;
+ } else if (this.impulse == 12
+ || this.impulse == 16
+ || this.impulse == 19
+ || (this.impulse >= 220 && this.impulse <= 229)
+ ) {
+ this.spectatorspeed = bound(1, this.spectatorspeed - 0.5, 5);
+ } else if (this.impulse >= 1 && this.impulse <= 9) {
+ this.spectatorspeed = 1 + 0.5 * (this.impulse - 1);
+ }
+ } // otherwise just clear
+ this.impulse = 0;
+ }
+}
+
+void sys_phys_fixspeed(entity this, float maxspeed_mod)
+{
+ float spd = max(PHYS_MAXSPEED(this), PHYS_MAXAIRSPEED(this)) * maxspeed_mod;
+ if (this.speed != spd) {
+ this.speed = spd;
+ string temps = ftos(spd);
+ stuffcmd(this, strcat("cl_forwardspeed ", temps, "\n"));
+ stuffcmd(this, strcat("cl_backspeed ", temps, "\n"));
+ stuffcmd(this, strcat("cl_sidespeed ", temps, "\n"));
+ stuffcmd(this, strcat("cl_upspeed ", temps, "\n"));
+ }
+
+ if (this.jumpspeedcap_min != autocvar_sv_jumpspeedcap_min) {
+ this.jumpspeedcap_min = autocvar_sv_jumpspeedcap_min;
+ stuffcmd(this, sprintf("\ncl_jumpspeedcap_min \"%s\"\n", autocvar_sv_jumpspeedcap_min));
+ }
+ if (this.jumpspeedcap_max != autocvar_sv_jumpspeedcap_max) {
+ this.jumpspeedcap_max = autocvar_sv_jumpspeedcap_max;
+ stuffcmd(this, sprintf("\ncl_jumpspeedcap_max \"%s\"\n", autocvar_sv_jumpspeedcap_max));
+ }
+}
+
+void sys_phys_land(entity this)
+{
+ if (autocvar_speedmeter) {
+ LOG_TRACEF("landing velocity: %v (abs: %f)", this.velocity, vlen(this.velocity));
+ }
+ if (this.jumppadcount > 1) {
+ LOG_TRACEF("%dx jumppad combo", this.jumppadcount);
+ }
+ this.jumppadcount = 0;
+}
+
+STATIC_INIT(sys_phys)
+{
+ entity listener = new_pure(sys_phys);
+ subscribe(listener, phys_land, sys_phys_land);
+}
#define COMPAT_NO_MOD_IS_XONOTIC
#endif
+#ifdef CSQC
+#define IS_CSQC 1
+#else
+#define IS_CSQC 0
+#endif
+
+#ifdef SVQC
+#define IS_SVQC 1
+#else
+#define IS_SVQC 0
+#endif
+
#include "compiler.qh"
#ifndef QCC_SUPPORT_INT
#else
#define TC(T, sym) MACRO_BEGIN \
if (!is_##T(sym)) { \
- LOG_WARNINGF("Type check failed: " #sym " :: " #T); \
+ LOG_WARNF("Type check failed: " #sym " :: " #T); \
isnt_##T(sym); \
} \
MACRO_END
#endif
#define objerror(this, msg) MACRO_BEGIN { \
- LOG_WARNING("======OBJECT ERROR======"); \
+ LOG_WARN("======OBJECT ERROR======"); \
entity _e = (this); \
eprint(_e); \
objerror_safe(_e); \
delete(_e); \
- LOG_WARNINGF("%s OBJECT ERROR in %s:\n%s\nTip: read above for entity information", PROGNAME, __FUNC__, msg); \
+ LOG_WARNF("%s OBJECT ERROR in %s:\n%s\nTip: read above for entity information", PROGNAME, __FUNC__, msg); \
} MACRO_END
#ifdef MENUQC
#define CSQC_Ent_Remove _CSQC_Ent_Remove
#endif
#undef ENGINE_EVENT
+
+#ifndef MENUQC
+ #include <ecs/_lib.qh>
+ #include <ecs/components/_mod.qh>
+#endif
MACRO_BEGIN \
{ \
buf_del(this.al_buf); \
- remove(this); \
+ delete(this); \
this = NULL; \
} MACRO_END
{
if (i < maxclients) return CSQCModel_players[i];
++i;
- LOG_DEBUGF("player out of bounds: %d\n", i);
+ LOG_DEBUGF("player out of bounds: %d", i);
return findfloat(NULL, entnum, i);
}
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
-#ifndef LIB_CSQCMODEL_CL_MODEL_H
-#define LIB_CSQCMODEL_CL_MODEL_H
+#pragma once
#include "common.qh"
void CSQCModel_InterpolateAnimation_2To4_Do(entity this);
void CSQCModel_InterpolateAnimation_1To2_Do(entity this);
// will overwrite lerpfrac, lerpfrac3, lerpfrac4, and possibly clear frame*time if they are undisplayed according to lerpfracs
-#endif
void CSQCPlayer_Unpredict(entity this)
{
if (csqcplayer_status == CSQCPLAYERSTATUS_UNPREDICTED) return;
- if (csqcplayer_status != CSQCPLAYERSTATUS_PREDICTED) LOG_FATALF("Cannot unpredict in current status (%d)\n", csqcplayer_status);
+ if (csqcplayer_status != CSQCPLAYERSTATUS_PREDICTED) LOG_FATALF("Cannot unpredict in current status (%d)", csqcplayer_status);
this.origin = csqcplayer_origin;
this.velocity = csqcplayer_velocity;
csqcplayer_moveframe = csqcplayer_sequence + 1; // + 1 because the recieved frame has the move already done (server side)
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
-#ifndef LIB_CSQCMODEL_CL_PLAYER_H
-#define LIB_CSQCMODEL_CL_PLAYER_H
+#pragma once
bool autocvar_cl_movement = true;
float CSQCPlayer_PreUpdate(entity this);
float CSQCPlayer_PostUpdate(entity this);
float CSQCPlayer_IsLocalPlayer(entity this);
-#endif
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
-#ifndef LIB_CSQCMODEL_COMMON_H
-#define LIB_CSQCMODEL_COMMON_H
+#pragma once
#include <common/csqcmodel_settings.qh>
#else
#define ALLPROPERTIES ALLPROPERTIES_COMMON
#endif
-#endif
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
-#ifndef LIB_CSQCMODEL_INTERPOLATE_H
-#define LIB_CSQCMODEL_INTERPOLATE_H
+#pragma once
.int iflags;
const int IFLAG_VELOCITY = BIT(0);
// in case we interpolate that:
.vector v_angle;
-#endif
-#ifndef LIB_CSQCMODEL_SETTINGS_H
-#define LIB_CSQCMODEL_SETTINGS_H
+#pragma once
// define this if svqc code wants to use .frame2 and .lerpfrac
//#define CSQCMODEL_HAVE_TWO_FRAMES
//vector PL_CROUCH_MIN = ...;
//vector PL_CROUCH_MAX = ...;
//vector PL_CROUCH_VIEW_OFS = ...;
-#endif
void CSQCModel_CheckUpdate(entity e)
{
// some nice flags for CSQCMODEL_IF
- float isplayer = IS_CLIENT(e);
- float islocalplayer = isplayer; // we set BOTH to 1 here as we need the sendflags
- float isnolocalplayer = isplayer; // we set BOTH to 1 here as we need the sendflags
-
- unused_float = isplayer;
- unused_float = islocalplayer;
- unused_float = isnolocalplayer;
+ noref float isplayer = IS_CLIENT(e);
+ noref float islocalplayer = isplayer; // we set BOTH to 1 here as we need the sendflags
+ noref float isnolocalplayer = isplayer; // we set BOTH to 1 here as we need the sendflags
#if CSQCPLAYER_FORCE_UPDATES
if(isplayer && time > e.csqcmodel_nextforcedupdate)
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
-#ifndef LIB_CSQCMODEL_SV_MODEL_H
-#define LIB_CSQCMODEL_SV_MODEL_H
+#pragma once
#include "common.qh"
#undef CSQCMODEL_PROPERTY
#undef CSQCMODEL_ENDIF
#undef CSQCMODEL_IF
-#endif
/** Remove entity */
void SUB_Remove(entity this)
{
- remove(this);
+ delete(this);
}
void defer_think(entity this)
int p = strstrofs(s, "^", 0);
string ret = (p < 0) ? s : substring(s, p + 1, -1);
#if CTX_CACHE
- LOG_DEBUGF("CTX(\"%s\")\n", s);
+ LOG_DEBUGF("CTX(\"%s\")", s);
HM_sets(CTX_cache, s, ret);
#endif
return ret;
* freed entities must be removed from the list
*/
CLASS(IntrusiveList, Object)
- ATTRIB(IntrusiveList, il_head, entity, NULL);
- ATTRIB(IntrusiveList, il_tail, entity, NULL);
+ ATTRIB(IntrusiveList, il_head, entity);
+ ATTRIB(IntrusiveList, il_tail, entity);
ATTRIB(IntrusiveList, il_nextfld, .entity, nil);
ATTRIB(IntrusiveList, il_prevfld, .entity, nil);
INIT(IntrusiveList) { IL_INIT(this); }
entity otail = this.il_tail;
next ? next.(il_prev) = prev : this.il_tail = prev;
prev ? prev.(il_next) = next : this.il_head = next;
- LOG_DEBUGF("remove %i (%i :: %i), head: %i -> %i, tail: %i -> %i\n", it, it.(il_prev), it.(il_next), ohead, this.il_head, otail, this.il_tail);
+ LOG_DEBUGF("remove %i (%i :: %i), head: %i -> %i, tail: %i -> %i", it, it.(il_prev), it.(il_next), ohead, this.il_head, otail, this.il_tail);
it.(il_next) = it.(il_prev) = NULL;
}
#define IL_DELETE(this, dtor) \
MACRO_BEGIN \
{ \
- remove(this); \
+ delete(this); \
this = NULL; \
} MACRO_END
return;
}
}
- LOG_WARNINGF("IntrusiveList overflow");
+ LOG_WARNF("IntrusiveList overflow");
}
void IL_DTOR(IntrusiveList this)
if (cond) LAMBDA(body) \
} \
} MACRO_END
+#define MUTEX_LOCK(this) MACRO_BEGIN \
+ if (this) LOG_SEVEREF("Loop mutex held by %s", this); \
+ this = __FUNC__; \
+MACRO_END
+#define MUTEX_UNLOCK(this) MACRO_BEGIN \
+ this = string_null; \
+MACRO_END
#define _FOREACH_ENTITY_FIND_UNORDERED(id, T, fld, match, cond, body) \
MACRO_BEGIN { \
- if (_FOREACH_ENTITY_FIND_##T##_##id##mutex) LOG_SEVEREF("Loop mutex held by %s", _FOREACH_ENTITY_FIND_##T##_##id##mutex); \
- _FOREACH_ENTITY_FIND_##T##_##id##mutex = __FUNC__; \
+ MUTEX_LOCK(_FOREACH_ENTITY_FIND_##T##_##id##mutex); \
entity _foundchain_first = _findchain##T##_tofield(fld, match, _FOREACH_ENTITY_FIND_##T##_next##id); \
FOREACH_LIST(_foundchain, _FOREACH_ENTITY_FIND_##T##_next##id, cond, body); \
- _FOREACH_ENTITY_FIND_##T##_##id##mutex = string_null; \
+ MUTEX_UNLOCK(_FOREACH_ENTITY_FIND_##T##_##id##mutex); \
} MACRO_END
#define FOREACH_ENTITY(cond, body) ORDERED(FOREACH_ENTITY)(cond, body)
#ifndef MENUQC
entity(vector org, float rad, .entity tofield) _findchainradius_tofield = #22;
-#define FOREACH_ENTITY_RADIUS(org, dist, cond, body) FOREACH_ENTITY_RADIUS_UNORDERED(org, dist, cond, body)
+#define FOREACH_ENTITY_RADIUS(org, dist, cond, body) ORDERED(FOREACH_ENTITY_RADIUS)(org, dist, cond, body)
.entity _FOREACH_ENTITY_FIND_radius_next; noref string _FOREACH_ENTITY_FIND_radius_mutex;
#define FOREACH_ENTITY_RADIUS_UNORDERED(org, dist, cond, body) _FOREACH_ENTITY_FIND_UNORDERED(, radius, org, dist, cond, body)
+.entity _FOREACH_ENTITY_FIND_radius_nexttmp; noref string _FOREACH_ENTITY_FIND_radius_tmpmutex;
+#define FOREACH_ENTITY_RADIUS_ORDERED(org, dist, cond, body) \
+MACRO_BEGIN \
+ entity _rev_first = NULL; \
+ _FOREACH_ENTITY_FIND_UNORDERED(tmp, radius, org, dist, cond, (it._FOREACH_ENTITY_FIND_radius_nexttmp = _rev_first, _rev_first = it)); \
+ MUTEX_LOCK(_FOREACH_ENTITY_FIND_radius_tmpmutex); \
+ FOREACH_LIST(_rev, _FOREACH_ENTITY_FIND_radius_nexttmp, true, body); \
+ MUTEX_UNLOCK(_FOREACH_ENTITY_FIND_radius_tmpmutex); \
+MACRO_END
#endif
#define FOREACH_ENTITY_FLOAT(fld, match, body) ORDERED(FOREACH_ENTITY_FLOAT)(fld, match, body)
#include "oo.qh"
CLASS(Lazy, Object)
- ATTRIB(Lazy, m_get, entity(), func_null);
+ ATTRIB(Lazy, m_get, entity());
CONSTRUCTOR(Lazy, entity() _compute)
{
this.m_get = _compute;
#pragma once
CLASS(LinkedListNode, Object)
- ATTRIB(LinkedListNode, ll_data, entity, NULL)
- ATTRIB(LinkedListNode, ll_prev, LinkedListNode, NULL)
- ATTRIB(LinkedListNode, ll_next, LinkedListNode, NULL)
+ ATTRIB(LinkedListNode, ll_data, entity);
+ ATTRIB(LinkedListNode, ll_prev, LinkedListNode);
+ ATTRIB(LinkedListNode, ll_next, LinkedListNode);
ENDCLASS(LinkedListNode)
CLASS(LinkedList, Object)
- ATTRIB(LinkedList, ll_head, LinkedListNode, NULL);
- ATTRIB(LinkedList, ll_tail, LinkedListNode, NULL);
+ ATTRIB(LinkedList, ll_head, LinkedListNode);
+ ATTRIB(LinkedList, ll_tail, LinkedListNode);
ENDCLASS(LinkedList)
#define LL_NEW() NEW(LinkedList)
LinkedListNode prev = n.ll_prev;
if (prev) (this.ll_tail = prev).ll_next = NULL;
else this.ll_head = this.ll_tail = NULL;
- remove(n);
+ delete(n);
return e;
}
entity it = LL_POP(_ll); \
if (!it) continue; \
dtor \
- remove(it); \
+ delete(it); \
} \
} MACRO_END
MACRO_BEGIN \
{ \
LL_CLEAR_2(this, dtor); \
- remove(this); \
+ delete(this); \
this = NULL; \
} MACRO_END
#if defined(MENUQC)
-string(string...) strcat0n = #53;
+string(string, string...) strcat1n = #53;
#else
-string(string...) strcat0n = #115;
+string(string, string...) strcat1n = #115;
#endif
-#define __SOURCELOC__ (sprintf("^7%s^9" "(" "^9"__FILE__"^7" ":" "^9"STR(__LINE__)"^7" ")", __FUNC__))
+// would be nice if __FUNC__ could be concatenated at compile time
+#if 0
+ // less work, bigger binary
+ #define __SOURCELOC__ (sprintf("^7%s^9" "(" "^9"__FILE__"^7" ":" "^9"STR(__LINE__)"^7" ")", __FUNC__))
+#else
+ #define __SOURCELOC__ (sprintf("^7%s^9" "(" "^9%s^7" ":" "^9%s^7" ")", __FUNC__, __FILE__, STR(__LINE__)))
+#endif
+#define _LOG_HEADER(level) "^9[::" "^7"PROGNAME"^9" "::" level"^9" "] ", __SOURCELOC__
#define _LOG(f, level, s) \
MACRO_BEGIN { \
- f(sprintf("^9[::" "^7"PROGNAME"^9" "::" level"^9" "] %s\n^7%s\n", __SOURCELOC__, s)); \
+ f(strcat1n(_LOG_HEADER(level), "\n^7", s, "\n")); \
} MACRO_END
-#define LOG_FATAL(...) _LOG_FATAL(strcat0n(__VA_ARGS__))
+#define LOG_FATAL(...) _LOG_FATAL(strcat1n(__VA_ARGS__))
#define LOG_FATALF(...) _LOG_FATAL(sprintf(__VA_ARGS__))
#define _LOG_FATAL(s) _LOG(error, "^1FATAL", s)
-#define LOG_SEVERE(...) _LOG_SEVERE(strcat0n(__VA_ARGS__))
+#define LOG_SEVERE(...) _LOG_SEVERE(strcat1n(__VA_ARGS__))
#define LOG_SEVEREF(...) _LOG_SEVERE(sprintf(__VA_ARGS__))
#define _LOG_SEVERE(s) _LOG(backtrace, "^1SEVERE", s)
-#define LOG_WARNING(...) _LOG_WARNING(strcat0n(__VA_ARGS__))
-#define LOG_WARNINGF(...) _LOG_WARNING(sprintf(__VA_ARGS__))
-#define _LOG_WARNING(s) _LOG(print, "^3WARNING", s)
+#define LOG_WARN(...) _LOG_WARN(strcat1n(__VA_ARGS__))
+#define LOG_WARNF(...) _LOG_WARN(sprintf(__VA_ARGS__))
+#define _LOG_WARN(s) _LOG(print, "^3WARNING", s)
-#define LOG_INFO(...) _LOG_INFO(strcat0n(__VA_ARGS__))
+#define LOG_INFO(...) _LOG_INFO(strcat1n(__VA_ARGS__))
#define LOG_INFOF(...) _LOG_INFO(sprintf(__VA_ARGS__))
#define _LOG_INFO(s) \
MACRO_BEGIN { \
- string ___s = s; \
- if (autocvar_developer) \
- _LOG(print, "^5INFO", ___s); \
- else \
- print(___s); \
+ dprint(_LOG_HEADER("^5INFO")); \
+ print("\n^7", s); \
} MACRO_END
-#define LOG_TRACE(...) _LOG_TRACE(strcat0n(__VA_ARGS__))
+#define LOG_TRACE(...) _LOG_TRACE(strcat1n(__VA_ARGS__))
#define LOG_TRACEF(...) _LOG_TRACE(sprintf(__VA_ARGS__))
#define _LOG_TRACE(s) _LOG(dprint, "^6TRACE", s)
-#define LOG_DEBUG(...) _LOG_DEBUG(strcat0n(__VA_ARGS__))
+#define LOG_DEBUG(...) _LOG_DEBUG(strcat1n(__VA_ARGS__))
#define LOG_DEBUGF(...) _LOG_DEBUG(sprintf(__VA_ARGS__))
#define _LOG_DEBUG(s) _LOG(dprint2, "^2DEBUG", s)
int fh = fopen(filename, FILE_WRITE);
if (fh < 0)
{
- LOG_WARNINGF("^1Can't write DB to %s\n", filename);
+ LOG_WARNF("^1Can't write DB to %s", filename);
return;
}
fputs(fh, strcat(ftos(DB_BUCKETS), "\n"));
void db_dump(int db, string filename)
{
int fh = fopen(filename, FILE_WRITE);
- if (fh < 0) LOG_FATALF("Can't dump DB to %s\n");
+ if (fh < 0) LOG_FATALF("Can't dump DB to %s");
fputs(fh, "0\n");
for (int i = 0, n = buf_getsize(db); i < n; ++i)
{
fh.url_verb = "PUT";
fh.url_content_type = "application/json";
url_fputs(fh, sprintf("{\"displayname\": \"%s\"}", pass.message));
- remove(pass);
+ delete(pass);
url_fclose(fh);
break;
}
{
switch (status) {
default: {
- LOG_WARNINGF("status: %d", status);
+ LOG_WARNF("status: %d", status);
break;
}
case URL_READY_CLOSED: break;
{
switch (status) {
default: {
- LOG_WARNINGF("status: %d", status);
+ LOG_WARNF("status: %d", status);
break;
}
case URL_READY_CLOSED: break;
fh.url_verb = "PUT";
fh.url_content_type = "application/json";
url_fputs(fh, sprintf("{\"typing\": %s, \"timeout\": 30000}", pass.message));
- remove(pass);
+ delete(pass);
url_fclose(fh);
break;
}
fh.url_verb = "PUT";
fh.url_content_type = "application/json";
url_fputs(fh, sprintf("{\"msgtype\": \"m.text\", \"body\": \"%s\"}", pass.message));
- strunzone(pass.message); remove(pass);
+ strunzone(pass.message); delete(pass);
url_fclose(fh);
break;
}
{
entity reader = C2S_Protocol_from(C2S);
if (reader && reader.m_read && reader.m_read(NULL, sender, true)) continue;
- LOG_SEVEREF("Net_ClientCommand() with malformed C2S=%d\n", C2S);
+ LOG_SEVEREF("Net_ClientCommand() with malformed C2S=%d", C2S);
return;
}
g_buf_i--;
int expected = strlen(buf);
- if (g_buf_i > expected) LOG_WARNINGF("Underflow: %d", g_buf_i - expected);
- if (g_buf_i < expected) LOG_WARNINGF("Overrflow: %d", expected - g_buf_i);
+ if (g_buf_i > expected) LOG_WARNF("Underflow: %d", g_buf_i - expected);
+ if (g_buf_i < expected) LOG_WARNF("Overrflow: %d", expected - g_buf_i);
}
#endif
} MACRO_END
#define Net_Reject() \
MACRO_BEGIN { \
- if (this) remove(this); \
+ if (this) delete(this); \
} MACRO_END
string g_buf;
} \
STATIC_METHOD(cname, dtorimpl, void(cname this))
-#define ATTRIB(cname, name, type, val) \
- class(cname).type name; \
+#define ATTRIB(...) EVAL_ATTRIB(OVERLOAD_(ATTRIB, __VA_ARGS__))
+#define EVAL_ATTRIB(...) __VA_ARGS__
+#define ATTRIB_3(cname, name, type) INIT(cname) {} class(cname) .type name
+#define ATTRIB_4(cname, name, type, val) \
+ ATTRIB_3(cname, name, type); \
INIT(cname) \
{ \
noref bool strzone; /* Error on strzone() calls. */ \
this.name = val; \
- }
+ } \
+ ATTRIB_3(cname, name, type)
#define STATIC_ATTRIB(cname, name, type, val) \
type cname##_##name; \
}
#define ATTRIBARRAY(cname, name, type, cnt) \
- class(cname).type name[cnt];
+ class(cname) .type name[cnt]
#define ENDCLASS(cname) \
INIT(cname) \
/* without even the implied warranty of merchantability or fitness for a */
/* particular purpose. */
/* */
-#ifndef P99_H_
-#define P99_H_
+#pragma once
#define P99_MAX_NUMBER 16
#define P00_ARG( \
P99_PASTE2(P99_PASTE3(_1, _2, _3), _4)
#define P99_PASTE5(_1, _2, _3, _4, _5) \
P99_PASTE2(P99_PASTE4(_1, _2, _3, _4), _5)
-
-#endif /* !P99_H_ */
{
if (DistributeEvenly_amount)
{
- LOG_TRACE("DistributeEvenly_Init: UNFINISHED DISTRIBUTION (", ftos(DistributeEvenly_amount), " for ");
- LOG_TRACE(ftos(DistributeEvenly_totalweight), " left!)\n");
+ LOG_TRACE("DistributeEvenly_Init: UNFINISHED DISTRIBUTION (", ftos(DistributeEvenly_amount), " for ", ftos(DistributeEvenly_totalweight), " left!)");
}
if (totalweight == 0) DistributeEvenly_amount = 0;
else DistributeEvenly_amount = amount;
prandom_seed = c;
#ifdef USE_PRANDOM_DEBUG
- LOG_TRACE("RANDOM -> ", ftos(c), "\n");
+ LOG_TRACE("RANDOM -> ", ftos(c));
#endif
return c / 65536; // in [0..1[
{
prandom_seed = seed;
#ifdef USE_PRANDOM_DEBUG
- LOG_TRACE("SRANDOM ", ftos(seed), "\n");
+ LOG_TRACE("SRANDOM ", ftos(seed));
#endif
}
#ifdef USE_PRANDOM_DEBUG
void prandom_debug()
{
- LOG_TRACE("Current random seed = ", ftos(prandom_seed), "\n");
+ LOG_TRACE("Current random seed = ", ftos(prandom_seed));
}
#endif
#endif
FOREACH(id, true, s = strcat(s, join, it.registered_id)); \
s = substring(s, strlen(join), -1); \
string h = REGISTRY_HASH(id) = strzone(digest_hex(algo, s)); \
- LOG_DEBUGF(#id ": %s\n[%s]\n", h, s); \
+ LOG_DEBUGF(#id ": %s\n[%s]", h, s); \
} \
void Registry_check(string r, string sv) \
{ \
string cl = REGISTRY_HASH(id); \
if (cl != sv) \
{ \
- LOG_FATALF("client/server mismatch (%s).\nCL: %s\nSV: %s\n", r, cl, sv); \
+ LOG_FATALF("client/server mismatch (%s).\nCL: %s\nSV: %s", r, cl, sv); \
} \
} \
} \
#define REGISTER_REGISTRY_2(id, str) \
ACCUMULATE_FUNCTION(__static_init, Register##id) \
CLASS(id##Registry, Object) \
- ATTRIB(id##Registry, m_name, string, str) \
- ATTRIB(id##Registry, REGISTRY_NEXT, entity, id##_first) \
+ ATTRIB(id##Registry, m_name, string, str); \
+ ATTRIB(id##Registry, REGISTRY_NEXT, entity, id##_first); \
METHOD(id##Registry, m_reload, void()); \
ENDCLASS(id##Registry) \
REGISTER(Registries, REGISTRY, id, m_id, NEW(id##Registry)); \
#define _spawnfunc_checktypes(fld) \
if (fieldname == #fld) \
- if (!entityfieldassignablefromeditor(i)) LOG_FATALF("Entity field '%s' cannot be whitelisted\n", fieldname);
+ if (!entityfieldassignablefromeditor(i)) LOG_FATALF("Entity field '%s' cannot be whitelisted", fieldname);
#else
#define _spawnfunc_checktypes(fld)
#endif
if (fieldname == "") continue; \
FIELDS_COMMON(_spawnfunc_check) \
whitelist(_spawnfunc_check) \
- LOG_WARNINGF(_("Entity field %s.%s (%s) is not whitelisted. If you believe this is an error, please file an issue.\n"), #id, fieldname, value); \
+ LOG_WARNF(_("Entity field %s.%s (%s) is not whitelisted. If you believe this is an error, please file an issue."), #id, fieldname, value); \
} \
this.spawnfunc_checked = true; \
} \
FIELD_SCALAR(fld, monster_moveflags) \
FIELD_SCALAR(fld, monster_name) \
FIELD_SCALAR(fld, movetype) \
+ FIELD_SCALAR(fld, move_movetype) \
FIELD_SCALAR(fld, netname) \
FIELD_SCALAR(fld, nextthink) \
FIELD_SCALAR(fld, noalign) \
.int m_id;
USING(vectori, vector);
+const int STATS_ENGINE_RESERVE = 32;
+// must be listed in ascending order
+#define MAGIC_STATS(_, x) \
+ _(x, MOVEVARS_TIMESCALE, 241) \
+ /**/
+
+int g_magic_stats_hole = 0;
+
+#define MAGIC_STATS_FIX_MANUAL(it, var, id) \
+ if (it.registered_id == "STAT_" #var) { --g_magic_stats_hole; it.m_id = id; } else
+
+#define MAGIC_STATS_FIX_AUTO(it, var, id) \
+ if (it.m_id == id) { ++g_magic_stats_hole; ++it.m_id; }
+
+#define MAGIC_STATS_FIX(it) \
+ it.m_id += g_magic_stats_hole; \
+ MAGIC_STATS(MAGIC_STATS_FIX_MANUAL, it) { MAGIC_STATS(MAGIC_STATS_FIX_AUTO, it) }
+
#define REGISTER_STAT(...) EVAL_REGISTER_STAT(OVERLOAD(REGISTER_STAT, __VA_ARGS__))
#define EVAL_REGISTER_STAT(...) __VA_ARGS__
#if defined(CSQC)
/** Prevent engine stats being sent */
STATIC_INIT(stats_clear)
{
- int r = 32;
+ int r = STATS_ENGINE_RESERVE;
for (int i = 0, n = 256 - r; i < n; ++i) {
+ #define X(_, name, id) if (i == id) continue;
+ MAGIC_STATS(X, );
+ #undef X
addstat(r + i, AS_INT, __stat_null);
}
}
#define REGISTER_STAT_3(id, T, expr)
#endif
-const int STATS_ENGINE_RESERVE = 32;
-
REGISTRY(Stats, 256 - STATS_ENGINE_RESERVE)
REGISTER_REGISTRY(Stats)
REGISTRY_SORT(Stats)
REGISTRY_CHECK(Stats)
STATIC_INIT(RegisterStats_renumber)
{
- FOREACH(Stats, true, it.m_id = STATS_ENGINE_RESERVE + i);
+ FOREACH(Stats, true, {
+ it.m_id = STATS_ENGINE_RESERVE + i;
+ MAGIC_STATS_FIX(it);
+ });
}
#ifdef SVQC
STATIC_INIT(stats_add) { stats_add(); }
#define SUCCEED() (TEST_ok = true)
/** Add a failure, but continue */
-#define ADD_FAILURE(msg) MACRO_BEGIN { ++TEST_failed; LOG_WARNINGF(msg); } MACRO_END
+#define ADD_FAILURE(msg) MACRO_BEGIN { ++TEST_failed; LOG_WARN(msg); } MACRO_END
/** Add a failure and return */
#define FAIL(msg) _TEST_ASSERT(ADD_FAILURE(msg))
#define EXPECT_NO_FATAL_FAILURE_(statement, then) \
EXPECT_NO_FATAL_FAILURE__(statement, { \
- LOG_WARNINGF( \
+ LOG_WARNF( \
" Actual: %d fatal failures\n" \
"Expected: no fatal failures\n", \
TEST_fatal - TEST_prevfatal \
LOG_INFO("url_URI_Get_Callback: out of memory in buf_create\n");
e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
strunzone(e.url_url);
- remove(e);
+ delete(e);
return 1;
}
e.url_rbufpos = 0;
LOG_INFO("url_URI_Get_Callback: out of memory in buf_create\n");
e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
strunzone(e.url_url);
- remove(e);
+ delete(e);
return 1;
}
for (i = 0; i < n; ++i)
// an ERROR
e.url_ready(e, e.url_ready_pass, -fabs(status));
strunzone(e.url_url);
- remove(e);
+ delete(e);
return 1;
}
}
LOG_INFO("url_single_fopen: out of memory in buf_create\n");
rdy(e, pass, URL_READY_ERROR);
strunzone(e.url_url);
- remove(e);
+ delete(e);
return;
}
e.url_wbufpos = 0;
e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
buf_del(e.url_wbuf);
strunzone(e.url_url);
- remove(e);
+ delete(e);
return;
}
}
e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
buf_del(e.url_wbuf);
strunzone(e.url_url);
- remove(e);
+ delete(e);
return;
}
e.url_ready(e, e.url_ready_pass, URL_READY_CLOSED);
buf_del(e.url_rbuf);
strunzone(e.url_url);
- remove(e);
+ delete(e);
}
}
else if (e.url_fh == URL_FH_STDOUT)
{
e.url_ready(e, e.url_ready_pass, URL_READY_CLOSED); // closing creates no reading handle
- remove(e);
+ delete(e);
}
else
{
// file
fclose(e.url_fh);
e.url_ready(e, e.url_ready_pass, URL_READY_CLOSED); // closing creates no reading handle
- remove(e);
+ delete(e);
}
}
else if (e.url_fh == URL_FH_STDOUT)
{
// stdout
- LOG_INFO(s);
+ print(s);
}
else
{
LOG_INFO("uri_multi_ready: got HTTP error 422, data is in unusable format - not continuing\n");
me.url_ready(fh, me.url_ready_pass, status);
strunzone(me.url_url);
- remove(me);
+ delete(me);
return;
}
me.url_attempt += 1;
{
me.url_ready(fh, me.url_ready_pass, status);
strunzone(me.url_url);
- remove(me);
+ delete(me);
return;
}
url_single_fopen(argv(me.url_attempt), me.url_mode, url_multi_ready, me);
}
#endif
+noref vector _vmul_a, _vmul_b;
+#define vmul(a, b) \
+ (_vmul_a = (a), _vmul_b = (b), \
+ '1 0 0' * (_vmul_a.x * _vmul_b.x) \
+ + '0 1 0' * (_vmul_a.y * _vmul_b.y) \
+ + '0 0 1' * (_vmul_a.z * _vmul_b.z))
+
const vector eX = '1 0 0';
const vector eY = '0 1 0';
const vector eZ = '0 0 1';
return vel - (1 + bounce) * (vel * norm) * norm;
}
+vector vec_epsilon(vector this, float eps)
+{
+ if (this.x > -eps && this.x < eps) this.x = 0;
+ if (this.y > -eps && this.y < eps) this.y = 0;
+ if (this.z > -eps && this.z < eps) this.z = 0;
+ return this;
+}
+
+#define ClipVelocity(in, normal, out, overbounce) \
+ (out = vec_epsilon(vec_reflect(in, normal, (overbounce) - 1), 0.1))
+
#ifndef MENUQC
vector get_corner_position(entity box, int corner)
{
-#ifndef LIB_WARPZONE_ANGLETRANSFORM_H
-#define LIB_WARPZONE_ANGLETRANSFORM_H
+#pragma once
#ifndef POSITIVE_PITCH_IS_DOWN
#define POSITIVE_PITCH_IS_DOWN 1
// transformed = original * transform + postshift
vector AnglesTransform_Multiply_GetPostShift(vector sf0, vector st0, vector t1, vector st1);
vector AnglesTransform_PrePostShift_GetPostShift(vector sf, vector t, vector st);
-#endif
-#ifndef LIB_WARPZONE_CLIENT_H
-#define LIB_WARPZONE_CLIENT_H
+#pragma once
void WarpZone_FixPMove();
void WarpZone_FixView();
vector warpzone_save_view_origin;
vector warpzone_save_view_angles;
-#endif
#ifdef CSQC
if (trace_networkentity)
{
- LOG_TRACE("hit a network ent, cannot continue WarpZoneLib_BoxTouchesBrush\n");
+ LOG_TRACE("hit a network ent, cannot continue WarpZoneLib_BoxTouchesBrush");
// we cannot continue, as a player blocks us...
// so, abort
return 0;
{
if(--i < 1)
{
- LOG_TRACE("Too many warpzones in sequence, aborting trace.\n");
+ LOG_TRACE("Too many warpzones in sequence, aborting trace.");
trace_ent = NULL;
break;
}
if(trace_ent == wz)
{
// FIXME can this check be removed? Do we really need it?
- LOG_TRACE("I transformed into the same zone again, wtf, aborting the trace\n");
+ LOG_TRACE("I transformed into the same zone again, wtf, aborting the trace");
trace_ent = NULL;
break;
}
{
if(--i < 1)
{
- LOG_TRACE("Too many warpzones in sequence, aborting trace.\n");
+ LOG_TRACE("Too many warpzones in sequence, aborting trace.");
trace_ent = NULL;
break;
}
if(trace_ent == wz)
{
// FIXME can this check be removed? Do we really need it?
- LOG_TRACE("I transformed into the same zone again, wtf, aborting the trace\n");
+ LOG_TRACE("I transformed into the same zone again, wtf, aborting the trace");
trace_ent = NULL;
break;
}
// garbage collect unused reference systems
this.nextthink = time + 1;
if(this.owner.WarpZone_refsys != this)
- remove(this);
+ delete(this);
}
void WarpZone_RefSys_CheckCreate(entity me)
{
{
if(me.WarpZone_refsys)
{
- remove(me.WarpZone_refsys);
+ delete(me.WarpZone_refsys);
me.WarpZone_refsys = NULL;
}
}
-#ifndef LIB_WARPZONE_COMMON_H
-#define LIB_WARPZONE_COMMON_H
+#pragma once
// uncomment this if your mod uses the roll angle in fixangle
// #define KEEP_ROLL
// WARNING: this kills the trace globals
#define EXACTTRIGGER_TOUCH(e,t) if(WarpZoneLib_ExactTrigger_Touch((e), (t))) return
#define EXACTTRIGGER_INIT WarpZoneLib_ExactTrigger_Init(this)
-#endif
-#ifndef LIB_WARPZONE_MATHLIB_H
-#define LIB_WARPZONE_MATHLIB_H
+#pragma once
// <math.h>
const float M_2_SQRTPI = 1.12837916709551257390; /* 2/sqrt(pi) */
const float M_SQRT2 = 1.41421356237309504880; /* sqrt(2) */
const float M_SQRT1_2 = 0.70710678118654752440; /* 1/sqrt(2) */
-
-#endif
}
else
{
- LOG_TRACE("WARPZONE FAIL AHAHAHAHAH))\n");
+ LOG_TRACE("WARPZONE FAIL AHAHAHAHAH))");
}
}
-#ifndef LIB_WARPZONE_SERVER_H
-#define LIB_WARPZONE_SERVER_H
+#pragma once
#ifdef SVQC
void WarpZone_StartFrame();
void WarpZone_PostInitialize_Callback();
#endif
-
-#endif
-#ifndef LIB_WARPZONE_UTIL_SERVER_H
-#define LIB_WARPZONE_UTIL_SERVER_H
+#pragma once
float WarpZoneLib_MoveOutOfSolid(entity e);
float WarpZoneLib_ExactTrigger_Touch(entity this, entity toucher);
#ifdef SVQC
void WarpZoneLib_ExactTrigger_Init(entity this);
#endif
-#endif
METHOD(Animation, resumeAnim, void(Animation this));
METHOD(Animation, isFinished, float(Animation this));
METHOD(Animation, finishAnim, void(Animation this));
- ATTRIB(Animation, object, entity, NULL)
+ ATTRIB(Animation, object, entity);
void setterDummy(Animation this, float) {}
- ATTRIB(Animation, setter, void(Animation this, float), setterDummy)
- ATTRIB(Animation, value, float, 0)
- ATTRIB(Animation, startTime, float, 0)
- ATTRIB(Animation, duration, float, 0)
- ATTRIB(Animation, startValue, float, 0)
- ATTRIB(Animation, delta, float, 0)
- ATTRIB(Animation, stopped, float, false)
- ATTRIB(Animation, finished, float, false)
+ ATTRIB(Animation, setter, void(Animation this, float), setterDummy);
+ ATTRIB(Animation, value, float, 0);
+ ATTRIB(Animation, startTime, float, 0);
+ ATTRIB(Animation, duration, float, 0);
+ ATTRIB(Animation, startValue, float, 0);
+ ATTRIB(Animation, delta, float, 0);
+ ATTRIB(Animation, stopped, float, false);
+ ATTRIB(Animation, finished, float, false);
ENDCLASS(Animation)
if (n) n.prevSibling = p;
else this.lastChild = p;
- remove(other);
+ delete(other);
}
METHOD(AnimHost, removeAllAnim, void(entity this))
METHOD(AnimHost, finishAllAnim, void(entity));
METHOD(AnimHost, finishObjAnim, void(entity, entity));
METHOD(AnimHost, tickAll, void(entity));
- ATTRIB(AnimHost, firstChild, entity, NULL)
- ATTRIB(AnimHost, lastChild, entity, NULL)
+ ATTRIB(AnimHost, firstChild, entity);
+ ATTRIB(AnimHost, lastChild, entity);
ENDCLASS(AnimHost)
CLASS(Easing, Animation)
METHOD(Easing, calcValue, float(entity, float, float, float, float));
METHOD(Easing, setMath, void(entity, float(float, float, float, float)));
- ATTRIB(Easing, math, float(float, float, float, float), easingLinear)
+ ATTRIB(Easing, math, float(float, float, float, float), easingLinear);
ENDCLASS(Easing)
METHOD(Keyframe, addEasing, entity(entity, float, float, float(float, float, float, float)));
METHOD(Keyframe, addAnim, void(entity, entity));
METHOD(Keyframe, calcValue, float(entity, float, float, float, float));
- ATTRIB(Keyframe, currentChild, entity, NULL)
- ATTRIB(Keyframe, firstChild, entity, NULL)
- ATTRIB(Keyframe, lastChild, entity, NULL)
+ ATTRIB(Keyframe, currentChild, entity);
+ ATTRIB(Keyframe, firstChild, entity);
+ ATTRIB(Keyframe, lastChild, entity);
ENDCLASS(Keyframe)
entity makeHostedKeyframe(entity, void(entity, float), float, float, float);
entity makeKeyframe(entity, void(entity, float), float, float, float);
+#include "all.qh"
+
#include <common/command/all.qc>
--- /dev/null
+#pragma once
void draw_Text(vector theOrigin, string theText, vector theSize, vector theColor, float theAlpha, float ICanHasKallerz)
{
if(theSize.x <= 0 || theSize.y <= 0) {
- LOG_TRACE("Drawing zero size text?\n");
+ LOG_TRACE("Drawing zero size text?");
return;
}
METHOD(Item, hideNotify, void(Item));
METHOD(Item, toString, string(Item));
METHOD(Item, destroy, void(Item));
- ATTRIB(Item, focused, float, 0)
- ATTRIB(Item, focusable, float, 0)
- ATTRIB(Item, allowFocusSound, float, 0)
- ATTRIB(Item, parent, entity, NULL)
- ATTRIB(Item, preferredFocusPriority, float, 0)
- ATTRIB(Item, origin, vector, '0 0 0')
- ATTRIB(Item, size, vector, '0 0 0')
- ATTRIB(Item, tooltip, string, string_null)
+ ATTRIB(Item, focused, float, 0);
+ ATTRIB(Item, focusable, float, 0);
+ ATTRIB(Item, allowFocusSound, float, 0);
+ ATTRIB(Item, parent, entity);
+ ATTRIB(Item, preferredFocusPriority, float, 0);
+ ATTRIB(Item, origin, vector, '0 0 0');
+ ATTRIB(Item, size, vector, '0 0 0');
+ ATTRIB(Item, tooltip, string);
ENDCLASS(Item)
METHOD(BorderImage, configureBorderImage, void(entity, string, float, vector, string, float));
METHOD(BorderImage, resizeNotify, void(entity, vector, vector, vector, vector));
METHOD(BorderImage, recalcPositionWithText, void(entity, string));
- ATTRIB(BorderImage, isBold, float, 1)
+ ATTRIB(BorderImage, isBold, float, 1);
METHOD(BorderImage, draw, void(entity));
- ATTRIB(BorderImage, src, string, string_null)
- ATTRIB(BorderImage, borderHeight, float, 0)
- ATTRIB(BorderImage, borderVec, vector, '0 0 0')
- ATTRIB(BorderImage, color, vector, '1 1 1')
- ATTRIB(BorderImage, closeButton, entity, NULL)
- ATTRIB(BorderImage, realFontSize_Nexposeed, vector, '0 0 0')
- ATTRIB(BorderImage, realOrigin_Nexposeed, vector, '0 0 0')
- ATTRIB(BorderImage, isNexposeeTitleBar, float, 0)
- ATTRIB(BorderImage, zoomedOutTitleBarPosition, float, 0)
- ATTRIB(BorderImage, zoomedOutTitleBar, float, 0)
- ATTRIB(BorderImage, overrideRealOrigin, vector, '0 1 0')
- ATTRIB(BorderImage, saveRelOrigin, vector, '0 0 0')
- ATTRIB(BorderImage, saveRelSize, vector, '0 0 0')
+ ATTRIB(BorderImage, src, string);
+ ATTRIB(BorderImage, borderHeight, float, 0);
+ ATTRIB(BorderImage, borderVec, vector, '0 0 0');
+ ATTRIB(BorderImage, color, vector, '1 1 1');
+ ATTRIB(BorderImage, closeButton, entity);
+ ATTRIB(BorderImage, realFontSize_Nexposeed, vector, '0 0 0');
+ ATTRIB(BorderImage, realOrigin_Nexposeed, vector, '0 0 0');
+ ATTRIB(BorderImage, isNexposeeTitleBar, float, 0);
+ ATTRIB(BorderImage, zoomedOutTitleBarPosition, float, 0);
+ ATTRIB(BorderImage, zoomedOutTitleBar, float, 0);
+ ATTRIB(BorderImage, overrideRealOrigin, vector, '0 1 0');
+ ATTRIB(BorderImage, saveRelOrigin, vector, '0 0 0');
+ ATTRIB(BorderImage, saveRelSize, vector, '0 0 0');
ENDCLASS(BorderImage)
.vector colorC, colorF;
METHOD(Button, mouseDrag, float(entity, vector));
METHOD(Button, mouseRelease, float(entity, vector));
METHOD(Button, playClickSound, void(entity));
- ATTRIB(Button, onClick, void(entity, entity), func_null)
- ATTRIB(Button, onClickEntity, entity, NULL)
- ATTRIB(Button, src, string, string_null)
- ATTRIB(Button, srcSuffix, string, string_null)
- ATTRIB(Button, src2, string, string_null) // is centered, same aspect, and stretched to label size
- ATTRIB(Button, src2scale, float, 1)
- ATTRIB(Button, srcMulti, float, 1) // 0: button square left, text right; 1: button stretched, text over it
- ATTRIB(Button, buttonLeftOfText, float, 0)
- ATTRIB(Button, focusable, float, 1)
- ATTRIB(Button, allowFocusSound, float, 1)
- ATTRIB(Button, pressed, float, 0)
- ATTRIB(Button, clickTime, float, 0)
- ATTRIB(Button, applyButton, entity, NULL)
- ATTRIB(Button, disableOnClick, bool, false)
- ATTRIB(Button, disabled, float, 0)
- ATTRIB(Button, disabledAlpha, float, 0.3)
- ATTRIB(Button, forcePressed, float, 0)
- ATTRIB(Button, color, vector, '1 1 1')
- ATTRIB(Button, colorC, vector, '1 1 1')
- ATTRIB(Button, colorF, vector, '1 1 1')
- ATTRIB(Button, colorD, vector, '1 1 1')
- ATTRIB(Button, color2, vector, '1 1 1')
- ATTRIB(Button, alpha2, float, 1)
+ ATTRIB(Button, onClick, void(entity, entity));
+ ATTRIB(Button, onClickEntity, entity);
+ ATTRIB(Button, src, string);
+ ATTRIB(Button, srcSuffix, string);
+ ATTRIB(Button, src2, string); // is centered, same aspect, and stretched to label size
+ ATTRIB(Button, src2scale, float, 1);
+ ATTRIB(Button, srcMulti, float, 1); // 0: button square left, text right; 1: button stretched, text over it
+ ATTRIB(Button, buttonLeftOfText, float, 0);
+ ATTRIB(Button, focusable, float, 1);
+ ATTRIB(Button, allowFocusSound, float, 1);
+ ATTRIB(Button, pressed, float, 0);
+ ATTRIB(Button, clickTime, float, 0);
+ ATTRIB(Button, applyButton, entity);
+ ATTRIB(Button, disableOnClick, bool, false);
+ ATTRIB(Button, disabled, float, 0);
+ ATTRIB(Button, disabledAlpha, float, 0.3);
+ ATTRIB(Button, forcePressed, float, 0);
+ ATTRIB(Button, color, vector, '1 1 1');
+ ATTRIB(Button, colorC, vector, '1 1 1');
+ ATTRIB(Button, colorF, vector, '1 1 1');
+ ATTRIB(Button, colorD, vector, '1 1 1');
+ ATTRIB(Button, color2, vector, '1 1 1');
+ ATTRIB(Button, alpha2, float, 1);
- ATTRIB(Button, origin, vector, '0 0 0')
- ATTRIB(Button, size, vector, '0 0 0')
+ ATTRIB(Button, origin, vector, '0 0 0');
+ ATTRIB(Button, size, vector, '0 0 0');
ENDCLASS(Button)
METHOD(CheckBox, playClickSound, void(entity));
METHOD(CheckBox, toString, string(entity));
METHOD(CheckBox, setChecked, void(entity, float));
- ATTRIB(CheckBox, useDownAsChecked, float, 0)
- ATTRIB(CheckBox, checked, float, 0)
+ ATTRIB(CheckBox, useDownAsChecked, float, 0);
+ ATTRIB(CheckBox, checked, float, 0);
void CheckBox_Click(entity me, entity other);
- ATTRIB(CheckBox, onClick, void(entity, entity), CheckBox_Click)
- ATTRIB(CheckBox, srcMulti, float, 0)
- ATTRIB(CheckBox, disabled, float, 0)
+ ATTRIB(CheckBox, onClick, void(entity, entity), CheckBox_Click);
+ ATTRIB(CheckBox, srcMulti, float, 0);
+ ATTRIB(CheckBox, disabled, float, 0);
ENDCLASS(CheckBox)
METHOD(Container, showNotify, void(entity));
METHOD(Container, hideNotify, void(entity));
METHOD(Container, preferredFocusedGrandChild, entity(entity));
- ATTRIB(Container, focusable, float, 0)
- ATTRIB(Container, firstChild, entity, NULL)
- ATTRIB(Container, lastChild, entity, NULL)
- ATTRIB(Container, focusedChild, entity, NULL)
- ATTRIB(Container, savedFocus, entity, NULL)
- ATTRIB(Container, shown, float, 0)
+ ATTRIB(Container, focusable, float, 0);
+ ATTRIB(Container, firstChild, entity);
+ ATTRIB(Container, lastChild, entity);
+ ATTRIB(Container, focusedChild, entity);
+ ATTRIB(Container, savedFocus, entity);
+ ATTRIB(Container, shown, float, 0);
METHOD(Container, enterSubitem, void(entity, entity));
METHOD(Container, enterLieSubitem, void(entity, vector, vector, vector, float));
METHOD(Dialog, TR, void(entity));
METHOD(Dialog, gotoRC, void(entity, float, float));
- ATTRIB(Dialog, isTabRoot, float, 1)
- ATTRIB(Dialog, closeButton, entity, NULL)
- ATTRIB(Dialog, intendedHeight, float, 0)
- ATTRIB(Dialog, itemOrigin, vector, '0 0 0')
- ATTRIB(Dialog, itemSize, vector, '0 0 0')
- ATTRIB(Dialog, itemSpacing, vector, '0 0 0')
- ATTRIB(Dialog, currentRow, float, 0)
- ATTRIB(Dialog, currentColumn, float, 0)
- ATTRIB(Dialog, firstColumn, float, 0)
+ ATTRIB(Dialog, isTabRoot, float, 1);
+ ATTRIB(Dialog, closeButton, entity);
+ ATTRIB(Dialog, intendedHeight, float, 0);
+ ATTRIB(Dialog, itemOrigin, vector, '0 0 0');
+ ATTRIB(Dialog, itemSize, vector, '0 0 0');
+ ATTRIB(Dialog, itemSpacing, vector, '0 0 0');
+ ATTRIB(Dialog, currentRow, float, 0);
+ ATTRIB(Dialog, currentColumn, float, 0);
+ ATTRIB(Dialog, firstColumn, float, 0);
// to be customized
- ATTRIB(Dialog, closable, float, 1)
- ATTRIB(Dialog, title, string, "Form1") // ;)
- ATTRIB(Dialog, color, vector, '1 0.5 1')
- ATTRIB(Dialog, intendedWidth, float, 0)
- ATTRIB(Dialog, rows, float, 3)
- ATTRIB(Dialog, columns, float, 2)
+ ATTRIB(Dialog, closable, float, 1);
+ ATTRIB(Dialog, title, string, "Form1");
+ ATTRIB(Dialog, color, vector, '1 0.5 1');
+ ATTRIB(Dialog, intendedWidth, float, 0);
+ ATTRIB(Dialog, rows, float, 3);
+ ATTRIB(Dialog, columns, float, 2);
- ATTRIB(Dialog, marginTop, float, 0) // pixels
- ATTRIB(Dialog, marginBottom, float, 0) // pixels
- ATTRIB(Dialog, marginLeft, float, 0) // pixels
- ATTRIB(Dialog, marginRight, float, 0) // pixels
- ATTRIB(Dialog, columnSpacing, float, 0) // pixels
- ATTRIB(Dialog, rowSpacing, float, 0) // pixels
- ATTRIB(Dialog, rowHeight, float, 0) // pixels
- ATTRIB(Dialog, titleHeight, float, 0) // pixels
- ATTRIB(Dialog, titleFontSize, float, 0) // pixels; if 0, title causes no margin
- ATTRIB(Dialog, zoomedOutTitleBarPosition, float, 0)
- ATTRIB(Dialog, zoomedOutTitleBar, float, 0)
+ ATTRIB(Dialog, marginTop, float, 0); // pixels
+ ATTRIB(Dialog, marginBottom, float, 0); // pixels
+ ATTRIB(Dialog, marginLeft, float, 0); // pixels
+ ATTRIB(Dialog, marginRight, float, 0); // pixels
+ ATTRIB(Dialog, columnSpacing, float, 0); // pixels
+ ATTRIB(Dialog, rowSpacing, float, 0); // pixels
+ ATTRIB(Dialog, rowHeight, float, 0); // pixels
+ ATTRIB(Dialog, titleHeight, float, 0); // pixels
+ ATTRIB(Dialog, titleFontSize, float, 0); // pixels; if 0, title causes no margin
+ ATTRIB(Dialog, zoomedOutTitleBarPosition, float, 0);
+ ATTRIB(Dialog, zoomedOutTitleBar, float, 0);
- ATTRIB(Dialog, requiresConnection, float, 0) // set to true if the dialog requires a connection to be opened
+ ATTRIB(Dialog, requiresConnection, float, 0); // set to true if the dialog requires a connection to be opened
- ATTRIB(Dialog, backgroundImage, string, string_null)
- ATTRIB(Dialog, borderLines, float, 1)
- ATTRIB(Dialog, closeButtonImage, string, string_null)
+ ATTRIB(Dialog, backgroundImage, string);
+ ATTRIB(Dialog, borderLines, float, 1);
+ ATTRIB(Dialog, closeButtonImage, string);
- ATTRIB(Dialog, frame, entity, NULL)
+ ATTRIB(Dialog, frame, entity);
ENDCLASS(Dialog)
void Dialog_Close(entity button, entity me);
METHOD(Image, setZoom, void(entity, float, float));
METHOD(Image, drag_setStartPos, float(entity, vector));
METHOD(Image, drag, float(entity, vector));
- ATTRIB(Image, src, string, string_null)
- ATTRIB(Image, color, vector, '1 1 1')
- ATTRIB(Image, forcedAspect, float, 0) // special values: -1 keep image aspect ratio, -2 keep image size but bound to the containing box, -3 always keep image size
- ATTRIB(Image, zoomBox, float, 0) // used by forcedAspect -2 when the image is larger than the containing box
- ATTRIB(Image, zoomFactor, float, 1)
- ATTRIB(Image, zoomOffset, vector, '0.5 0.5 0')
- ATTRIB(Image, zoomSnapToTheBox, float, 1) // snap the zoomed in image to the box borders when zooming/dragging it
- ATTRIB(Image, zoomTime, float, 0)
- ATTRIB(Image, zoomLimitedByTheBox, float, 0) // forbids zoom if image would be larger than the containing box
- ATTRIB(Image, zoomMax, float, 0)
- ATTRIB(Image, start_zoomOffset, vector, '0 0 0')
- ATTRIB(Image, start_coords, vector, '0 0 0')
- ATTRIB(Image, imgOrigin, vector, '0 0 0')
- ATTRIB(Image, imgSize, vector, '0 0 0')
+ ATTRIB(Image, src, string);
+ ATTRIB(Image, color, vector, '1 1 1');
+ ATTRIB(Image, forcedAspect, float, 0); // special values: -1 keep image aspect ratio, -2 keep image size but bound to the containing box, -3 always keep image size
+ ATTRIB(Image, zoomBox, float, 0); // used by forcedAspect -2 when the image is larger than the containing box
+ ATTRIB(Image, zoomFactor, float, 1);
+ ATTRIB(Image, zoomOffset, vector, '0.5 0.5 0');
+ ATTRIB(Image, zoomSnapToTheBox, float, 1); // snap the zoomed in image to the box borders when zooming/dragging it
+ ATTRIB(Image, zoomTime, float, 0);
+ ATTRIB(Image, zoomLimitedByTheBox, float, 0); // forbids zoom if image would be larger than the containing box
+ ATTRIB(Image, zoomMax, float, 0);
+ ATTRIB(Image, start_zoomOffset, vector, '0 0 0');
+ ATTRIB(Image, start_coords, vector, '0 0 0');
+ ATTRIB(Image, imgOrigin, vector, '0 0 0');
+ ATTRIB(Image, imgSize, vector, '0 0 0');
ENDCLASS(Image)
METHOD(InputBox, showNotify, void(entity));
METHOD(InputBox, resizeNotify, void(entity, vector, vector, vector, vector));
- ATTRIB(InputBox, src, string, string_null)
+ ATTRIB(InputBox, src, string);
- ATTRIB(InputBox, cursorPos, float, 0) // characters
- ATTRIB(InputBox, scrollPos, float, 0) // widths
+ ATTRIB(InputBox, cursorPos, float, 0); // characters
+ ATTRIB(InputBox, scrollPos, float, 0); // widths
- ATTRIB(InputBox, focusable, float, 1)
- ATTRIB(InputBox, allowFocusSound, float, 1)
- ATTRIB(InputBox, disabled, float, 0)
- ATTRIB(InputBox, lastChangeTime, float, 0)
- ATTRIB(InputBox, dragScrollTimer, float, 0)
- ATTRIB(InputBox, dragScrollPos, vector, '0 0 0')
- ATTRIB(InputBox, pressed, float, 0)
- ATTRIB(InputBox, editColorCodes, float, 1)
- ATTRIB(InputBox, forbiddenCharacters, string, "")
- ATTRIB(InputBox, color, vector, '1 1 1')
- ATTRIB(InputBox, colorF, vector, '1 1 1')
- ATTRIB(InputBox, maxLength, float, 255) // if negative, it counts bytes, not chars
- ATTRIB(InputBox, applyButton, entity, NULL)
+ ATTRIB(InputBox, focusable, float, 1);
+ ATTRIB(InputBox, allowFocusSound, float, 1);
+ ATTRIB(InputBox, disabled, float, 0);
+ ATTRIB(InputBox, lastChangeTime, float, 0);
+ ATTRIB(InputBox, dragScrollTimer, float, 0);
+ ATTRIB(InputBox, dragScrollPos, vector, '0 0 0');
+ ATTRIB(InputBox, pressed, float, 0);
+ ATTRIB(InputBox, editColorCodes, float, 1);
+ ATTRIB(InputBox, forbiddenCharacters, string, "");
+ ATTRIB(InputBox, color, vector, '1 1 1');
+ ATTRIB(InputBox, colorF, vector, '1 1 1');
+ ATTRIB(InputBox, maxLength, float, 255); // if negative, it counts bytes, not chars
+ ATTRIB(InputBox, applyButton, entity);
- ATTRIB(InputBox, enableClearButton, float, 1)
- ATTRIB(InputBox, clearButton, entity, NULL)
- ATTRIB(InputBox, cb_width, float, 0)
- ATTRIB(InputBox, cb_pressed, float, 0)
- ATTRIB(InputBox, cb_focused, float, 0)
- ATTRIB(InputBox, cb_color, vector, '1 1 1')
- ATTRIB(InputBox, cb_colorF, vector, '1 1 1')
- ATTRIB(InputBox, cb_colorC, vector, '1 1 1')
+ ATTRIB(InputBox, enableClearButton, float, 1);
+ ATTRIB(InputBox, clearButton, entity);
+ ATTRIB(InputBox, cb_width, float, 0);
+ ATTRIB(InputBox, cb_pressed, float, 0);
+ ATTRIB(InputBox, cb_focused, float, 0);
+ ATTRIB(InputBox, cb_color, vector, '1 1 1');
+ ATTRIB(InputBox, cb_colorF, vector, '1 1 1');
+ ATTRIB(InputBox, cb_colorC, vector, '1 1 1');
ENDCLASS(InputBox)
METHOD(InputContainer, resizeNotify, void(entity, vector, vector, vector, vector));
METHOD(InputContainer, _changeFocusXY, bool(entity this, vector pos));
- ATTRIB(InputContainer, mouseFocusedChild, entity, NULL)
- ATTRIB(InputContainer, isTabRoot, float, 0)
+ ATTRIB(InputContainer, mouseFocusedChild, entity);
+ ATTRIB(InputContainer, isTabRoot, float, 0);
ENDCLASS(InputContainer)
{
if (!me.overrideRealOrigin_x) me.realOrigin_x = me.keepspaceLeft;
if (!me.overrideCondenseFactor) me.condenseFactor = spaceAvail / spaceUsed;
- LOG_TRACEF("NOTE: label text %s too wide for label, condensed by factor %f\n", t, me.condenseFactor);
+ LOG_TRACEF("NOTE: label text %s too wide for label, condensed by factor %f", t, me.condenseFactor);
}
if (!me.overrideRealOrigin_y)
METHOD(Label, setText, void(entity, string));
METHOD(Label, toString, string(entity));
METHOD(Label, recalcPositionWithText, void(entity, string));
- ATTRIB(Label, isBold, float, 0)
- ATTRIB(Label, text, string, string_null)
- ATTRIB(Label, currentText, string, string_null)
- ATTRIB(Label, fontSize, float, 8)
- ATTRIB(Label, align, float, 0.5)
- ATTRIB(Label, allowCut, float, 0)
- ATTRIB(Label, allowColors, float, 0)
- ATTRIB(Label, keepspaceLeft, float, 0) // for use by subclasses (radiobuttons for example)
- ATTRIB(Label, keepspaceRight, float, 0)
- ATTRIB(Label, marginLeft, float, 0) // alternate way to specify keepspace* (in characters from the font)
- ATTRIB(Label, marginRight, float, 0)
- ATTRIB(Label, realFontSize, vector, '0 0 0')
- ATTRIB(Label, realOrigin, vector, '0 0 0')
- ATTRIB(Label, alpha, float, 0.7)
- ATTRIB(Label, colorL, vector, SKINCOLOR_TEXT)
- ATTRIB(Label, disabled, float, 0)
- ATTRIB(Label, disabledAlpha, float, 0.3)
- ATTRIB(Label, textEntity, entity, NULL)
- ATTRIB(Label, allowWrap, float, 0)
- ATTRIB(Label, recalcPos, float, 0)
- ATTRIB(Label, condenseFactor, float, 1)
- ATTRIB(Label, overrideRealOrigin, vector, '0 0 0')
- ATTRIB(Label, overrideCondenseFactor, float, 0)
+ ATTRIB(Label, isBold, float, 0);
+ ATTRIB(Label, text, string);
+ ATTRIB(Label, currentText, string);
+ ATTRIB(Label, fontSize, float, 8);
+ ATTRIB(Label, align, float, 0.5);
+ ATTRIB(Label, allowCut, float, 0);
+ ATTRIB(Label, allowColors, float, 0);
+ ATTRIB(Label, keepspaceLeft, float, 0); // for use by subclasses (radiobuttons for example);
+ ATTRIB(Label, keepspaceRight, float, 0);
+ ATTRIB(Label, marginLeft, float, 0); // alternate way to specify keepspace* (in characters from the font);
+ ATTRIB(Label, marginRight, float, 0);
+ ATTRIB(Label, realFontSize, vector, '0 0 0');
+ ATTRIB(Label, realOrigin, vector, '0 0 0');
+ ATTRIB(Label, alpha, float, 0.7);
+ ATTRIB(Label, colorL, vector, SKINCOLOR_TEXT);
+ ATTRIB(Label, disabled, float, 0);
+ ATTRIB(Label, disabledAlpha, float, 0.3);
+ ATTRIB(Label, textEntity, entity);
+ ATTRIB(Label, allowWrap, float, 0);
+ ATTRIB(Label, recalcPos, float, 0);
+ ATTRIB(Label, condenseFactor, float, 1);
+ ATTRIB(Label, overrideRealOrigin, vector, '0 0 0');
+ ATTRIB(Label, overrideCondenseFactor, float, 0);
ENDCLASS(Label)
METHOD(ListBox, mouseDrag, float(entity, vector));
METHOD(ListBox, mouseRelease, float(entity, vector));
METHOD(ListBox, focusLeave, void(entity));
- ATTRIB(ListBox, focusable, float, 1)
- ATTRIB(ListBox, focusedItem, int, -1)
- ATTRIB(ListBox, focusedItemAlpha, float, 0.3)
+ ATTRIB(ListBox, focusable, float, 1);
+ ATTRIB(ListBox, focusedItem, int, -1);
+ ATTRIB(ListBox, focusedItemAlpha, float, 0.3);
METHOD(ListBox, setFocusedItem, void(entity, int));
- ATTRIB(ListBox, mouseMoveOffset, float, -1) // let know where the cursor is when the list scrolls without moving the cursor
- ATTRIB(ListBox, allowFocusSound, float, 1)
- ATTRIB(ListBox, selectedItem, int, 0)
- ATTRIB(ListBox, size, vector, '0 0 0')
- ATTRIB(ListBox, origin, vector, '0 0 0')
- ATTRIB(ListBox, scrollPos, float, 0) // measured in window heights, fixed when needed
- ATTRIB(ListBox, scrollPosTarget, float, 0)
+ ATTRIB(ListBox, mouseMoveOffset, float, -1); // let know where the cursor is when the list scrolls without moving the cursor
+ ATTRIB(ListBox, allowFocusSound, float, 1);
+ ATTRIB(ListBox, selectedItem, int, 0);
+ ATTRIB(ListBox, size, vector, '0 0 0');
+ ATTRIB(ListBox, origin, vector, '0 0 0');
+ ATTRIB(ListBox, scrollPos, float, 0); // measured in window heights, fixed when needed
+ ATTRIB(ListBox, scrollPosTarget, float, 0);
METHOD(ListBox, isScrolling, bool(entity));
- ATTRIB(ListBox, needScrollToItem, float, -1)
+ ATTRIB(ListBox, needScrollToItem, float, -1);
METHOD(ListBox, scrollToItem, void(entity, int));
- ATTRIB(ListBox, previousValue, float, 0)
- ATTRIB(ListBox, pressed, float, 0) // 0 = normal, 1 = scrollbar dragging, 2 = item dragging, 3 = released
- ATTRIB(ListBox, pressOffset, float, 0)
+ ATTRIB(ListBox, previousValue, float, 0);
+ ATTRIB(ListBox, pressed, float, 0); // 0 = normal, 1 = scrollbar dragging, 2 = item dragging, 3 = released
+ ATTRIB(ListBox, pressOffset, float, 0);
METHOD(ListBox, updateControlTopBottom, void(entity));
- ATTRIB(ListBox, controlTop, float, 0)
- ATTRIB(ListBox, controlBottom, float, 0)
- ATTRIB(ListBox, controlWidth, float, 0)
- ATTRIB(ListBox, dragScrollPos, vector, '0 0 0')
- ATTRIB(ListBox, selectionDoesntMatter, bool, false) // improves scrolling by keys for lists that don't need to show an active selection
+ ATTRIB(ListBox, controlTop, float, 0);
+ ATTRIB(ListBox, controlBottom, float, 0);
+ ATTRIB(ListBox, controlWidth, float, 0);
+ ATTRIB(ListBox, dragScrollPos, vector, '0 0 0');
+ ATTRIB(ListBox, selectionDoesntMatter, bool, false); // improves scrolling by keys for lists that don't need to show an active selection
- ATTRIB(ListBox, src, string, string_null) // scrollbar
- ATTRIB(ListBox, color, vector, '1 1 1')
- ATTRIB(ListBox, color2, vector, '1 1 1')
- ATTRIB(ListBox, colorC, vector, '1 1 1')
- ATTRIB(ListBox, colorF, vector, '1 1 1')
- ATTRIB(ListBox, tolerance, vector, '0 0 0') // drag tolerance
- ATTRIB(ListBox, scrollbarWidth, float, 0) // pixels
- ATTRIB(ListBox, nItems, float, 42) // FIXME: why?!?
- ATTRIB(ListBox, itemHeight, float, 0)
- ATTRIB(ListBox, itemAbsSize, vector, '0 0 0')
- ATTRIB(ListBox, colorBG, vector, '0 0 0')
- ATTRIB(ListBox, alphaBG, float, 0)
+ ATTRIB(ListBox, src, string); // scrollbar
+ ATTRIB(ListBox, color, vector, '1 1 1');
+ ATTRIB(ListBox, color2, vector, '1 1 1');
+ ATTRIB(ListBox, colorC, vector, '1 1 1');
+ ATTRIB(ListBox, colorF, vector, '1 1 1');
+ ATTRIB(ListBox, tolerance, vector, '0 0 0'); // drag tolerance
+ ATTRIB(ListBox, scrollbarWidth, float, 0); // pixels
+ ATTRIB(ListBox, nItems, float, 42); // FIXME: why?!?
+ ATTRIB(ListBox, itemHeight, float, 0);
+ ATTRIB(ListBox, itemAbsSize, vector, '0 0 0');
+ ATTRIB(ListBox, colorBG, vector, '0 0 0');
+ ATTRIB(ListBox, alphaBG, float, 0);
- ATTRIB(ListBox, lastClickedItem, float, -1)
- ATTRIB(ListBox, lastClickedTime, float, 0)
+ ATTRIB(ListBox, lastClickedItem, float, -1);
+ ATTRIB(ListBox, lastClickedTime, float, 0);
METHOD(ListBox, drawListBoxItem, void(entity, int, vector, bool, bool)); // item number, width/height, isSelected, isFocused
METHOD(ListBox, clickListBoxItem, void(entity, float, vector)); // item number, relative clickpos
METHOD(ModalController, initializeDialog, void(entity, entity));
METHOD(ModalController, switchState, void(entity, entity, float, float));
- ATTRIB(ModalController, origin, vector, '0 0 0')
- ATTRIB(ModalController, size, vector, '0 0 0')
- ATTRIB(ModalController, previousButton, entity, NULL)
- ATTRIB(ModalController, fadedAlpha, float, 0.3)
+ ATTRIB(ModalController, origin, vector, '0 0 0');
+ ATTRIB(ModalController, size, vector, '0 0 0');
+ ATTRIB(ModalController, previousButton, entity);
+ ATTRIB(ModalController, fadedAlpha, float, 0.3);
ENDCLASS(ModalController)
.float ModalController_state;
METHOD(Nexposee, focusEnter, void(entity));
METHOD(Nexposee, close, void(entity));
- ATTRIB(Nexposee, animationState, float, -1)
- ATTRIB(Nexposee, animationFactor, float, 0)
- ATTRIB(Nexposee, selectedChild, entity, NULL)
- ATTRIB(Nexposee, mouseFocusedChild, entity, NULL)
+ ATTRIB(Nexposee, animationState, float, -1);
+ ATTRIB(Nexposee, animationFactor, float, 0);
+ ATTRIB(Nexposee, selectedChild, entity);
+ ATTRIB(Nexposee, mouseFocusedChild, entity);
METHOD(Nexposee, addItem, void(entity, entity, vector, vector, float));
METHOD(Nexposee, calc, void(entity));
METHOD(Nexposee, setNexposee, void(entity, entity, vector, float, float));
- ATTRIB(Nexposee, mousePosition, vector, '0 0 0')
+ ATTRIB(Nexposee, mousePosition, vector, '0 0 0');
METHOD(Nexposee, pullNexposee, void(entity, entity, vector));
ENDCLASS(Nexposee)
void RadioButton_Click(entity me, entity other);
CLASS(RadioButton, CheckBox)
METHOD(RadioButton, configureRadioButton, void(entity, string, float, string, float, float));
- ATTRIB(RadioButton, checked, float, 0)
- ATTRIB(RadioButton, group, float, 0)
- ATTRIB(RadioButton, allowDeselect, float, 0)
- ATTRIB(RadioButton, onClick, void(entity, entity), RadioButton_Click)
+ ATTRIB(RadioButton, checked, float, 0);
+ ATTRIB(RadioButton, group, float, 0);
+ ATTRIB(RadioButton, allowDeselect, float, 0);
+ ATTRIB(RadioButton, onClick, void(entity, entity), RadioButton_Click);
ENDCLASS(RadioButton)
METHOD(Slider, setValue, void(entity, float));
METHOD(Slider, setSliderValue, void(entity, float));
METHOD(Slider, showNotify, void(entity));
- ATTRIB(Slider, src, string, string_null)
- ATTRIB(Slider, focusable, float, 1)
- ATTRIB(Slider, allowFocusSound, float, 1)
- ATTRIB(Slider, value, float, 0)
- ATTRIB(Slider, animated, float, 1)
- ATTRIB(Slider, sliderValue, float, 0)
- ATTRIB(Slider, sliderAnim, entity, NULL)
- ATTRIB(Slider, valueMin, float, 0)
- ATTRIB(Slider, valueMax, float, 0)
- ATTRIB(Slider, valueStep, float, 0)
- ATTRIB(Slider, valueDigits, float, 0)
- ATTRIB(Slider, valueKeyStep, float, 0)
- ATTRIB(Slider, valuePageStep, float, 0)
- ATTRIB(Slider, valueDisplayMultiplier, float, 1.0)
- ATTRIB(Slider, textSpace, float, 0)
- ATTRIB(Slider, controlWidth, float, 0)
- ATTRIB(Slider, pressed, float, 0)
- ATTRIB(Slider, pressOffset, float, 0)
- ATTRIB(Slider, previousValue, float, 0)
- ATTRIB(Slider, tolerance, vector, '0 0 0')
- ATTRIB(Slider, disabled, float, 0)
- ATTRIB(Slider, color, vector, '1 1 1')
- ATTRIB(Slider, color2, vector, '1 1 1')
- ATTRIB(Slider, colorD, vector, '1 1 1')
- ATTRIB(Slider, colorC, vector, '1 1 1')
- ATTRIB(Slider, colorF, vector, '1 1 1')
- ATTRIB(Slider, disabledAlpha, float, 0.3)
+ ATTRIB(Slider, src, string);
+ ATTRIB(Slider, focusable, float, 1);
+ ATTRIB(Slider, allowFocusSound, float, 1);
+ ATTRIB(Slider, value, float, 0);
+ ATTRIB(Slider, animated, float, 1);
+ ATTRIB(Slider, sliderValue, float, 0);
+ ATTRIB(Slider, sliderAnim, entity);
+ ATTRIB(Slider, valueMin, float, 0);
+ ATTRIB(Slider, valueMax, float, 0);
+ ATTRIB(Slider, valueStep, float, 0);
+ ATTRIB(Slider, valueDigits, float, 0);
+ ATTRIB(Slider, valueKeyStep, float, 0);
+ ATTRIB(Slider, valuePageStep, float, 0);
+ ATTRIB(Slider, valueDisplayMultiplier, float, 1.0);
+ ATTRIB(Slider, textSpace, float, 0);
+ ATTRIB(Slider, controlWidth, float, 0);
+ ATTRIB(Slider, pressed, float, 0);
+ ATTRIB(Slider, pressOffset, float, 0);
+ ATTRIB(Slider, previousValue, float, 0);
+ ATTRIB(Slider, tolerance, vector, '0 0 0');
+ ATTRIB(Slider, disabled, float, 0);
+ ATTRIB(Slider, color, vector, '1 1 1');
+ ATTRIB(Slider, color2, vector, '1 1 1');
+ ATTRIB(Slider, colorD, vector, '1 1 1');
+ ATTRIB(Slider, colorC, vector, '1 1 1');
+ ATTRIB(Slider, colorF, vector, '1 1 1');
+ ATTRIB(Slider, disabledAlpha, float, 0.3);
ENDCLASS(Slider)
#include "dialog.qh"
CLASS(Tab, Dialog)
- ATTRIB(Tab, isTabRoot, float, 0)
- ATTRIB(Tab, closable, float, 0)
- ATTRIB(Tab, rootDialog, float, 0)
- ATTRIB(Tab, title, string, string_null)
- ATTRIB(Tab, titleFontSize, float, 0) // pixels
+ ATTRIB(Tab, isTabRoot, float, 0);
+ ATTRIB(Tab, closable, float, 0);
+ ATTRIB(Tab, rootDialog, float, 0);
+ ATTRIB(Tab, title, string);
+ ATTRIB(Tab, titleFontSize, float, 0); // pixels
// still to be customized
- ATTRIB(Tab, intendedWidth, float, 0)
- ATTRIB(Tab, rows, float, 3)
- ATTRIB(Tab, columns, float, 2)
+ ATTRIB(Tab, intendedWidth, float, 0);
+ ATTRIB(Tab, rows, float, 3);
+ ATTRIB(Tab, columns, float, 2);
- ATTRIB(Tab, marginTop, float, 0) // pixels
- ATTRIB(Tab, marginBottom, float, 0) // pixels
- ATTRIB(Tab, marginLeft, float, 0) // pixels
- ATTRIB(Tab, marginRight, float, 0) // pixels
- ATTRIB(Tab, columnSpacing, float, 0) // pixels
- ATTRIB(Tab, rowSpacing, float, 0) // pixels
- ATTRIB(Tab, rowHeight, float, 0) // pixels
- ATTRIB(Tab, titleHeight, float, 0) // pixels
+ ATTRIB(Tab, marginTop, float, 0); // pixels
+ ATTRIB(Tab, marginBottom, float, 0); // pixels
+ ATTRIB(Tab, marginLeft, float, 0); // pixels
+ ATTRIB(Tab, marginRight, float, 0); // pixels
+ ATTRIB(Tab, columnSpacing, float, 0); // pixels
+ ATTRIB(Tab, rowSpacing, float, 0); // pixels
+ ATTRIB(Tab, rowHeight, float, 0); // pixels
+ ATTRIB(Tab, titleHeight, float, 0); // pixels
- ATTRIB(Tab, backgroundImage, string, string_null)
+ ATTRIB(Tab, backgroundImage, string);
ENDCLASS(Tab)
METHOD(TextSlider, addValue, void(entity, string, string));
METHOD(TextSlider, insertValue, void(entity, float, string, string));
METHOD(TextSlider, configureTextSliderValues, void(entity, string));
- ATTRIBARRAY(TextSlider, valueStrings, string, 256)
- ATTRIBARRAY(TextSlider, valueIdentifiers, string, 256)
- ATTRIB(TextSlider, nValues, int, 0)
+ ATTRIBARRAY(TextSlider, valueStrings, string, 256);
+ ATTRIBARRAY(TextSlider, valueIdentifiers, string, 256);
+ ATTRIB(TextSlider, nValues, int, 0);
ENDCLASS(TextSlider)
+#include "matrix.qh"
+
var void MX_Handle(int buf, string ancestor)
{
string type = json_get(buf, strcat(ancestor, ".type"));
--- /dev/null
+#pragma once
if (mouseButtonsPressed < 0)
{
mouseButtonsPressed = 0;
- LOG_TRACE("Warning: released an already released button\n");
+ LOG_TRACE("Warning: released an already released button");
}
}
if (key == K_ALT) menuShiftState &= ~S_ALT;
if (mouseButtonsPressed > 10)
{
mouseButtonsPressed = 10;
- LOG_TRACE("Warning: pressed an already pressed button\n");
+ LOG_TRACE("Warning: pressed an already pressed button");
}
}
if (key == K_ALT) menuShiftState |= S_ALT;
//#define SKINSTRING(name,def) case #name: break
#define SKINSTRING(name,def) case #name: SKIN##name = strzone(_value); break
// I know this leaks memory when skin is read multiple times. Screw it.
-#define SKINEND case "": break; case "//": break; default: LOG_TRACE("Invalid key in skin file: ", key, "\n"); } }
+#define SKINEND case "": break; case "//": break; default: LOG_TRACE("Invalid key in skin file: ", key); } }
#include "skin-customizables.inc"
#undef SKINEND
#undef SKINSTRING
#include "button.qh"
CLASS(XonoticBigButton, XonoticButton)
METHOD(XonoticBigButton, configureXonoticBigButton, void(entity, string, vector));
- ATTRIB(XonoticBigButton, image, string, SKINGFX_BUTTON_BIG)
- ATTRIB(XonoticBigButton, grayImage, string, SKINGFX_BUTTON_BIG_GRAY)
+ ATTRIB(XonoticBigButton, image, string, SKINGFX_BUTTON_BIG);
+ ATTRIB(XonoticBigButton, grayImage, string, SKINGFX_BUTTON_BIG_GRAY);
ENDCLASS(XonoticBigButton)
entity makeXonoticBigButton(string theText, vector theColor);
#include "commandbutton.qh"
CLASS(XonoticBigCommandButton, XonoticCommandButton)
METHOD(XonoticBigCommandButton, configureXonoticBigCommandButton, void(entity, string, vector, string, float, string));
- ATTRIB(XonoticBigCommandButton, image, string, SKINGFX_BUTTON_BIG)
- ATTRIB(XonoticBigCommandButton, grayImage, string, SKINGFX_BUTTON_BIG_GRAY)
+ ATTRIB(XonoticBigCommandButton, image, string, SKINGFX_BUTTON_BIG);
+ ATTRIB(XonoticBigCommandButton, grayImage, string, SKINGFX_BUTTON_BIG_GRAY);
ENDCLASS(XonoticBigCommandButton)
entity makeXonoticBigCommandButton_T(string theText, vector theColor, string theCommand, float closesMenu, string theTooltip);
entity makeXonoticBigCommandButton(string theText, vector theColor, string theCommand, float closesMenu);
#include "../item/button.qh"
CLASS(XonoticButton, Button)
METHOD(XonoticButton, configureXonoticButton, void(entity, string, vector, string));
- ATTRIB(XonoticButton, fontSize, float, SKINFONTSIZE_NORMAL)
- ATTRIB(XonoticButton, image, string, SKINGFX_BUTTON)
- ATTRIB(XonoticButton, grayImage, string, SKINGFX_BUTTON_GRAY)
- ATTRIB(XonoticButton, color, vector, SKINCOLOR_BUTTON_N)
- ATTRIB(XonoticButton, colorC, vector, SKINCOLOR_BUTTON_C)
- ATTRIB(XonoticButton, colorF, vector, SKINCOLOR_BUTTON_F)
- ATTRIB(XonoticButton, colorD, vector, SKINCOLOR_BUTTON_D)
- ATTRIB(XonoticButton, alpha, float, SKINALPHA_TEXT)
- ATTRIB(XonoticButton, disabledAlpha, float, SKINALPHA_DISABLED)
- ATTRIB(XonoticButton, marginLeft, float, SKINMARGIN_BUTTON) // chars
- ATTRIB(XonoticButton, marginRight, float, SKINMARGIN_BUTTON) // chars
+ ATTRIB(XonoticButton, fontSize, float, SKINFONTSIZE_NORMAL);
+ ATTRIB(XonoticButton, image, string, SKINGFX_BUTTON);
+ ATTRIB(XonoticButton, grayImage, string, SKINGFX_BUTTON_GRAY);
+ ATTRIB(XonoticButton, color, vector, SKINCOLOR_BUTTON_N);
+ ATTRIB(XonoticButton, colorC, vector, SKINCOLOR_BUTTON_C);
+ ATTRIB(XonoticButton, colorF, vector, SKINCOLOR_BUTTON_F);
+ ATTRIB(XonoticButton, colorD, vector, SKINCOLOR_BUTTON_D);
+ ATTRIB(XonoticButton, alpha, float, SKINALPHA_TEXT);
+ ATTRIB(XonoticButton, disabledAlpha, float, SKINALPHA_DISABLED);
+ ATTRIB(XonoticButton, marginLeft, float, SKINMARGIN_BUTTON); // chars
+ ATTRIB(XonoticButton, marginRight, float, SKINMARGIN_BUTTON); // chars
ENDCLASS(XonoticButton)
entity makeXonoticButton_T(string theText, vector theColor, string theTooltip);
#include "listbox.qh"
CLASS(XonoticCampaignList, XonoticListBox)
METHOD(XonoticCampaignList, configureXonoticCampaignList, void(entity));
- ATTRIB(XonoticCampaignList, rowsPerItem, float, 10)
+ ATTRIB(XonoticCampaignList, rowsPerItem, float, 10);
METHOD(XonoticCampaignList, draw, void(entity));
METHOD(XonoticCampaignList, drawListBoxItem, void(entity, int, vector, bool, bool));
METHOD(XonoticCampaignList, doubleClickListBoxItem, void(entity, float, vector));
METHOD(XonoticCampaignList, campaignGo, void(entity, float));
METHOD(XonoticCampaignList, destroy, void(entity));
- ATTRIB(XonoticCampaignList, campaignGlob, float, 0)
- ATTRIB(XonoticCampaignList, realFontSize, vector, '0 0 0')
- ATTRIB(XonoticCampaignList, columnPreviewOrigin, float, 0)
- ATTRIB(XonoticCampaignList, columnPreviewSize, float, 0)
- ATTRIB(XonoticCampaignList, columnNameOrigin, float, 0)
- ATTRIB(XonoticCampaignList, columnNameSize, float, 0)
- ATTRIB(XonoticCampaignList, columnCheckMarkOrigin, float, 0)
- ATTRIB(XonoticCampaignList, columnCheckMarkSize, float, 0)
- ATTRIB(XonoticCampaignList, checkMarkOrigin, vector, '0 0 0')
- ATTRIB(XonoticCampaignList, checkMarkSize, vector, '0 0 0')
- ATTRIB(XonoticCampaignList, realUpperMargin1, float, 0)
- ATTRIB(XonoticCampaignList, realUpperMargin2, float, 0)
+ ATTRIB(XonoticCampaignList, campaignGlob, float, 0);
+ ATTRIB(XonoticCampaignList, realFontSize, vector, '0 0 0');
+ ATTRIB(XonoticCampaignList, columnPreviewOrigin, float, 0);
+ ATTRIB(XonoticCampaignList, columnPreviewSize, float, 0);
+ ATTRIB(XonoticCampaignList, columnNameOrigin, float, 0);
+ ATTRIB(XonoticCampaignList, columnNameSize, float, 0);
+ ATTRIB(XonoticCampaignList, columnCheckMarkOrigin, float, 0);
+ ATTRIB(XonoticCampaignList, columnCheckMarkSize, float, 0);
+ ATTRIB(XonoticCampaignList, checkMarkOrigin, vector, '0 0 0');
+ ATTRIB(XonoticCampaignList, checkMarkSize, vector, '0 0 0');
+ ATTRIB(XonoticCampaignList, realUpperMargin1, float, 0);
+ ATTRIB(XonoticCampaignList, realUpperMargin2, float, 0);
- ATTRIB(XonoticCampaignList, origin, vector, '0 0 0')
- ATTRIB(XonoticCampaignList, itemAbsSize, vector, '0 0 0')
- ATTRIB(XonoticCampaignList, emptyLineHeight, float, 0.5)
+ ATTRIB(XonoticCampaignList, origin, vector, '0 0 0');
+ ATTRIB(XonoticCampaignList, itemAbsSize, vector, '0 0 0');
+ ATTRIB(XonoticCampaignList, emptyLineHeight, float, 0.5);
- ATTRIB(XonoticCampaignList, campaignIndex, float, 0)
- ATTRIB(XonoticCampaignList, cvarName, string, string_null)
+ ATTRIB(XonoticCampaignList, campaignIndex, float, 0);
+ ATTRIB(XonoticCampaignList, cvarName, string);
METHOD(XonoticCampaignList, loadCvars, void(entity));
METHOD(XonoticCampaignList, saveCvars, void(entity));
- ATTRIB(XonoticCampaignList, buttonNext, entity, NULL)
- ATTRIB(XonoticCampaignList, buttonPrev, entity, NULL)
- ATTRIB(XonoticCampaignList, labelTitle, entity, NULL)
+ ATTRIB(XonoticCampaignList, buttonNext, entity);
+ ATTRIB(XonoticCampaignList, buttonPrev, entity);
+ ATTRIB(XonoticCampaignList, labelTitle, entity);
ENDCLASS(XonoticCampaignList)
entity makeXonoticCampaignList();
void CampaignList_LoadMap(entity btn, entity me);
METHOD(XonoticCharmap, focusLeave, void(entity));
METHOD(XonoticCharmap, resizeNotify, void(entity, vector, vector, vector, vector));
METHOD(XonoticCharmap, keyDown, float(entity, float, float, float));
- ATTRIB(XonoticCharmap, inputBox, entity, NULL)
- ATTRIB(XonoticCharmap, realFontSize, vector, '0 0 0')
+ ATTRIB(XonoticCharmap, inputBox, entity);
+ ATTRIB(XonoticCharmap, realFontSize, vector, '0 0 0');
- ATTRIB(XonoticCharmap, rows, float, 10)
- ATTRIB(XonoticCharmap, columns, float, 14)
+ ATTRIB(XonoticCharmap, rows, float, 10);
+ ATTRIB(XonoticCharmap, columns, float, 14);
METHOD(XonoticCharmap, cellSelect, void(entity, vector));
METHOD(XonoticCharmap, cellIsValid, bool(entity, vector));
METHOD(XonoticCharmap, cellDraw, void(entity, vector, vector));
- ATTRIB(XonoticCharmap, charOffset, vector, '0 0 0')
+ ATTRIB(XonoticCharmap, charOffset, vector, '0 0 0');
ENDCLASS(XonoticCharmap)
entity makeXonoticCharmap(entity controlledInputBox);
CLASS(XonoticCheckBox, CheckBox)
METHOD(XonoticCheckBox, configureXonoticCheckBox, void(entity, float, float, string, string, string));
METHOD(XonoticCheckBox, setChecked, void(entity, float));
- ATTRIB(XonoticCheckBox, fontSize, float, SKINFONTSIZE_NORMAL)
- ATTRIB(XonoticCheckBox, image, string, SKINGFX_CHECKBOX)
- ATTRIB(XonoticCheckBox, yesValue, float, 1)
- ATTRIB(XonoticCheckBox, noValue, float, 0)
+ ATTRIB(XonoticCheckBox, fontSize, float, SKINFONTSIZE_NORMAL);
+ ATTRIB(XonoticCheckBox, image, string, SKINGFX_CHECKBOX);
+ ATTRIB(XonoticCheckBox, yesValue, float, 1);
+ ATTRIB(XonoticCheckBox, noValue, float, 0);
- ATTRIB(XonoticCheckBox, color, vector, SKINCOLOR_CHECKBOX_N)
- ATTRIB(XonoticCheckBox, colorC, vector, SKINCOLOR_CHECKBOX_C)
- ATTRIB(XonoticCheckBox, colorF, vector, SKINCOLOR_CHECKBOX_F)
- ATTRIB(XonoticCheckBox, colorD, vector, SKINCOLOR_CHECKBOX_D)
+ ATTRIB(XonoticCheckBox, color, vector, SKINCOLOR_CHECKBOX_N);
+ ATTRIB(XonoticCheckBox, colorC, vector, SKINCOLOR_CHECKBOX_C);
+ ATTRIB(XonoticCheckBox, colorF, vector, SKINCOLOR_CHECKBOX_F);
+ ATTRIB(XonoticCheckBox, colorD, vector, SKINCOLOR_CHECKBOX_D);
- ATTRIB(XonoticCheckBox, cvarName, string, string_null)
+ ATTRIB(XonoticCheckBox, cvarName, string);
METHOD(XonoticCheckBox, loadCvars, void(entity));
METHOD(XonoticCheckBox, saveCvars, void(entity));
- ATTRIB(XonoticCheckBox, sendCvars, float, 0)
+ ATTRIB(XonoticCheckBox, sendCvars, float, 0);
- ATTRIB(XonoticCheckBox, alpha, float, SKINALPHA_TEXT)
- ATTRIB(XonoticCheckBox, disabledAlpha, float, SKINALPHA_DISABLED)
- ATTRIB(XonoticCheckBox, linkedCheckBox, entity, NULL)
+ ATTRIB(XonoticCheckBox, alpha, float, SKINALPHA_TEXT);
+ ATTRIB(XonoticCheckBox, disabledAlpha, float, SKINALPHA_DISABLED);
+ ATTRIB(XonoticCheckBox, linkedCheckBox, entity);
ENDCLASS(XonoticCheckBox)
entity makeXonoticCheckBox_T(float, string, string, string);
entity makeXonoticCheckBox(float, string, string);
METHOD(XonoticSliderCheckBox, configureXonoticSliderCheckBox, void(entity, float, float, entity, string));
METHOD(XonoticSliderCheckBox, setChecked, void(entity, float));
METHOD(XonoticSliderCheckBox, draw, void(entity));
- ATTRIB(XonoticSliderCheckBox, fontSize, float, SKINFONTSIZE_NORMAL)
- ATTRIB(XonoticSliderCheckBox, image, string, SKINGFX_CHECKBOX)
+ ATTRIB(XonoticSliderCheckBox, fontSize, float, SKINFONTSIZE_NORMAL);
+ ATTRIB(XonoticSliderCheckBox, image, string, SKINGFX_CHECKBOX);
- ATTRIB(XonoticSliderCheckBox, color, vector, SKINCOLOR_CHECKBOX_N)
- ATTRIB(XonoticSliderCheckBox, colorC, vector, SKINCOLOR_CHECKBOX_C)
- ATTRIB(XonoticSliderCheckBox, colorF, vector, SKINCOLOR_CHECKBOX_F)
- ATTRIB(XonoticSliderCheckBox, colorD, vector, SKINCOLOR_CHECKBOX_D)
+ ATTRIB(XonoticSliderCheckBox, color, vector, SKINCOLOR_CHECKBOX_N);
+ ATTRIB(XonoticSliderCheckBox, colorC, vector, SKINCOLOR_CHECKBOX_C);
+ ATTRIB(XonoticSliderCheckBox, colorF, vector, SKINCOLOR_CHECKBOX_F);
+ ATTRIB(XonoticSliderCheckBox, colorD, vector, SKINCOLOR_CHECKBOX_D);
- ATTRIB(XonoticSliderCheckBox, alpha, float, SKINALPHA_TEXT)
- ATTRIB(XonoticSliderCheckBox, disabledAlpha, float, SKINALPHA_DISABLED)
+ ATTRIB(XonoticSliderCheckBox, alpha, float, SKINALPHA_TEXT);
+ ATTRIB(XonoticSliderCheckBox, disabledAlpha, float, SKINALPHA_DISABLED);
- ATTRIB(XonoticSliderCheckBox, controlledSlider, entity, NULL)
- ATTRIB(XonoticSliderCheckBox, offValue, float, -1)
- ATTRIB(XonoticSliderCheckBox, inverted, float, 0)
- ATTRIB(XonoticSliderCheckBox, savedValue, float, -1)
+ ATTRIB(XonoticSliderCheckBox, controlledSlider, entity);
+ ATTRIB(XonoticSliderCheckBox, offValue, float, -1);
+ ATTRIB(XonoticSliderCheckBox, inverted, float, 0);
+ ATTRIB(XonoticSliderCheckBox, savedValue, float, -1);
ENDCLASS(XonoticSliderCheckBox)
entity makeXonoticSliderCheckBox(float, float, entity, string);
CLASS(XonoticCheckBoxString, CheckBox)
METHOD(XonoticCheckBoxString, configureXonoticCheckBoxString, void(entity, string, string, string, string));
METHOD(XonoticCheckBoxString, setChecked, void(entity, float));
- ATTRIB(XonoticCheckBoxString, fontSize, float, SKINFONTSIZE_NORMAL)
- ATTRIB(XonoticCheckBoxString, image, string, SKINGFX_CHECKBOX)
- ATTRIB(XonoticCheckBoxString, yesString, string, string_null)
- ATTRIB(XonoticCheckBoxString, noString, string, string_null)
+ ATTRIB(XonoticCheckBoxString, fontSize, float, SKINFONTSIZE_NORMAL);
+ ATTRIB(XonoticCheckBoxString, image, string, SKINGFX_CHECKBOX);
+ ATTRIB(XonoticCheckBoxString, yesString, string);
+ ATTRIB(XonoticCheckBoxString, noString, string);
- ATTRIB(XonoticCheckBoxString, color, vector, SKINCOLOR_CHECKBOX_N)
- ATTRIB(XonoticCheckBoxString, colorC, vector, SKINCOLOR_CHECKBOX_C)
- ATTRIB(XonoticCheckBoxString, colorF, vector, SKINCOLOR_CHECKBOX_F)
- ATTRIB(XonoticCheckBoxString, colorD, vector, SKINCOLOR_CHECKBOX_D)
+ ATTRIB(XonoticCheckBoxString, color, vector, SKINCOLOR_CHECKBOX_N);
+ ATTRIB(XonoticCheckBoxString, colorC, vector, SKINCOLOR_CHECKBOX_C);
+ ATTRIB(XonoticCheckBoxString, colorF, vector, SKINCOLOR_CHECKBOX_F);
+ ATTRIB(XonoticCheckBoxString, colorD, vector, SKINCOLOR_CHECKBOX_D);
- ATTRIB(XonoticCheckBoxString, cvarName, string, string_null)
+ ATTRIB(XonoticCheckBoxString, cvarName, string);
METHOD(XonoticCheckBoxString, loadCvars, void(entity));
METHOD(XonoticCheckBoxString, saveCvars, void(entity));
- ATTRIB(XonoticCheckBoxString, sendCvars, float, 0)
+ ATTRIB(XonoticCheckBoxString, sendCvars, float, 0);
- ATTRIB(XonoticCheckBoxString, alpha, float, SKINALPHA_TEXT)
- ATTRIB(XonoticCheckBoxString, disabledAlpha, float, SKINALPHA_DISABLED)
+ ATTRIB(XonoticCheckBoxString, alpha, float, SKINALPHA_TEXT);
+ ATTRIB(XonoticCheckBoxString, disabledAlpha, float, SKINALPHA_DISABLED);
ENDCLASS(XonoticCheckBoxString)
entity makeXonoticCheckBoxString(string, string, string, string);
METHOD(XonoticColorButton, configureXonoticColorButton, void(entity, float, float, float));
METHOD(XonoticColorButton, setChecked, void(entity, float));
METHOD(XonoticColorButton, draw, void(entity));
- ATTRIB(XonoticColorButton, fontSize, float, 0)
- ATTRIB(XonoticColorButton, image, string, SKINGFX_COLORBUTTON)
+ ATTRIB(XonoticColorButton, fontSize, float, 0);
+ ATTRIB(XonoticColorButton, image, string, SKINGFX_COLORBUTTON);
- ATTRIB(XonoticColorButton, useDownAsChecked, float, 1)
+ ATTRIB(XonoticColorButton, useDownAsChecked, float, 1);
- ATTRIB(XonoticColorButton, cvarPart, float, 0)
- ATTRIB(XonoticColorButton, cvarName, string, string_null)
- ATTRIB(XonoticColorButton, cvarValueFloat, float, 0)
+ ATTRIB(XonoticColorButton, cvarPart, float, 0);
+ ATTRIB(XonoticColorButton, cvarName, string);
+ ATTRIB(XonoticColorButton, cvarValueFloat, float, 0);
METHOD(XonoticColorButton, loadCvars, void(entity));
METHOD(XonoticColorButton, saveCvars, void(entity));
ENDCLASS(XonoticColorButton)
METHOD(XonoticColorpicker, mousePress, float(entity, vector));
METHOD(XonoticColorpicker, mouseRelease, float(entity, vector));
METHOD(XonoticColorpicker, mouseDrag, float(entity, vector));
- ATTRIB(XonoticColorpicker, controlledTextbox, entity, NULL)
- ATTRIB(XonoticColorpicker, image, string, SKINGFX_COLORPICKER)
- ATTRIB(XonoticColorpicker, imagemargin, vector, SKINMARGIN_COLORPICKER)
- ATTRIB(XonoticColorpicker, focusable, float, 1)
+ ATTRIB(XonoticColorpicker, controlledTextbox, entity);
+ ATTRIB(XonoticColorpicker, image, string, SKINGFX_COLORPICKER);
+ ATTRIB(XonoticColorpicker, imagemargin, vector, SKINMARGIN_COLORPICKER);
+ ATTRIB(XonoticColorpicker, focusable, float, 1);
METHOD(XonoticColorpicker, focusLeave, void(entity));
METHOD(XonoticColorpicker, keyDown, float(entity, float, float, float));
METHOD(XonoticColorpicker, draw, void(entity));
METHOD(XonoticColorpickerString, mouseRelease, float(entity, vector));
METHOD(XonoticColorpickerString, mouseDrag, float(entity, vector));
- ATTRIB(XonoticColorpickerString, cvarName, string, string_null)
+ ATTRIB(XonoticColorpickerString, cvarName, string);
METHOD(XonoticColorpickerString, loadCvars, void(entity));
METHOD(XonoticColorpickerString, saveCvars, void(entity));
- ATTRIB(XonoticColorpickerString, prevcoords, vector, '0 0 0')
- ATTRIB(XonoticColorpickerString, image, string, SKINGFX_COLORPICKER)
- ATTRIB(XonoticColorpickerString, imagemargin, vector, SKINMARGIN_COLORPICKER)
- ATTRIB(XonoticColorpickerString, focusable, float, 1)
+ ATTRIB(XonoticColorpickerString, prevcoords, vector, '0 0 0');
+ ATTRIB(XonoticColorpickerString, image, string, SKINGFX_COLORPICKER);
+ ATTRIB(XonoticColorpickerString, imagemargin, vector, SKINMARGIN_COLORPICKER);
+ ATTRIB(XonoticColorpickerString, focusable, float, 1);
METHOD(XonoticColorpickerString, draw, void(entity));
- ATTRIB(XonoticColorpickerString, disabledAlpha, float, 0.3)
+ ATTRIB(XonoticColorpickerString, disabledAlpha, float, 0.3);
ENDCLASS(XonoticColorpickerString)
entity makeXonoticColorpickerString(string theCvar, string theDefaultCvar);
#include "button.qh"
CLASS(XonoticCommandButton, XonoticButton)
METHOD(XonoticCommandButton, configureXonoticCommandButton, void(entity, string, vector, string, float, string));
- ATTRIB(XonoticCommandButton, onClickCommand, string, string_null)
- ATTRIB(XonoticCommandButton, flags, float, 0)
+ ATTRIB(XonoticCommandButton, onClickCommand, string);
+ ATTRIB(XonoticCommandButton, flags, float, 0);
ENDCLASS(XonoticCommandButton)
entity makeXonoticCommandButton_T(string theText, vector theColor, string theCommand, float closesMenu, string theTooltip);
#include "listbox.qh"
CLASS(XonoticCreditsList, XonoticListBox)
METHOD(XonoticCreditsList, configureXonoticCreditsList, void(entity));
- ATTRIB(XonoticCreditsList, rowsPerItem, float, 1)
+ ATTRIB(XonoticCreditsList, rowsPerItem, float, 1);
METHOD(XonoticCreditsList, draw, void(entity));
METHOD(XonoticCreditsList, drawListBoxItem, void(entity, int, vector, bool, bool));
METHOD(XonoticCreditsList, resizeNotify, void(entity, vector, vector, vector, vector));
METHOD(XonoticCreditsList, keyDown, float(entity, float, float, float));
METHOD(XonoticCreditsList, destroy, void(entity));
- ATTRIB(XonoticCreditsList, selectionDoesntMatter, bool, true)
+ ATTRIB(XonoticCreditsList, selectionDoesntMatter, bool, true);
- ATTRIB(XonoticCreditsList, realFontSize, vector, '0 0 0')
- ATTRIB(XonoticCreditsList, realUpperMargin, float, 0)
- ATTRIB(XonoticCreditsList, bufferIndex, float, 0)
- ATTRIB(XonoticCreditsList, scrolling, float, 0)
+ ATTRIB(XonoticCreditsList, realFontSize, vector, '0 0 0');
+ ATTRIB(XonoticCreditsList, realUpperMargin, float, 0);
+ ATTRIB(XonoticCreditsList, bufferIndex, float, 0);
+ ATTRIB(XonoticCreditsList, scrolling, float, 0);
- ATTRIB(XonoticCreditsList, alphaBG, float, 0)
+ ATTRIB(XonoticCreditsList, alphaBG, float, 0);
ENDCLASS(XonoticCreditsList)
entity makeXonoticCreditsList();
CLASS(XonoticCrosshairPicker, XonoticPicker)
METHOD(XonoticCrosshairPicker, configureXonoticCrosshairPicker, void(entity));
- ATTRIB(XonoticCrosshairPicker, rows, float, 3)
- ATTRIB(XonoticCrosshairPicker, columns, float, 12)
+ ATTRIB(XonoticCrosshairPicker, rows, float, 3);
+ ATTRIB(XonoticCrosshairPicker, columns, float, 12);
METHOD(XonoticCrosshairPicker, cellSelect, void(entity, vector));
METHOD(XonoticCrosshairPicker, cellIsValid, bool(entity, vector));
CLASS(XonoticCrosshairPreview, Item)
METHOD(XonoticCrosshairPreview, configureXonoticCrosshairPreview, void(entity));
METHOD(XonoticCrosshairPreview, draw, void(entity));
- ATTRIB(XonoticCrosshairPreview, src, string, string_null)
- ATTRIB(XonoticCrosshairPreview, src2, string, string_null)
- ATTRIB(XonoticCrosshairPreview, disabled, float, 0)
- ATTRIB(XonoticCrosshairPreview, disabledAlpha, float, SKINALPHA_DISABLED)
+ ATTRIB(XonoticCrosshairPreview, src, string);
+ ATTRIB(XonoticCrosshairPreview, src2, string);
+ ATTRIB(XonoticCrosshairPreview, disabled, float, 0);
+ ATTRIB(XonoticCrosshairPreview, disabledAlpha, float, SKINALPHA_DISABLED);
ENDCLASS(XonoticCrosshairPreview)
entity makeXonoticCrosshairPreview();
#include "listbox.qh"
CLASS(XonoticCvarList, XonoticListBox)
METHOD(XonoticCvarList, configureXonoticCvarList, void(entity));
- ATTRIB(XonoticCvarList, rowsPerItem, float, 1)
+ ATTRIB(XonoticCvarList, rowsPerItem, float, 1);
METHOD(XonoticCvarList, drawListBoxItem, void(entity, int, vector, bool, bool));
METHOD(XonoticCvarList, resizeNotify, void(entity, vector, vector, vector, vector));
METHOD(XonoticCvarList, keyDown, float(entity, float, float, float));
METHOD(XonoticCvarList, destroy, void(entity));
- ATTRIB(XonoticCvarList, realFontSize, vector, '0 0 0')
- ATTRIB(XonoticCvarList, realUpperMargin, float, 0)
- ATTRIB(XonoticCvarList, columnNameOrigin, float, 0)
- ATTRIB(XonoticCvarList, columnNameSize, float, 0)
- ATTRIB(XonoticCvarList, columnValueOrigin, float, 0)
- ATTRIB(XonoticCvarList, columnValueSize, float, 0)
+ ATTRIB(XonoticCvarList, realFontSize, vector, '0 0 0');
+ ATTRIB(XonoticCvarList, realUpperMargin, float, 0);
+ ATTRIB(XonoticCvarList, columnNameOrigin, float, 0);
+ ATTRIB(XonoticCvarList, columnNameSize, float, 0);
+ ATTRIB(XonoticCvarList, columnValueOrigin, float, 0);
+ ATTRIB(XonoticCvarList, columnValueSize, float, 0);
METHOD(XonoticCvarList, mouseRelease, float(entity, vector));
METHOD(XonoticCvarList, setSelected, void(entity, float));
METHOD(XonoticCvarList, updateCvarType, float(entity));
- ATTRIB(XonoticCvarList, controlledTextbox, entity, NULL)
- ATTRIB(XonoticCvarList, cvarNameBox, entity, NULL)
- ATTRIB(XonoticCvarList, cvarDescriptionBox, entity, NULL)
- ATTRIB(XonoticCvarList, cvarTypeBox, entity, NULL)
- ATTRIB(XonoticCvarList, cvarValueBox, entity, NULL)
- ATTRIB(XonoticCvarList, cvarDefaultBox, entity, NULL)
- ATTRIB(XonoticCvarList, cvarNeedsForcing, float, 0)
+ ATTRIB(XonoticCvarList, controlledTextbox, entity);
+ ATTRIB(XonoticCvarList, cvarNameBox, entity);
+ ATTRIB(XonoticCvarList, cvarDescriptionBox, entity);
+ ATTRIB(XonoticCvarList, cvarTypeBox, entity);
+ ATTRIB(XonoticCvarList, cvarValueBox, entity);
+ ATTRIB(XonoticCvarList, cvarDefaultBox, entity);
+ ATTRIB(XonoticCvarList, cvarNeedsForcing, float, 0);
- ATTRIB(XonoticCvarList, handle, float, -1)
- ATTRIB(XonoticCvarList, cvarName, string, string_null)
- ATTRIB(XonoticCvarList, cvarDescription, string, string_null)
- ATTRIB(XonoticCvarList, cvarType, string, string_null)
- ATTRIB(XonoticCvarList, cvarDefault, string, string_null)
+ ATTRIB(XonoticCvarList, handle, float, -1);
+ ATTRIB(XonoticCvarList, cvarName, string);
+ ATTRIB(XonoticCvarList, cvarDescription, string);
+ ATTRIB(XonoticCvarList, cvarType, string);
+ ATTRIB(XonoticCvarList, cvarDefault, string);
ENDCLASS(XonoticCvarList)
entity makeXonoticCvarList();
void CvarList_Filter_Change(entity box, entity me);
CLASS(StringSource, DataSource)
- ATTRIB(StringSource, StringSource_str, string, string_null)
- ATTRIB(StringSource, StringSource_sep, string, string_null)
+ ATTRIB(StringSource, StringSource_str, string);
+ ATTRIB(StringSource, StringSource_sep, string);
CONSTRUCTOR(StringSource, string str, string sep);
METHOD(StringSource, getEntry, entity(entity this, int i, void(string name, string icon) returns));
METHOD(StringSource, reload, int(entity this, string filter));
ENDCLASS(StringSource)
CLASS(CvarStringSource, StringSource)
- ATTRIB(CvarStringSource, CvarStringSource_cvar, string, string_null)
+ ATTRIB(CvarStringSource, CvarStringSource_cvar, string);
CONSTRUCTOR(CvarStringSource, string cv, string sep);
METHOD(CvarStringSource, getEntry, entity(entity this, int i, void(string name, string icon) returns));
METHOD(CvarStringSource, reload, int(entity this, string filter));
#include "listbox.qh"
CLASS(XonoticDemoList, XonoticListBox)
METHOD(XonoticDemoList, configureXonoticDemoList, void(entity));
- ATTRIB(XonoticDemoList, rowsPerItem, float, 1)
+ ATTRIB(XonoticDemoList, rowsPerItem, float, 1);
METHOD(XonoticDemoList, resizeNotify, void(entity, vector, vector, vector, vector));
METHOD(XonoticDemoList, drawListBoxItem, void(entity, int, vector, bool, bool));
METHOD(XonoticDemoList, getDemos, void(entity));
METHOD(XonoticDemoList, destroy, void(entity));
METHOD(XonoticDemoList, showNotify, void(entity));
- ATTRIB(XonoticDemoList, listDemo, float, -1)
- ATTRIB(XonoticDemoList, realFontSize, vector, '0 0 0')
- ATTRIB(XonoticDemoList, columnNameOrigin, float, 0)
- ATTRIB(XonoticDemoList, columnNameSize, float, 0)
- ATTRIB(XonoticDemoList, realUpperMargin, float, 0)
- ATTRIB(XonoticDemoList, origin, vector, '0 0 0')
- ATTRIB(XonoticDemoList, itemAbsSize, vector, '0 0 0')
+ ATTRIB(XonoticDemoList, listDemo, float, -1);
+ ATTRIB(XonoticDemoList, realFontSize, vector, '0 0 0');
+ ATTRIB(XonoticDemoList, columnNameOrigin, float, 0);
+ ATTRIB(XonoticDemoList, columnNameSize, float, 0);
+ ATTRIB(XonoticDemoList, realUpperMargin, float, 0);
+ ATTRIB(XonoticDemoList, origin, vector, '0 0 0');
+ ATTRIB(XonoticDemoList, itemAbsSize, vector, '0 0 0');
- ATTRIB(XonoticDemoList, filterString, string, string_null)
+ ATTRIB(XonoticDemoList, filterString, string);
ENDCLASS(XonoticDemoList)
entity demolist; // for reference elsewhere
CLASS(XonoticDialog, Dialog)
// still to be customized by user
/*
- ATTRIB(XonoticDialog, closable, float, 1)
- ATTRIB(XonoticDialog, title, string, _("Form1")) // ;)
- ATTRIB(XonoticDialog, color, vector, '1 0.5 1')
- ATTRIB(XonoticDialog, intendedWidth, float, 0)
- ATTRIB(XonoticDialog, rows, float, 3)
- ATTRIB(XonoticDialog, columns, float, 2)
+ ATTRIB(XonoticDialog, closable, float, 1);
+ ATTRIB(XonoticDialog, title, string, _("Form1")); // ;);
+ ATTRIB(XonoticDialog, color, vector, '1 0.5 1');
+ ATTRIB(XonoticDialog, intendedWidth, float, 0);
+ ATTRIB(XonoticDialog, rows, float, 3);
+ ATTRIB(XonoticDialog, columns, float, 2);
*/
- ATTRIB(XonoticDialog, marginTop, float, SKINMARGIN_TOP) // pixels
- ATTRIB(XonoticDialog, marginBottom, float, SKINMARGIN_BOTTOM) // pixels
- ATTRIB(XonoticDialog, marginLeft, float, SKINMARGIN_LEFT) // pixels
- ATTRIB(XonoticDialog, marginRight, float, SKINMARGIN_RIGHT) // pixels
- ATTRIB(XonoticDialog, columnSpacing, float, SKINMARGIN_COLUMNS) // pixels
- ATTRIB(XonoticDialog, rowSpacing, float, SKINMARGIN_ROWS) // pixels
- ATTRIB(XonoticDialog, rowHeight, float, SKINFONTSIZE_NORMAL * SKINHEIGHT_NORMAL) // pixels
- ATTRIB(XonoticDialog, titleHeight, float, SKINFONTSIZE_TITLE * SKINHEIGHT_TITLE) // pixels
- ATTRIB(XonoticDialog, titleFontSize, float, SKINFONTSIZE_TITLE) // pixels
+ ATTRIB(XonoticDialog, marginTop, float, SKINMARGIN_TOP); // pixels
+ ATTRIB(XonoticDialog, marginBottom, float, SKINMARGIN_BOTTOM); // pixels
+ ATTRIB(XonoticDialog, marginLeft, float, SKINMARGIN_LEFT); // pixels
+ ATTRIB(XonoticDialog, marginRight, float, SKINMARGIN_RIGHT); // pixels
+ ATTRIB(XonoticDialog, columnSpacing, float, SKINMARGIN_COLUMNS); // pixels
+ ATTRIB(XonoticDialog, rowSpacing, float, SKINMARGIN_ROWS); // pixels
+ ATTRIB(XonoticDialog, rowHeight, float, SKINFONTSIZE_NORMAL * SKINHEIGHT_NORMAL); // pixels
+ ATTRIB(XonoticDialog, titleHeight, float, SKINFONTSIZE_TITLE * SKINHEIGHT_TITLE); // pixels
+ ATTRIB(XonoticDialog, titleFontSize, float, SKINFONTSIZE_TITLE); // pixels
- ATTRIB(XonoticDialog, backgroundImage, string, SKINGFX_DIALOGBORDER)
- ATTRIB(XonoticDialog, borderLines, float, SKINHEIGHT_DIALOGBORDER)
- ATTRIB(XonoticDialog, closeButtonImage, string, SKINGFX_CLOSEBUTTON)
- ATTRIB(XonoticDialog, zoomedOutTitleBarPosition, float, SKINHEIGHT_ZOOMEDTITLE * 0.5 - 0.5)
- ATTRIB(XonoticDialog, zoomedOutTitleBar, float, SKINHEIGHT_ZOOMEDTITLE != 0)
+ ATTRIB(XonoticDialog, backgroundImage, string, SKINGFX_DIALOGBORDER);
+ ATTRIB(XonoticDialog, borderLines, float, SKINHEIGHT_DIALOGBORDER);
+ ATTRIB(XonoticDialog, closeButtonImage, string, SKINGFX_CLOSEBUTTON);
+ ATTRIB(XonoticDialog, zoomedOutTitleBarPosition, float, SKINHEIGHT_ZOOMEDTITLE * 0.5 - 0.5);
+ ATTRIB(XonoticDialog, zoomedOutTitleBar, float, SKINHEIGHT_ZOOMEDTITLE != 0);
- ATTRIB(XonoticDialog, alpha, float, SKINALPHA_TEXT)
+ ATTRIB(XonoticDialog, alpha, float, SKINALPHA_TEXT);
METHOD(XonoticDialog, configureDialog, void(entity));
ENDCLASS(XonoticDialog)
CLASS(XonoticCreditsDialog, XonoticDialog)
METHOD(XonoticCreditsDialog, fill, void(entity));
METHOD(XonoticCreditsDialog, focusEnter, void(entity));
- ATTRIB(XonoticCreditsDialog, title, string, _("Credits"))
- ATTRIB(XonoticCreditsDialog, tooltip, string, _("The Xonotic credits"))
- ATTRIB(XonoticCreditsDialog, color, vector, SKINCOLOR_DIALOG_CREDITS)
- ATTRIB(XonoticCreditsDialog, intendedWidth, float, SKINWIDTH_CREDITS)
- ATTRIB(XonoticCreditsDialog, rows, float, SKINROWS_CREDITS)
- ATTRIB(XonoticCreditsDialog, columns, float, 2)
- ATTRIB(XonoticCreditsDialog, creditsList, entity, NULL)
+ ATTRIB(XonoticCreditsDialog, title, string, _("Credits"));
+ ATTRIB(XonoticCreditsDialog, tooltip, string, _("The Xonotic credits"));
+ ATTRIB(XonoticCreditsDialog, color, vector, SKINCOLOR_DIALOG_CREDITS);
+ ATTRIB(XonoticCreditsDialog, intendedWidth, float, SKINWIDTH_CREDITS);
+ ATTRIB(XonoticCreditsDialog, rows, float, SKINROWS_CREDITS);
+ ATTRIB(XonoticCreditsDialog, columns, float, 2);
+ ATTRIB(XonoticCreditsDialog, creditsList, entity);
ENDCLASS(XonoticCreditsDialog)
#include "rootdialog.qh"
CLASS(XonoticFirstRunDialog, XonoticRootDialog)
METHOD(XonoticFirstRunDialog, fill, void(entity));
- ATTRIB(XonoticFirstRunDialog, title, string, _("Welcome"))
- ATTRIB(XonoticFirstRunDialog, color, vector, SKINCOLOR_DIALOG_FIRSTRUN)
- ATTRIB(XonoticFirstRunDialog, intendedWidth, float, 0.7)
- ATTRIB(XonoticFirstRunDialog, rows, float, 16)
- ATTRIB(XonoticFirstRunDialog, columns, float, 6)
- ATTRIB(XonoticFirstRunDialog, name, string, "FirstRun")
- ATTRIB(XonoticFirstRunDialog, playerNameLabel, entity, NULL)
- ATTRIB(XonoticFirstRunDialog, playerNameLabelAlpha, float, 0)
+ ATTRIB(XonoticFirstRunDialog, title, string, _("Welcome"));
+ ATTRIB(XonoticFirstRunDialog, color, vector, SKINCOLOR_DIALOG_FIRSTRUN);
+ ATTRIB(XonoticFirstRunDialog, intendedWidth, float, 0.7);
+ ATTRIB(XonoticFirstRunDialog, rows, float, 16);
+ ATTRIB(XonoticFirstRunDialog, columns, float, 6);
+ ATTRIB(XonoticFirstRunDialog, name, string, "FirstRun");
+ ATTRIB(XonoticFirstRunDialog, playerNameLabel, entity);
+ ATTRIB(XonoticFirstRunDialog, playerNameLabelAlpha, float, 0);
- ATTRIB(XonoticFirstRunDialog, closable, float, 0)
+ ATTRIB(XonoticFirstRunDialog, closable, float, 0);
ENDCLASS(XonoticFirstRunDialog)
#include "rootdialog.qh"
CLASS(XonoticHUDAmmoDialog, XonoticRootDialog)
METHOD(XonoticHUDAmmoDialog, fill, void(entity));
- ATTRIB(XonoticHUDAmmoDialog, title, string, _("Ammo Panel"))
- ATTRIB(XonoticHUDAmmoDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
- ATTRIB(XonoticHUDAmmoDialog, intendedWidth, float, 0.4)
- ATTRIB(XonoticHUDAmmoDialog, rows, float, 15)
- ATTRIB(XonoticHUDAmmoDialog, columns, float, 4)
- ATTRIB(XonoticHUDAmmoDialog, name, string, "HUDammo")
- ATTRIB(XonoticHUDAmmoDialog, requiresConnection, float, true)
+ ATTRIB(XonoticHUDAmmoDialog, title, string, _("Ammo Panel"));
+ ATTRIB(XonoticHUDAmmoDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
+ ATTRIB(XonoticHUDAmmoDialog, intendedWidth, float, 0.4);
+ ATTRIB(XonoticHUDAmmoDialog, rows, float, 15);
+ ATTRIB(XonoticHUDAmmoDialog, columns, float, 4);
+ ATTRIB(XonoticHUDAmmoDialog, name, string, "HUDammo");
+ ATTRIB(XonoticHUDAmmoDialog, requiresConnection, float, true);
ENDCLASS(XonoticHUDAmmoDialog)
#include "rootdialog.qh"
CLASS(XonoticHUDCenterprintDialog, XonoticRootDialog)
METHOD(XonoticHUDCenterprintDialog, fill, void(entity));
- ATTRIB(XonoticHUDCenterprintDialog, title, string, _("Centerprint Panel"))
- ATTRIB(XonoticHUDCenterprintDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
- ATTRIB(XonoticHUDCenterprintDialog, intendedWidth, float, 0.4)
- ATTRIB(XonoticHUDCenterprintDialog, rows, float, 15)
- ATTRIB(XonoticHUDCenterprintDialog, columns, float, 4)
- ATTRIB(XonoticHUDCenterprintDialog, name, string, "HUDcenterprint")
- ATTRIB(XonoticHUDCenterprintDialog, requiresConnection, float, true)
+ ATTRIB(XonoticHUDCenterprintDialog, title, string, _("Centerprint Panel"));
+ ATTRIB(XonoticHUDCenterprintDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
+ ATTRIB(XonoticHUDCenterprintDialog, intendedWidth, float, 0.4);
+ ATTRIB(XonoticHUDCenterprintDialog, rows, float, 15);
+ ATTRIB(XonoticHUDCenterprintDialog, columns, float, 4);
+ ATTRIB(XonoticHUDCenterprintDialog, name, string, "HUDcenterprint");
+ ATTRIB(XonoticHUDCenterprintDialog, requiresConnection, float, true);
ENDCLASS(XonoticHUDCenterprintDialog)
#include "rootdialog.qh"
CLASS(XonoticHUDChatDialog, XonoticRootDialog)
METHOD(XonoticHUDChatDialog, fill, void(entity));
- ATTRIB(XonoticHUDChatDialog, title, string, _("Chat Panel"))
- ATTRIB(XonoticHUDChatDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
- ATTRIB(XonoticHUDChatDialog, intendedWidth, float, 0.4)
- ATTRIB(XonoticHUDChatDialog, rows, float, 15)
- ATTRIB(XonoticHUDChatDialog, columns, float, 4)
- ATTRIB(XonoticHUDChatDialog, name, string, "HUDchat")
- ATTRIB(XonoticHUDChatDialog, requiresConnection, float, true)
+ ATTRIB(XonoticHUDChatDialog, title, string, _("Chat Panel"));
+ ATTRIB(XonoticHUDChatDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
+ ATTRIB(XonoticHUDChatDialog, intendedWidth, float, 0.4);
+ ATTRIB(XonoticHUDChatDialog, rows, float, 15);
+ ATTRIB(XonoticHUDChatDialog, columns, float, 4);
+ ATTRIB(XonoticHUDChatDialog, name, string, "HUDchat");
+ ATTRIB(XonoticHUDChatDialog, requiresConnection, float, true);
ENDCLASS(XonoticHUDChatDialog)
#include "rootdialog.qh"
CLASS(XonoticHUDEngineInfoDialog, XonoticRootDialog)
METHOD(XonoticHUDEngineInfoDialog, fill, void(entity));
- ATTRIB(XonoticHUDEngineInfoDialog, title, string, _("Engine Info Panel"))
- ATTRIB(XonoticHUDEngineInfoDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
- ATTRIB(XonoticHUDEngineInfoDialog, intendedWidth, float, 0.4)
- ATTRIB(XonoticHUDEngineInfoDialog, rows, float, 15)
- ATTRIB(XonoticHUDEngineInfoDialog, columns, float, 4)
- ATTRIB(XonoticHUDEngineInfoDialog, name, string, "HUDengineinfo")
- ATTRIB(XonoticHUDEngineInfoDialog, requiresConnection, float, true)
+ ATTRIB(XonoticHUDEngineInfoDialog, title, string, _("Engine Info Panel"));
+ ATTRIB(XonoticHUDEngineInfoDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
+ ATTRIB(XonoticHUDEngineInfoDialog, intendedWidth, float, 0.4);
+ ATTRIB(XonoticHUDEngineInfoDialog, rows, float, 15);
+ ATTRIB(XonoticHUDEngineInfoDialog, columns, float, 4);
+ ATTRIB(XonoticHUDEngineInfoDialog, name, string, "HUDengineinfo");
+ ATTRIB(XonoticHUDEngineInfoDialog, requiresConnection, float, true);
ENDCLASS(XonoticHUDEngineInfoDialog)
#include "rootdialog.qh"
CLASS(XonoticHUDHealthArmorDialog, XonoticRootDialog)
METHOD(XonoticHUDHealthArmorDialog, fill, void(entity));
- ATTRIB(XonoticHUDHealthArmorDialog, title, string, _("Health/Armor Panel"))
- ATTRIB(XonoticHUDHealthArmorDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
- ATTRIB(XonoticHUDHealthArmorDialog, intendedWidth, float, 0.4)
- ATTRIB(XonoticHUDHealthArmorDialog, rows, float, 16)
- ATTRIB(XonoticHUDHealthArmorDialog, columns, float, 4)
- ATTRIB(XonoticHUDHealthArmorDialog, name, string, "HUDhealtharmor")
- ATTRIB(XonoticHUDHealthArmorDialog, requiresConnection, float, true)
+ ATTRIB(XonoticHUDHealthArmorDialog, title, string, _("Health/Armor Panel"));
+ ATTRIB(XonoticHUDHealthArmorDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
+ ATTRIB(XonoticHUDHealthArmorDialog, intendedWidth, float, 0.4);
+ ATTRIB(XonoticHUDHealthArmorDialog, rows, float, 16);
+ ATTRIB(XonoticHUDHealthArmorDialog, columns, float, 4);
+ ATTRIB(XonoticHUDHealthArmorDialog, name, string, "HUDhealtharmor");
+ ATTRIB(XonoticHUDHealthArmorDialog, requiresConnection, float, true);
ENDCLASS(XonoticHUDHealthArmorDialog)
#include "rootdialog.qh"
CLASS(XonoticHUDInfoMessagesDialog, XonoticRootDialog)
METHOD(XonoticHUDInfoMessagesDialog, fill, void(entity));
- ATTRIB(XonoticHUDInfoMessagesDialog, title, string, _("Info Messages Panel"))
- ATTRIB(XonoticHUDInfoMessagesDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
- ATTRIB(XonoticHUDInfoMessagesDialog, intendedWidth, float, 0.4)
- ATTRIB(XonoticHUDInfoMessagesDialog, rows, float, 15)
- ATTRIB(XonoticHUDInfoMessagesDialog, columns, float, 4)
- ATTRIB(XonoticHUDInfoMessagesDialog, name, string, "HUDinfomessages")
- ATTRIB(XonoticHUDInfoMessagesDialog, requiresConnection, float, true)
+ ATTRIB(XonoticHUDInfoMessagesDialog, title, string, _("Info Messages Panel"));
+ ATTRIB(XonoticHUDInfoMessagesDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
+ ATTRIB(XonoticHUDInfoMessagesDialog, intendedWidth, float, 0.4);
+ ATTRIB(XonoticHUDInfoMessagesDialog, rows, float, 15);
+ ATTRIB(XonoticHUDInfoMessagesDialog, columns, float, 4);
+ ATTRIB(XonoticHUDInfoMessagesDialog, name, string, "HUDinfomessages");
+ ATTRIB(XonoticHUDInfoMessagesDialog, requiresConnection, float, true);
ENDCLASS(XonoticHUDInfoMessagesDialog)
#include "rootdialog.qh"
CLASS(XonoticHUDItemsTimeDialog, XonoticRootDialog)
METHOD(XonoticHUDItemsTimeDialog, fill, void(entity));
- ATTRIB(XonoticHUDItemsTimeDialog, title, string, _("Items Time Panel"))
- ATTRIB(XonoticHUDItemsTimeDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
- ATTRIB(XonoticHUDItemsTimeDialog, intendedWidth, float, 0.4)
- ATTRIB(XonoticHUDItemsTimeDialog, rows, float, 15)
- ATTRIB(XonoticHUDItemsTimeDialog, columns, float, 4)
- ATTRIB(XonoticHUDItemsTimeDialog, name, string, "HUDitemstime")
+ ATTRIB(XonoticHUDItemsTimeDialog, title, string, _("Items Time Panel"));
+ ATTRIB(XonoticHUDItemsTimeDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
+ ATTRIB(XonoticHUDItemsTimeDialog, intendedWidth, float, 0.4);
+ ATTRIB(XonoticHUDItemsTimeDialog, rows, float, 15);
+ ATTRIB(XonoticHUDItemsTimeDialog, columns, float, 4);
+ ATTRIB(XonoticHUDItemsTimeDialog, name, string, "HUDitemstime");
ENDCLASS(XonoticHUDItemsTimeDialog)
#include "rootdialog.qh"
CLASS(XonoticHUDModIconsDialog, XonoticRootDialog)
METHOD(XonoticHUDModIconsDialog, fill, void(entity));
- ATTRIB(XonoticHUDModIconsDialog, title, string, _("Mod Icons Panel"))
- ATTRIB(XonoticHUDModIconsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
- ATTRIB(XonoticHUDModIconsDialog, intendedWidth, float, 0.4)
- ATTRIB(XonoticHUDModIconsDialog, rows, float, 15)
- ATTRIB(XonoticHUDModIconsDialog, columns, float, 4)
- ATTRIB(XonoticHUDModIconsDialog, name, string, "HUDmodicons")
- ATTRIB(XonoticHUDModIconsDialog, requiresConnection, float, true)
+ ATTRIB(XonoticHUDModIconsDialog, title, string, _("Mod Icons Panel"));
+ ATTRIB(XonoticHUDModIconsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
+ ATTRIB(XonoticHUDModIconsDialog, intendedWidth, float, 0.4);
+ ATTRIB(XonoticHUDModIconsDialog, rows, float, 15);
+ ATTRIB(XonoticHUDModIconsDialog, columns, float, 4);
+ ATTRIB(XonoticHUDModIconsDialog, name, string, "HUDmodicons");
+ ATTRIB(XonoticHUDModIconsDialog, requiresConnection, float, true);
ENDCLASS(XonoticHUDModIconsDialog)
#include "rootdialog.qh"
CLASS(XonoticHUDNotificationDialog, XonoticRootDialog)
METHOD(XonoticHUDNotificationDialog, fill, void(entity));
- ATTRIB(XonoticHUDNotificationDialog, title, string, _("Notification Panel"))
- ATTRIB(XonoticHUDNotificationDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
- ATTRIB(XonoticHUDNotificationDialog, intendedWidth, float, 0.4)
- ATTRIB(XonoticHUDNotificationDialog, rows, float, 15)
- ATTRIB(XonoticHUDNotificationDialog, columns, float, 4)
- ATTRIB(XonoticHUDNotificationDialog, name, string, "HUDnotify")
- ATTRIB(XonoticHUDNotificationDialog, requiresConnection, float, true)
+ ATTRIB(XonoticHUDNotificationDialog, title, string, _("Notification Panel"));
+ ATTRIB(XonoticHUDNotificationDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
+ ATTRIB(XonoticHUDNotificationDialog, intendedWidth, float, 0.4);
+ ATTRIB(XonoticHUDNotificationDialog, rows, float, 15);
+ ATTRIB(XonoticHUDNotificationDialog, columns, float, 4);
+ ATTRIB(XonoticHUDNotificationDialog, name, string, "HUDnotify");
+ ATTRIB(XonoticHUDNotificationDialog, requiresConnection, float, true);
ENDCLASS(XonoticHUDNotificationDialog)
#include "rootdialog.qh"
CLASS(XonoticHUDPhysicsDialog, XonoticRootDialog)
METHOD(XonoticHUDPhysicsDialog, fill, void(entity));
- ATTRIB(XonoticHUDPhysicsDialog, title, string, _("Physics Panel"))
- ATTRIB(XonoticHUDPhysicsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
- ATTRIB(XonoticHUDPhysicsDialog, intendedWidth, float, 0.4)
- ATTRIB(XonoticHUDPhysicsDialog, rows, float, 15)
- ATTRIB(XonoticHUDPhysicsDialog, columns, float, 4)
- ATTRIB(XonoticHUDPhysicsDialog, name, string, "HUDphysics")
- ATTRIB(XonoticHUDPhysicsDialog, sliderTopspeedTime, entity, NULL)
- ATTRIB(XonoticHUDPhysicsDialog, requiresConnection, float, true)
+ ATTRIB(XonoticHUDPhysicsDialog, title, string, _("Physics Panel"));
+ ATTRIB(XonoticHUDPhysicsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
+ ATTRIB(XonoticHUDPhysicsDialog, intendedWidth, float, 0.4);
+ ATTRIB(XonoticHUDPhysicsDialog, rows, float, 15);
+ ATTRIB(XonoticHUDPhysicsDialog, columns, float, 4);
+ ATTRIB(XonoticHUDPhysicsDialog, name, string, "HUDphysics");
+ ATTRIB(XonoticHUDPhysicsDialog, sliderTopspeedTime, entity);
+ ATTRIB(XonoticHUDPhysicsDialog, requiresConnection, float, true);
ENDCLASS(XonoticHUDPhysicsDialog)
#include "rootdialog.qh"
CLASS(XonoticHUDPowerupsDialog, XonoticRootDialog)
METHOD(XonoticHUDPowerupsDialog, fill, void(entity));
- ATTRIB(XonoticHUDPowerupsDialog, title, string, _("Powerups Panel"))
- ATTRIB(XonoticHUDPowerupsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
- ATTRIB(XonoticHUDPowerupsDialog, intendedWidth, float, 0.4)
- ATTRIB(XonoticHUDPowerupsDialog, rows, float, 14)
- ATTRIB(XonoticHUDPowerupsDialog, columns, float, 4)
- ATTRIB(XonoticHUDPowerupsDialog, name, string, "HUDpowerups")
- ATTRIB(XonoticHUDPowerupsDialog, requiresConnection, float, true)
+ ATTRIB(XonoticHUDPowerupsDialog, title, string, _("Powerups Panel"));
+ ATTRIB(XonoticHUDPowerupsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
+ ATTRIB(XonoticHUDPowerupsDialog, intendedWidth, float, 0.4);
+ ATTRIB(XonoticHUDPowerupsDialog, rows, float, 14);
+ ATTRIB(XonoticHUDPowerupsDialog, columns, float, 4);
+ ATTRIB(XonoticHUDPowerupsDialog, name, string, "HUDpowerups");
+ ATTRIB(XonoticHUDPowerupsDialog, requiresConnection, float, true);
ENDCLASS(XonoticHUDPowerupsDialog)
#include "rootdialog.qh"
CLASS(XonoticHUDPressedKeysDialog, XonoticRootDialog)
METHOD(XonoticHUDPressedKeysDialog, fill, void(entity));
- ATTRIB(XonoticHUDPressedKeysDialog, title, string, _("Pressed Keys Panel"))
- ATTRIB(XonoticHUDPressedKeysDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
- ATTRIB(XonoticHUDPressedKeysDialog, intendedWidth, float, 0.4)
- ATTRIB(XonoticHUDPressedKeysDialog, rows, float, 15)
- ATTRIB(XonoticHUDPressedKeysDialog, columns, float, 4)
- ATTRIB(XonoticHUDPressedKeysDialog, name, string, "HUDpressedkeys")
- ATTRIB(XonoticHUDPressedKeysDialog, requiresConnection, float, true)
+ ATTRIB(XonoticHUDPressedKeysDialog, title, string, _("Pressed Keys Panel"));
+ ATTRIB(XonoticHUDPressedKeysDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
+ ATTRIB(XonoticHUDPressedKeysDialog, intendedWidth, float, 0.4);
+ ATTRIB(XonoticHUDPressedKeysDialog, rows, float, 15);
+ ATTRIB(XonoticHUDPressedKeysDialog, columns, float, 4);
+ ATTRIB(XonoticHUDPressedKeysDialog, name, string, "HUDpressedkeys");
+ ATTRIB(XonoticHUDPressedKeysDialog, requiresConnection, float, true);
ENDCLASS(XonoticHUDPressedKeysDialog)
#include "rootdialog.qh"
CLASS(XonoticHUDQuickMenuDialog, XonoticRootDialog)
METHOD(XonoticHUDQuickMenuDialog, fill, void(entity));
- ATTRIB(XonoticHUDQuickMenuDialog, title, string, _("Quick Menu Panel"))
- ATTRIB(XonoticHUDQuickMenuDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
- ATTRIB(XonoticHUDQuickMenuDialog, intendedWidth, float, 0.4)
- ATTRIB(XonoticHUDQuickMenuDialog, rows, float, 15)
- ATTRIB(XonoticHUDQuickMenuDialog, columns, float, 4)
- ATTRIB(XonoticHUDQuickMenuDialog, name, string, "HUDquickmenu")
+ ATTRIB(XonoticHUDQuickMenuDialog, title, string, _("Quick Menu Panel"));
+ ATTRIB(XonoticHUDQuickMenuDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
+ ATTRIB(XonoticHUDQuickMenuDialog, intendedWidth, float, 0.4);
+ ATTRIB(XonoticHUDQuickMenuDialog, rows, float, 15);
+ ATTRIB(XonoticHUDQuickMenuDialog, columns, float, 4);
+ ATTRIB(XonoticHUDQuickMenuDialog, name, string, "HUDquickmenu");
ENDCLASS(XonoticHUDQuickMenuDialog)
#include "rootdialog.qh"
CLASS(XonoticHUDRaceTimerDialog, XonoticRootDialog)
METHOD(XonoticHUDRaceTimerDialog, fill, void(entity));
- ATTRIB(XonoticHUDRaceTimerDialog, title, string, _("Race Timer Panel"))
- ATTRIB(XonoticHUDRaceTimerDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
- ATTRIB(XonoticHUDRaceTimerDialog, intendedWidth, float, 0.4)
- ATTRIB(XonoticHUDRaceTimerDialog, rows, float, 15)
- ATTRIB(XonoticHUDRaceTimerDialog, columns, float, 4)
- ATTRIB(XonoticHUDRaceTimerDialog, name, string, "HUDracetimer")
- ATTRIB(XonoticHUDRaceTimerDialog, requiresConnection, float, true)
+ ATTRIB(XonoticHUDRaceTimerDialog, title, string, _("Race Timer Panel"));
+ ATTRIB(XonoticHUDRaceTimerDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
+ ATTRIB(XonoticHUDRaceTimerDialog, intendedWidth, float, 0.4);
+ ATTRIB(XonoticHUDRaceTimerDialog, rows, float, 15);
+ ATTRIB(XonoticHUDRaceTimerDialog, columns, float, 4);
+ ATTRIB(XonoticHUDRaceTimerDialog, name, string, "HUDracetimer");
+ ATTRIB(XonoticHUDRaceTimerDialog, requiresConnection, float, true);
ENDCLASS(XonoticHUDRaceTimerDialog)
#include "rootdialog.qh"
CLASS(XonoticHUDRadarDialog, XonoticRootDialog)
METHOD(XonoticHUDRadarDialog, fill, void(entity));
- ATTRIB(XonoticHUDRadarDialog, title, string, _("Radar Panel"))
- ATTRIB(XonoticHUDRadarDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
- ATTRIB(XonoticHUDRadarDialog, intendedWidth, float, 0.4)
- ATTRIB(XonoticHUDRadarDialog, rows, float, 15)
- ATTRIB(XonoticHUDRadarDialog, columns, float, 4)
- ATTRIB(XonoticHUDRadarDialog, name, string, "HUDradar")
- ATTRIB(XonoticHUDRadarDialog, requiresConnection, float, true)
+ ATTRIB(XonoticHUDRadarDialog, title, string, _("Radar Panel"));
+ ATTRIB(XonoticHUDRadarDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
+ ATTRIB(XonoticHUDRadarDialog, intendedWidth, float, 0.4);
+ ATTRIB(XonoticHUDRadarDialog, rows, float, 15);
+ ATTRIB(XonoticHUDRadarDialog, columns, float, 4);
+ ATTRIB(XonoticHUDRadarDialog, name, string, "HUDradar");
+ ATTRIB(XonoticHUDRadarDialog, requiresConnection, float, true);
ENDCLASS(XonoticHUDRadarDialog)
#include "rootdialog.qh"
CLASS(XonoticHUDScoreDialog, XonoticRootDialog)
METHOD(XonoticHUDScoreDialog, fill, void(entity));
- ATTRIB(XonoticHUDScoreDialog, title, string, _("Score Panel"))
- ATTRIB(XonoticHUDScoreDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
- ATTRIB(XonoticHUDScoreDialog, intendedWidth, float, 0.4)
- ATTRIB(XonoticHUDScoreDialog, rows, float, 15)
- ATTRIB(XonoticHUDScoreDialog, columns, float, 4)
- ATTRIB(XonoticHUDScoreDialog, name, string, "HUDscore")
- ATTRIB(XonoticHUDScoreDialog, requiresConnection, float, true)
+ ATTRIB(XonoticHUDScoreDialog, title, string, _("Score Panel"));
+ ATTRIB(XonoticHUDScoreDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
+ ATTRIB(XonoticHUDScoreDialog, intendedWidth, float, 0.4);
+ ATTRIB(XonoticHUDScoreDialog, rows, float, 15);
+ ATTRIB(XonoticHUDScoreDialog, columns, float, 4);
+ ATTRIB(XonoticHUDScoreDialog, name, string, "HUDscore");
+ ATTRIB(XonoticHUDScoreDialog, requiresConnection, float, true);
ENDCLASS(XonoticHUDScoreDialog)
#include "rootdialog.qh"
CLASS(XonoticHUDTimerDialog, XonoticRootDialog)
METHOD(XonoticHUDTimerDialog, fill, void(entity));
- ATTRIB(XonoticHUDTimerDialog, title, string, _("Timer Panel"))
- ATTRIB(XonoticHUDTimerDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
- ATTRIB(XonoticHUDTimerDialog, intendedWidth, float, 0.4)
- ATTRIB(XonoticHUDTimerDialog, rows, float, 15)
- ATTRIB(XonoticHUDTimerDialog, columns, float, 4)
- ATTRIB(XonoticHUDTimerDialog, name, string, "HUDtimer")
- ATTRIB(XonoticHUDTimerDialog, requiresConnection, float, true)
+ ATTRIB(XonoticHUDTimerDialog, title, string, _("Timer Panel"));
+ ATTRIB(XonoticHUDTimerDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
+ ATTRIB(XonoticHUDTimerDialog, intendedWidth, float, 0.4);
+ ATTRIB(XonoticHUDTimerDialog, rows, float, 15);
+ ATTRIB(XonoticHUDTimerDialog, columns, float, 4);
+ ATTRIB(XonoticHUDTimerDialog, name, string, "HUDtimer");
+ ATTRIB(XonoticHUDTimerDialog, requiresConnection, float, true);
ENDCLASS(XonoticHUDTimerDialog)
#include "rootdialog.qh"
CLASS(XonoticHUDVoteDialog, XonoticRootDialog)
METHOD(XonoticHUDVoteDialog, fill, void(entity));
- ATTRIB(XonoticHUDVoteDialog, title, string, _("Vote Panel"))
- ATTRIB(XonoticHUDVoteDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
- ATTRIB(XonoticHUDVoteDialog, intendedWidth, float, 0.4)
- ATTRIB(XonoticHUDVoteDialog, rows, float, 15)
- ATTRIB(XonoticHUDVoteDialog, columns, float, 4)
- ATTRIB(XonoticHUDVoteDialog, name, string, "HUDvote")
- ATTRIB(XonoticHUDVoteDialog, requiresConnection, float, true)
+ ATTRIB(XonoticHUDVoteDialog, title, string, _("Vote Panel"));
+ ATTRIB(XonoticHUDVoteDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
+ ATTRIB(XonoticHUDVoteDialog, intendedWidth, float, 0.4);
+ ATTRIB(XonoticHUDVoteDialog, rows, float, 15);
+ ATTRIB(XonoticHUDVoteDialog, columns, float, 4);
+ ATTRIB(XonoticHUDVoteDialog, name, string, "HUDvote");
+ ATTRIB(XonoticHUDVoteDialog, requiresConnection, float, true);
ENDCLASS(XonoticHUDVoteDialog)
#include "rootdialog.qh"
CLASS(XonoticHUDWeaponsDialog, XonoticRootDialog)
METHOD(XonoticHUDWeaponsDialog, fill, void(entity));
- ATTRIB(XonoticHUDWeaponsDialog, title, string, _("Weapons Panel"))
- ATTRIB(XonoticHUDWeaponsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
- ATTRIB(XonoticHUDWeaponsDialog, intendedWidth, float, 0.4)
- ATTRIB(XonoticHUDWeaponsDialog, rows, float, 21)
- ATTRIB(XonoticHUDWeaponsDialog, columns, float, 4)
- ATTRIB(XonoticHUDWeaponsDialog, name, string, "HUDweapons")
- ATTRIB(XonoticHUDWeaponsDialog, requiresConnection, float, true)
+ ATTRIB(XonoticHUDWeaponsDialog, title, string, _("Weapons Panel"));
+ ATTRIB(XonoticHUDWeaponsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
+ ATTRIB(XonoticHUDWeaponsDialog, intendedWidth, float, 0.4);
+ ATTRIB(XonoticHUDWeaponsDialog, rows, float, 21);
+ ATTRIB(XonoticHUDWeaponsDialog, columns, float, 4);
+ ATTRIB(XonoticHUDWeaponsDialog, name, string, "HUDweapons");
+ ATTRIB(XonoticHUDWeaponsDialog, requiresConnection, float, true);
ENDCLASS(XonoticHUDWeaponsDialog)
#include "rootdialog.qh"
CLASS(XonoticHUDExitDialog, XonoticRootDialog)
METHOD(XonoticHUDExitDialog, fill, void(entity));
- ATTRIB(XonoticHUDExitDialog, title, string, _("Panel HUD Setup"))
- ATTRIB(XonoticHUDExitDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
- ATTRIB(XonoticHUDExitDialog, intendedWidth, float, 0.8)
- ATTRIB(XonoticHUDExitDialog, rows, float, 18)
- ATTRIB(XonoticHUDExitDialog, columns, float, 8.2)
- ATTRIB(XonoticHUDExitDialog, name, string, "HUDExit")
- ATTRIB(XonoticHUDExitDialog, requiresConnection, float, true)
+ ATTRIB(XonoticHUDExitDialog, title, string, _("Panel HUD Setup"));
+ ATTRIB(XonoticHUDExitDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
+ ATTRIB(XonoticHUDExitDialog, intendedWidth, float, 0.8);
+ ATTRIB(XonoticHUDExitDialog, rows, float, 18);
+ ATTRIB(XonoticHUDExitDialog, columns, float, 8.2);
+ ATTRIB(XonoticHUDExitDialog, name, string, "HUDExit");
+ ATTRIB(XonoticHUDExitDialog, requiresConnection, float, true);
ENDCLASS(XonoticHUDExitDialog)
#include "rootdialog.qh"
CLASS(XonoticMonsterToolsDialog, XonoticRootDialog)
METHOD(XonoticMonsterToolsDialog, fill, void(entity));
- ATTRIB(XonoticMonsterToolsDialog, title, string, _("Monster Tools"))
- ATTRIB(XonoticMonsterToolsDialog, color, vector, SKINCOLOR_DIALOG_SANDBOXTOOLS)
- ATTRIB(XonoticMonsterToolsDialog, intendedWidth, float, 0.8)
- ATTRIB(XonoticMonsterToolsDialog, rows, float, 16)
- ATTRIB(XonoticMonsterToolsDialog, columns, float, 4)
- ATTRIB(XonoticMonsterToolsDialog, name, string, "MonsterTools")
+ ATTRIB(XonoticMonsterToolsDialog, title, string, _("Monster Tools"));
+ ATTRIB(XonoticMonsterToolsDialog, color, vector, SKINCOLOR_DIALOG_SANDBOXTOOLS);
+ ATTRIB(XonoticMonsterToolsDialog, intendedWidth, float, 0.8);
+ ATTRIB(XonoticMonsterToolsDialog, rows, float, 16);
+ ATTRIB(XonoticMonsterToolsDialog, columns, float, 4);
+ ATTRIB(XonoticMonsterToolsDialog, name, string, "MonsterTools");
ENDCLASS(XonoticMonsterToolsDialog)
#include "dialog.qh"
CLASS(XonoticMultiplayerDialog, XonoticDialog)
METHOD(XonoticMultiplayerDialog, fill, void(entity));
- ATTRIB(XonoticMultiplayerDialog, title, string, _("Multiplayer"))
- ATTRIB(XonoticMultiplayerDialog, tooltip, string, _("Play online, against your friends in LAN, view demos or change player settings"))
- ATTRIB(XonoticMultiplayerDialog, color, vector, SKINCOLOR_DIALOG_MULTIPLAYER)
- ATTRIB(XonoticMultiplayerDialog, intendedWidth, float, 0.96)
- ATTRIB(XonoticMultiplayerDialog, rows, float, 24)
- ATTRIB(XonoticMultiplayerDialog, columns, float, 4)
+ ATTRIB(XonoticMultiplayerDialog, title, string, _("Multiplayer"));
+ ATTRIB(XonoticMultiplayerDialog, tooltip, string, _("Play online, against your friends in LAN, view demos or change player settings"));
+ ATTRIB(XonoticMultiplayerDialog, color, vector, SKINCOLOR_DIALOG_MULTIPLAYER);
+ ATTRIB(XonoticMultiplayerDialog, intendedWidth, float, 0.96);
+ ATTRIB(XonoticMultiplayerDialog, rows, float, 24);
+ ATTRIB(XonoticMultiplayerDialog, columns, float, 4);
ENDCLASS(XonoticMultiplayerDialog)
METHOD(XonoticServerCreateTab, fill, void(entity));
METHOD(XonoticServerCreateTab, gameTypeChangeNotify, void(entity));
METHOD(XonoticServerCreateTab, gameTypeSelectNotify, void(entity));
- ATTRIB(XonoticServerCreateTab, intendedWidth, float, 0.9)
- ATTRIB(XonoticServerCreateTab, rows, float, 23)
- ATTRIB(XonoticServerCreateTab, columns, float, 6.2) // added extra .2 for center space
+ ATTRIB(XonoticServerCreateTab, intendedWidth, float, 0.9);
+ ATTRIB(XonoticServerCreateTab, rows, float, 23);
+ ATTRIB(XonoticServerCreateTab, columns, float, 6.2); // added extra .2 for center space
- ATTRIB(XonoticServerCreateTab, mapListBox, entity, NULL)
- ATTRIB(XonoticServerCreateTab, sliderFraglimit, entity, NULL)
- ATTRIB(XonoticServerCreateTab, sliderTeams, entity, NULL)
- ATTRIB(XonoticServerCreateTab, sliderTimelimit, entity, NULL)
- ATTRIB(XonoticServerCreateTab, labelFraglimit, entity, NULL)
- ATTRIB(XonoticServerCreateTab, labelTeams, entity, NULL)
+ ATTRIB(XonoticServerCreateTab, mapListBox, entity);
+ ATTRIB(XonoticServerCreateTab, sliderFraglimit, entity);
+ ATTRIB(XonoticServerCreateTab, sliderTeams, entity);
+ ATTRIB(XonoticServerCreateTab, sliderTimelimit, entity);
+ ATTRIB(XonoticServerCreateTab, labelFraglimit, entity);
+ ATTRIB(XonoticServerCreateTab, labelTeams, entity);
ENDCLASS(XonoticServerCreateTab)
entity makeXonoticServerCreateTab();
{
entity e;
e = me.(typeLabels[i]);
- e.disabled = !(MapInfo_Map_supportedGametypes & GameType_GetID(i));
+ e.disabled = !(MapInfo_Map_supportedGametypes & GameType_GetID(i).m_flags);
}
MapInfo_ClearTemps();
CLASS(XonoticMapInfoDialog, XonoticDialog)
METHOD(XonoticMapInfoDialog, fill, void(entity));
METHOD(XonoticMapInfoDialog, loadMapInfo, void(entity, float, entity));
- ATTRIB(XonoticMapInfoDialog, title, string, _("Map Information"))
- ATTRIB(XonoticMapInfoDialog, color, vector, SKINCOLOR_DIALOG_MAPINFO)
- ATTRIB(XonoticMapInfoDialog, intendedWidth, float, 1.0)
- ATTRIB(XonoticMapInfoDialog, rows, float, 11)
- ATTRIB(XonoticMapInfoDialog, columns, float, 10)
+ ATTRIB(XonoticMapInfoDialog, title, string, _("Map Information"));
+ ATTRIB(XonoticMapInfoDialog, color, vector, SKINCOLOR_DIALOG_MAPINFO);
+ ATTRIB(XonoticMapInfoDialog, intendedWidth, float, 1.0);
+ ATTRIB(XonoticMapInfoDialog, rows, float, 11);
+ ATTRIB(XonoticMapInfoDialog, columns, float, 10);
- ATTRIB(XonoticMapInfoDialog, previewImage, entity, NULL)
- ATTRIB(XonoticMapInfoDialog, titleLabel, entity, NULL)
- ATTRIB(XonoticMapInfoDialog, authorLabel, entity, NULL)
- ATTRIB(XonoticMapInfoDialog, descriptionLabel, entity, NULL)
- ATTRIB(XonoticMapInfoDialog, featuresLabel, entity, NULL)
+ ATTRIB(XonoticMapInfoDialog, previewImage, entity);
+ ATTRIB(XonoticMapInfoDialog, titleLabel, entity);
+ ATTRIB(XonoticMapInfoDialog, authorLabel, entity);
+ ATTRIB(XonoticMapInfoDialog, descriptionLabel, entity);
+ ATTRIB(XonoticMapInfoDialog, featuresLabel, entity);
- ATTRIBARRAY(XonoticMapInfoDialog, typeLabels, entity, 24)
+ ATTRIBARRAY(XonoticMapInfoDialog, typeLabels, entity, 24);
- ATTRIB(XonoticMapInfoDialog, currentMapIndex, float, 0)
- ATTRIB(XonoticMapInfoDialog, currentMapBSPName, string, string_null)
- ATTRIB(XonoticMapInfoDialog, currentMapTitle, string, string_null)
- ATTRIB(XonoticMapInfoDialog, currentMapAuthor, string, string_null)
- ATTRIB(XonoticMapInfoDialog, currentMapDescription, string, string_null)
- ATTRIB(XonoticMapInfoDialog, currentMapPreviewImage, string, string_null)
+ ATTRIB(XonoticMapInfoDialog, currentMapIndex, float, 0);
+ ATTRIB(XonoticMapInfoDialog, currentMapBSPName, string);
+ ATTRIB(XonoticMapInfoDialog, currentMapTitle, string);
+ ATTRIB(XonoticMapInfoDialog, currentMapAuthor, string);
+ ATTRIB(XonoticMapInfoDialog, currentMapDescription, string);
+ ATTRIB(XonoticMapInfoDialog, currentMapPreviewImage, string);
ENDCLASS(XonoticMapInfoDialog)
METHOD(XonoticMutatorsDialog, fill, void(entity));
METHOD(XonoticMutatorsDialog, showNotify, void(entity));
METHOD(XonoticMutatorsDialog, close, void(entity));
- ATTRIB(XonoticMutatorsDialog, title, string, _("Mutators"))
- ATTRIB(XonoticMutatorsDialog, color, vector, SKINCOLOR_DIALOG_MUTATORS)
- ATTRIB(XonoticMutatorsDialog, intendedWidth, float, 0.9)
- ATTRIB(XonoticMutatorsDialog, rows, float, 20)
- ATTRIB(XonoticMutatorsDialog, columns, float, 6)
- ATTRIB(XonoticMutatorsDialog, refilterEntity, entity, NULL)
+ ATTRIB(XonoticMutatorsDialog, title, string, _("Mutators"));
+ ATTRIB(XonoticMutatorsDialog, color, vector, SKINCOLOR_DIALOG_MUTATORS);
+ ATTRIB(XonoticMutatorsDialog, intendedWidth, float, 0.9);
+ ATTRIB(XonoticMutatorsDialog, rows, float, 20);
+ ATTRIB(XonoticMutatorsDialog, columns, float, 6);
+ ATTRIB(XonoticMutatorsDialog, refilterEntity, entity);
ENDCLASS(XonoticMutatorsDialog)
me.configureDialog(me);
return me;
}
+
+void XonoticServerListTab_refresh(entity this, entity slist)
+{
+ bool clear = false;
+ slist.refreshServerList(slist, clear ? REFRESHSERVERLIST_RESET : REFRESHSERVERLIST_ASK);
+}
+
void XonoticServerListTab_fill(entity me)
{
entity e, slist;
slist = makeXonoticServerList();
me.gotoRC(me, 0.5, 0);
- me.TD(me, 1, 0.6, e = makeXonoticTextLabel(1, _("Filter:")));
- me.TD(me, 1, 2.8, e = makeXonoticInputBox(0, string_null));
+ me.TD(me, 1, 0.5, e = makeXonoticTextLabel(1, _("Filter:")));
+ me.TD(me, 1, 2, e = makeXonoticInputBox(0, string_null));
e.onChange = ServerList_Filter_Change;
e.onChangeEntity = slist;
slist.controlledTextbox = e;
- me.gotoRC(me, 0.5, 3.6);
+ me.gotoRC(me, 0.5, 2.6);
me.TD(me, 1, 0.9, e = makeXonoticCheckBox(0, "menu_slist_categories", ZCTX(_("SRVS^Categories"))));
e.onClickEntity = slist;
e.onClick = ServerList_Categories_Click;
e.onClick = ServerList_ShowFull_Click;
me.TD(me, 1, 0.6, e = makeXonoticCheckBox_T(0, "net_slist_pause", _("Pause"),
_("Pause updating the server list to prevent servers from \"jumping around\"")));
+ me.TD(me, 1, 1, e = makeXonoticButton_T(_("Refresh"), '0 0 0', _("Reload the server list")));
+ e.onClick = XonoticServerListTab_refresh;
+ e.onClickEntity = slist;
me.gotoRC(me, 2, 0);
me.TD(me, 1, 1, slist.sortButton1 = makeXonoticButton(string_null, '0 0 0'));
#include "tab.qh"
CLASS(XonoticServerListTab, XonoticTab)
METHOD(XonoticServerListTab, fill, void(entity));
- ATTRIB(XonoticServerListTab, intendedWidth, float, 0.9)
- ATTRIB(XonoticServerListTab, rows, float, 23)
- ATTRIB(XonoticServerListTab, columns, float, 6.5)
+ ATTRIB(XonoticServerListTab, intendedWidth, float, 0.9);
+ ATTRIB(XonoticServerListTab, rows, float, 23);
+ ATTRIB(XonoticServerListTab, columns, float, 6.5);
ENDCLASS(XonoticServerListTab)
entity makeXonoticServerListTab();
void XonoticServerInfoDialog_loadServerInfo(entity me, float i)
{
bool pure_available;
- float m, pure_violations, freeslots, j, numh, maxp, numb, sflags;
+ float m, pure_violations, freeslots, numh, maxp, numb, sflags;
string s, typestr, versionstr, k, v, modname;
// ====================================
freeslots = -1;
sflags = -1;
modname = "";
- for(j = 2; j < m; ++j)
+ for(int j = 2; j < m; ++j)
{
if(argv(j) == "")
break;
if(s != "data")
modname = sprintf("%s (%s)", modname, s);
- j = MapInfo_Type_FromString(typestr); // try and get the real name of the game type
+ Gametype j = MapInfo_Type_FromString(typestr); // try and get the real name of the game type
if(j) { typestr = MapInfo_Type_ToText(j); } // only set it if we actually found it
me.currentServerType = strzone(typestr);
CLASS(XonoticServerInfoDialog, XonoticDialog)
METHOD(XonoticServerInfoDialog, fill, void(entity));
METHOD(XonoticServerInfoDialog, loadServerInfo, void(entity, float));
- ATTRIB(XonoticServerInfoDialog, title, string, _("Server Information"))
- ATTRIB(XonoticServerInfoDialog, color, vector, SKINCOLOR_DIALOG_SERVERINFO)
- ATTRIB(XonoticServerInfoDialog, intendedWidth, float, 0.8)
- ATTRIB(XonoticServerInfoDialog, rows, float, 18)
- ATTRIB(XonoticServerInfoDialog, columns, float, 6.2)
+ ATTRIB(XonoticServerInfoDialog, title, string, _("Server Information"));
+ ATTRIB(XonoticServerInfoDialog, color, vector, SKINCOLOR_DIALOG_SERVERINFO);
+ ATTRIB(XonoticServerInfoDialog, intendedWidth, float, 0.8);
+ ATTRIB(XonoticServerInfoDialog, rows, float, 18);
+ ATTRIB(XonoticServerInfoDialog, columns, float, 6.2);
- ATTRIB(XonoticServerInfoDialog, currentServerName, string, string_null)
- ATTRIB(XonoticServerInfoDialog, currentServerCName, string, string_null)
- ATTRIB(XonoticServerInfoDialog, currentServerType, string, string_null)
- ATTRIB(XonoticServerInfoDialog, currentServerMap, string, string_null)
- ATTRIB(XonoticServerInfoDialog, currentServerPlayers, string, string_null)
- ATTRIB(XonoticServerInfoDialog, currentServerNumPlayers, string, string_null)
- ATTRIB(XonoticServerInfoDialog, currentServerNumBots, string, string_null)
- ATTRIB(XonoticServerInfoDialog, currentServerNumFreeSlots, string, string_null)
- ATTRIB(XonoticServerInfoDialog, currentServerMod, string, string_null)
- ATTRIB(XonoticServerInfoDialog, currentServerVersion, string, string_null)
- ATTRIB(XonoticServerInfoDialog, currentServerKey, string, string_null)
- ATTRIB(XonoticServerInfoDialog, currentServerID, string, string_null)
- ATTRIB(XonoticServerInfoDialog, currentServerEncrypt, string, string_null)
- ATTRIB(XonoticServerInfoDialog, currentServerPure, string, string_null)
+ ATTRIB(XonoticServerInfoDialog, currentServerName, string);
+ ATTRIB(XonoticServerInfoDialog, currentServerCName, string);
+ ATTRIB(XonoticServerInfoDialog, currentServerType, string);
+ ATTRIB(XonoticServerInfoDialog, currentServerMap, string);
+ ATTRIB(XonoticServerInfoDialog, currentServerPlayers, string);
+ ATTRIB(XonoticServerInfoDialog, currentServerNumPlayers, string);
+ ATTRIB(XonoticServerInfoDialog, currentServerNumBots, string);
+ ATTRIB(XonoticServerInfoDialog, currentServerNumFreeSlots, string);
+ ATTRIB(XonoticServerInfoDialog, currentServerMod, string);
+ ATTRIB(XonoticServerInfoDialog, currentServerVersion, string);
+ ATTRIB(XonoticServerInfoDialog, currentServerKey, string);
+ ATTRIB(XonoticServerInfoDialog, currentServerID, string);
+ ATTRIB(XonoticServerInfoDialog, currentServerEncrypt, string);
+ ATTRIB(XonoticServerInfoDialog, currentServerPure, string);
- ATTRIB(XonoticServerInfoDialog, nameLabel, entity, NULL)
- ATTRIB(XonoticServerInfoDialog, cnameLabel, entity, NULL)
- ATTRIB(XonoticServerInfoDialog, typeLabel, entity, NULL)
- ATTRIB(XonoticServerInfoDialog, mapLabel, entity, NULL)
- ATTRIB(XonoticServerInfoDialog, rawPlayerList, entity, NULL)
- ATTRIB(XonoticServerInfoDialog, numPlayersLabel, entity, NULL)
- ATTRIB(XonoticServerInfoDialog, numBotsLabel, entity, NULL)
- ATTRIB(XonoticServerInfoDialog, numFreeSlotsLabel, entity, NULL)
- ATTRIB(XonoticServerInfoDialog, modLabel, entity, NULL)
- ATTRIB(XonoticServerInfoDialog, versionLabel, entity, NULL)
- ATTRIB(XonoticServerInfoDialog, keyLabel, entity, NULL)
- ATTRIB(XonoticServerInfoDialog, idLabel, entity, NULL)
- ATTRIB(XonoticServerInfoDialog, encryptLabel, entity, NULL)
- ATTRIB(XonoticServerInfoDialog, canConnectLabel, entity, NULL)
- ATTRIB(XonoticServerInfoDialog, pureLabel, entity, NULL)
+ ATTRIB(XonoticServerInfoDialog, nameLabel, entity);
+ ATTRIB(XonoticServerInfoDialog, cnameLabel, entity);
+ ATTRIB(XonoticServerInfoDialog, typeLabel, entity);
+ ATTRIB(XonoticServerInfoDialog, mapLabel, entity);
+ ATTRIB(XonoticServerInfoDialog, rawPlayerList, entity);
+ ATTRIB(XonoticServerInfoDialog, numPlayersLabel, entity);
+ ATTRIB(XonoticServerInfoDialog, numBotsLabel, entity);
+ ATTRIB(XonoticServerInfoDialog, numFreeSlotsLabel, entity);
+ ATTRIB(XonoticServerInfoDialog, modLabel, entity);
+ ATTRIB(XonoticServerInfoDialog, versionLabel, entity);
+ ATTRIB(XonoticServerInfoDialog, keyLabel, entity);
+ ATTRIB(XonoticServerInfoDialog, idLabel, entity);
+ ATTRIB(XonoticServerInfoDialog, encryptLabel, entity);
+ ATTRIB(XonoticServerInfoDialog, canConnectLabel, entity);
+ ATTRIB(XonoticServerInfoDialog, pureLabel, entity);
ENDCLASS(XonoticServerInfoDialog)
void Join_Click(entity btn, entity me);
#include "tab.qh"
CLASS(XonoticMediaTab, XonoticTab)
METHOD(XonoticMediaTab, fill, void(entity));
- ATTRIB(XonoticMediaTab, intendedWidth, float, 0.9)
- ATTRIB(XonoticMediaTab, rows, float, 23)
- ATTRIB(XonoticMediaTab, columns, float, 3)
- ATTRIB(XonoticMediaTab, name, string, "Media")
+ ATTRIB(XonoticMediaTab, intendedWidth, float, 0.9);
+ ATTRIB(XonoticMediaTab, rows, float, 23);
+ ATTRIB(XonoticMediaTab, columns, float, 3);
+ ATTRIB(XonoticMediaTab, name, string, "Media");
ENDCLASS(XonoticMediaTab)
entity makeXonoticMediaTab();
#include "tab.qh"
CLASS(XonoticDemoBrowserTab, XonoticTab)
METHOD(XonoticDemoBrowserTab, fill, void(entity));
- ATTRIB(XonoticDemoBrowserTab, intendedWidth, float, 0.9)
- ATTRIB(XonoticDemoBrowserTab, rows, float, 21)
- ATTRIB(XonoticDemoBrowserTab, columns, float, 6.5)
- ATTRIB(XonoticDemoBrowserTab, name, string, "DemoBrowser")
- ATTRIB(XonoticDemoBrowserTab, democlicktype, float, 0)
+ ATTRIB(XonoticDemoBrowserTab, intendedWidth, float, 0.9);
+ ATTRIB(XonoticDemoBrowserTab, rows, float, 21);
+ ATTRIB(XonoticDemoBrowserTab, columns, float, 6.5);
+ ATTRIB(XonoticDemoBrowserTab, name, string, "DemoBrowser");
+ ATTRIB(XonoticDemoBrowserTab, democlicktype, float, 0);
ENDCLASS(XonoticDemoBrowserTab)
entity makeXonoticDemoBrowserTab();
#include "dialog.qh"
CLASS(XonoticDemoStartConfirmDialog, XonoticDialog)
METHOD(XonoticDemoStartConfirmDialog, fill, void(entity));
- ATTRIB(XonoticDemoStartConfirmDialog, title, string, _("Disconnect"))
- ATTRIB(XonoticDemoStartConfirmDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM)
- ATTRIB(XonoticDemoStartConfirmDialog, intendedWidth, float, 0.5)
- ATTRIB(XonoticDemoStartConfirmDialog, rows, float, 4)
- ATTRIB(XonoticDemoStartConfirmDialog, columns, float, 2)
+ ATTRIB(XonoticDemoStartConfirmDialog, title, string, _("Disconnect"));
+ ATTRIB(XonoticDemoStartConfirmDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM);
+ ATTRIB(XonoticDemoStartConfirmDialog, intendedWidth, float, 0.5);
+ ATTRIB(XonoticDemoStartConfirmDialog, rows, float, 4);
+ ATTRIB(XonoticDemoStartConfirmDialog, columns, float, 2);
ENDCLASS(XonoticDemoStartConfirmDialog)
#include "dialog.qh"
CLASS(XonoticDemoTimeConfirmDialog, XonoticDialog)
METHOD(XonoticDemoTimeConfirmDialog, fill, void(entity));
- ATTRIB(XonoticDemoTimeConfirmDialog, title, string, _("Disconnect"))
- ATTRIB(XonoticDemoTimeConfirmDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM)
- ATTRIB(XonoticDemoTimeConfirmDialog, intendedWidth, float, 0.5)
- ATTRIB(XonoticDemoTimeConfirmDialog, rows, float, 4)
- ATTRIB(XonoticDemoTimeConfirmDialog, columns, float, 2)
+ ATTRIB(XonoticDemoTimeConfirmDialog, title, string, _("Disconnect"));
+ ATTRIB(XonoticDemoTimeConfirmDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM);
+ ATTRIB(XonoticDemoTimeConfirmDialog, intendedWidth, float, 0.5);
+ ATTRIB(XonoticDemoTimeConfirmDialog, rows, float, 4);
+ ATTRIB(XonoticDemoTimeConfirmDialog, columns, float, 2);
ENDCLASS(XonoticDemoTimeConfirmDialog)
#include "tab.qh"
CLASS(XonoticMusicPlayerTab, XonoticTab)
METHOD(XonoticMusicPlayerTab, fill, void(entity));
- ATTRIB(XonoticMusicPlayerTab, intendedWidth, float, 0.9)
- ATTRIB(XonoticMusicPlayerTab, rows, float, 21)
- ATTRIB(XonoticMusicPlayerTab, columns, float, 6.5)
- ATTRIB(XonoticMusicPlayerTab, name, string, "MusicPlayer")
+ ATTRIB(XonoticMusicPlayerTab, intendedWidth, float, 0.9);
+ ATTRIB(XonoticMusicPlayerTab, rows, float, 21);
+ ATTRIB(XonoticMusicPlayerTab, columns, float, 6.5);
+ ATTRIB(XonoticMusicPlayerTab, name, string, "MusicPlayer");
ENDCLASS(XonoticMusicPlayerTab)
entity makeXonoticMusicPlayerTab();
#include "tab.qh"
CLASS(XonoticScreenshotBrowserTab, XonoticTab)
METHOD(XonoticScreenshotBrowserTab, fill, void(entity));
- ATTRIB(XonoticScreenshotBrowserTab, intendedWidth, float, 1)
- ATTRIB(XonoticScreenshotBrowserTab, rows, float, 21)
- ATTRIB(XonoticScreenshotBrowserTab, columns, float, 6.5)
- ATTRIB(XonoticScreenshotBrowserTab, name, string, "ScreenshotBrowser")
+ ATTRIB(XonoticScreenshotBrowserTab, intendedWidth, float, 1);
+ ATTRIB(XonoticScreenshotBrowserTab, rows, float, 21);
+ ATTRIB(XonoticScreenshotBrowserTab, columns, float, 6.5);
+ ATTRIB(XonoticScreenshotBrowserTab, name, string, "ScreenshotBrowser");
METHOD(XonoticScreenshotBrowserTab, loadPreviewScreenshot, void(entity, string));
- ATTRIB(XonoticScreenshotBrowserTab, screenshotImage, entity, NULL)
- ATTRIB(XonoticScreenshotBrowserTab, currentScrPath, string, string_null)
+ ATTRIB(XonoticScreenshotBrowserTab, screenshotImage, entity);
+ ATTRIB(XonoticScreenshotBrowserTab, currentScrPath, string);
ENDCLASS(XonoticScreenshotBrowserTab)
entity makeXonoticScreenshotBrowserTab();
METHOD(XonoticScreenshotViewerDialog, keyDown, float(entity, float, float, float));
METHOD(XonoticScreenshotViewerDialog, loadScreenshot, void(entity, string));
METHOD(XonoticScreenshotViewerDialog, close, void(entity));
- ATTRIB(XonoticScreenshotViewerDialog, title, string, "Screenshot Viewer")
- ATTRIB(XonoticScreenshotViewerDialog, name, string, "ScreenshotViewer")
- ATTRIB(XonoticScreenshotViewerDialog, intendedWidth, float, 1)
- ATTRIB(XonoticScreenshotViewerDialog, rows, float, 25)
- ATTRIB(XonoticScreenshotViewerDialog, columns, float, 4)
- ATTRIB(XonoticScreenshotViewerDialog, color, vector, SKINCOLOR_DIALOG_SCREENSHOTVIEWER)
- ATTRIB(XonoticScreenshotViewerDialog, scrList, entity, NULL)
- ATTRIB(XonoticScreenshotViewerDialog, screenshotImage, entity, NULL)
- ATTRIB(XonoticScreenshotViewerDialog, slideShowButton, entity, NULL)
- ATTRIB(XonoticScreenshotViewerDialog, currentScrPath, string, string_null)
+ ATTRIB(XonoticScreenshotViewerDialog, title, string, "Screenshot Viewer");
+ ATTRIB(XonoticScreenshotViewerDialog, name, string, "ScreenshotViewer");
+ ATTRIB(XonoticScreenshotViewerDialog, intendedWidth, float, 1);
+ ATTRIB(XonoticScreenshotViewerDialog, rows, float, 25);
+ ATTRIB(XonoticScreenshotViewerDialog, columns, float, 4);
+ ATTRIB(XonoticScreenshotViewerDialog, color, vector, SKINCOLOR_DIALOG_SCREENSHOTVIEWER);
+ ATTRIB(XonoticScreenshotViewerDialog, scrList, entity);
+ ATTRIB(XonoticScreenshotViewerDialog, screenshotImage, entity);
+ ATTRIB(XonoticScreenshotViewerDialog, slideShowButton, entity);
+ ATTRIB(XonoticScreenshotViewerDialog, currentScrPath, string);
ENDCLASS(XonoticScreenshotViewerDialog)
CLASS(XonoticProfileTab, XonoticTab)
METHOD(XonoticProfileTab, fill, void(entity));
METHOD(XonoticProfileTab, draw, void(entity));
- ATTRIB(XonoticProfileTab, intendedWidth, float, 0.9)
- ATTRIB(XonoticProfileTab, rows, float, 23)
- ATTRIB(XonoticProfileTab, columns, float, 6.1) // added extra .2 for center space
- ATTRIB(XonoticProfileTab, playerNameLabel, entity, NULL)
- ATTRIB(XonoticProfileTab, playerNameLabelAlpha, float, SKINALPHA_HEADER)
+ ATTRIB(XonoticProfileTab, intendedWidth, float, 0.9);
+ ATTRIB(XonoticProfileTab, rows, float, 23);
+ ATTRIB(XonoticProfileTab, columns, float, 6.1); // added extra .2 for center space
+ ATTRIB(XonoticProfileTab, playerNameLabel, entity);
+ ATTRIB(XonoticProfileTab, playerNameLabelAlpha, float, SKINALPHA_HEADER);
ENDCLASS(XonoticProfileTab)
entity makeXonoticProfileTab();
#include "dialog.qh"
CLASS(XonoticQuitDialog, XonoticDialog)
METHOD(XonoticQuitDialog, fill, void(entity));
- ATTRIB(XonoticQuitDialog, title, string, _("Quit"))
- ATTRIB(XonoticQuitDialog, tooltip, string, _("Quit the game"))
- ATTRIB(XonoticQuitDialog, color, vector, SKINCOLOR_DIALOG_QUIT)
- ATTRIB(XonoticQuitDialog, intendedWidth, float, 0.5)
- ATTRIB(XonoticQuitDialog, rows, float, 3)
- ATTRIB(XonoticQuitDialog, columns, float, 2)
- ATTRIB(XonoticQuitDialog, name, string, "Quit")
+ ATTRIB(XonoticQuitDialog, title, string, _("Quit"));
+ ATTRIB(XonoticQuitDialog, tooltip, string, _("Quit the game"));
+ ATTRIB(XonoticQuitDialog, color, vector, SKINCOLOR_DIALOG_QUIT);
+ ATTRIB(XonoticQuitDialog, intendedWidth, float, 0.5);
+ ATTRIB(XonoticQuitDialog, rows, float, 3);
+ ATTRIB(XonoticQuitDialog, columns, float, 2);
+ ATTRIB(XonoticQuitDialog, name, string, "Quit");
ENDCLASS(XonoticQuitDialog)
#include "rootdialog.qh"
CLASS(XonoticSandboxToolsDialog, XonoticRootDialog)
METHOD(XonoticSandboxToolsDialog, fill, void(entity));
- ATTRIB(XonoticSandboxToolsDialog, title, string, _("Sandbox Tools"))
- ATTRIB(XonoticSandboxToolsDialog, color, vector, SKINCOLOR_DIALOG_SANDBOXTOOLS)
- ATTRIB(XonoticSandboxToolsDialog, intendedWidth, float, 0.8)
- ATTRIB(XonoticSandboxToolsDialog, rows, float, 16)
- ATTRIB(XonoticSandboxToolsDialog, columns, float, 4)
- ATTRIB(XonoticSandboxToolsDialog, name, string, "SandboxTools")
- ATTRIB(XonoticSandboxToolsDialog, requiresConnection, float, true)
+ ATTRIB(XonoticSandboxToolsDialog, title, string, _("Sandbox Tools"));
+ ATTRIB(XonoticSandboxToolsDialog, color, vector, SKINCOLOR_DIALOG_SANDBOXTOOLS);
+ ATTRIB(XonoticSandboxToolsDialog, intendedWidth, float, 0.8);
+ ATTRIB(XonoticSandboxToolsDialog, rows, float, 16);
+ ATTRIB(XonoticSandboxToolsDialog, columns, float, 4);
+ ATTRIB(XonoticSandboxToolsDialog, name, string, "SandboxTools");
+ ATTRIB(XonoticSandboxToolsDialog, requiresConnection, float, true);
ENDCLASS(XonoticSandboxToolsDialog)
#include "dialog.qh"
CLASS(XonoticSettingsDialog, XonoticDialog)
METHOD(XonoticSettingsDialog, fill, void(entity));
- ATTRIB(XonoticSettingsDialog, title, string, _("Settings"))
- ATTRIB(XonoticSettingsDialog, tooltip, string, _("Change the game settings"))
- ATTRIB(XonoticSettingsDialog, color, vector, SKINCOLOR_DIALOG_SETTINGS)
- ATTRIB(XonoticSettingsDialog, intendedWidth, float, 0.96)
- ATTRIB(XonoticSettingsDialog, rows, float, 18)
- ATTRIB(XonoticSettingsDialog, columns, float, 6)
+ ATTRIB(XonoticSettingsDialog, title, string, _("Settings"));
+ ATTRIB(XonoticSettingsDialog, tooltip, string, _("Change the game settings"));
+ ATTRIB(XonoticSettingsDialog, color, vector, SKINCOLOR_DIALOG_SETTINGS);
+ ATTRIB(XonoticSettingsDialog, intendedWidth, float, 0.96);
+ ATTRIB(XonoticSettingsDialog, rows, float, 18);
+ ATTRIB(XonoticSettingsDialog, columns, float, 6);
ENDCLASS(XonoticSettingsDialog)
#include "tab.qh"
CLASS(XonoticAudioSettingsTab, XonoticTab)
METHOD(XonoticAudioSettingsTab, fill, void(entity));
- ATTRIB(XonoticAudioSettingsTab, intendedWidth, float, 0.9)
- ATTRIB(XonoticAudioSettingsTab, rows, float, 15.5)
- ATTRIB(XonoticAudioSettingsTab, columns, float, 6.2) // added extra .2 for center space
- ATTRIB(XonoticAudioSettingsTab, hiddenMenuSoundsSlider, entity, NULL)
+ ATTRIB(XonoticAudioSettingsTab, intendedWidth, float, 0.9);
+ ATTRIB(XonoticAudioSettingsTab, rows, float, 15.5);
+ ATTRIB(XonoticAudioSettingsTab, columns, float, 6.2); // added extra .2 for center space
+ ATTRIB(XonoticAudioSettingsTab, hiddenMenuSoundsSlider, entity);
ENDCLASS(XonoticAudioSettingsTab)
entity makeXonoticAudioSettingsTab();
#include "tab.qh"
CLASS(XonoticEffectsSettingsTab, XonoticTab)
METHOD(XonoticEffectsSettingsTab, fill, void(entity));
- ATTRIB(XonoticEffectsSettingsTab, intendedWidth, float, 0.9)
- ATTRIB(XonoticEffectsSettingsTab, rows, float, 15.5)
- ATTRIB(XonoticEffectsSettingsTab, columns, float, 6.2) // added extra .2 for center space
+ ATTRIB(XonoticEffectsSettingsTab, intendedWidth, float, 0.9);
+ ATTRIB(XonoticEffectsSettingsTab, rows, float, 15.5);
+ ATTRIB(XonoticEffectsSettingsTab, columns, float, 6.2); // added extra .2 for center space
ENDCLASS(XonoticEffectsSettingsTab)
entity makeXonoticEffectsSettingsTab();
#include "listbox.qh"
CLASS(XonoticRegisteredSettingsList, XonoticListBox)
- ATTRIB(XonoticRegisteredSettingsList, alphaBG, float, 0)
- ATTRIB(XonoticRegisteredSettingsList, itemAbsSize, vector, '0 0 0')
- ATTRIB(XonoticRegisteredSettingsList, origin, vector, '0 0 0')
- ATTRIB(XonoticRegisteredSettingsList, realFontSize, vector, '0 0 0')
- ATTRIB(XonoticRegisteredSettingsList, realUpperMargin, float, 0)
- ATTRIB(XonoticRegisteredSettingsList, rowsPerItem, float, 2)
- ATTRIB(XonoticRegisteredSettingsList, stringFilterBox, entity, NULL)
- ATTRIB(XonoticRegisteredSettingsList, stringFilter, string, string_null)
- ATTRIB(XonoticRegisteredSettingsList, typeToSearchString, string, string_null)
- ATTRIB(XonoticRegisteredSettingsList, typeToSearchTime, float, 0)
- ATTRIB(XonoticRegisteredSettingsList, source, DataSource, NULL)
- ATTRIB(XonoticRegisteredSettingsList, onChange, void(entity, entity), func_null)
- ATTRIB(XonoticRegisteredSettingsList, onChangeEntity, entity, NULL)
+ ATTRIB(XonoticRegisteredSettingsList, alphaBG, float, 0);
+ ATTRIB(XonoticRegisteredSettingsList, itemAbsSize, vector, '0 0 0');
+ ATTRIB(XonoticRegisteredSettingsList, origin, vector, '0 0 0');
+ ATTRIB(XonoticRegisteredSettingsList, realFontSize, vector, '0 0 0');
+ ATTRIB(XonoticRegisteredSettingsList, realUpperMargin, float, 0);
+ ATTRIB(XonoticRegisteredSettingsList, rowsPerItem, float, 2);
+ ATTRIB(XonoticRegisteredSettingsList, stringFilterBox, entity);
+ ATTRIB(XonoticRegisteredSettingsList, stringFilter, string);
+ ATTRIB(XonoticRegisteredSettingsList, typeToSearchString, string);
+ ATTRIB(XonoticRegisteredSettingsList, typeToSearchTime, float, 0);
+ ATTRIB(XonoticRegisteredSettingsList, source, DataSource);
+ ATTRIB(XonoticRegisteredSettingsList, onChange, void(entity, entity));
+ ATTRIB(XonoticRegisteredSettingsList, onChangeEntity, entity);
METHOD(XonoticRegisteredSettingsList, focusedItemChangeNotify, void(entity));
METHOD(XonoticRegisteredSettingsList, drawListBoxItem, void(entity this, int i, vector absSize, bool isSelected, bool isFocused));
METHOD(XonoticRegisteredSettingsList, focusedItemChangeNotify, void(entity this));
#include "tab.qh"
CLASS(XonoticGameSettingsTab, XonoticTab)
- ATTRIB(XonoticGameSettingsTab, intendedWidth, float, 0.9)
- ATTRIB(XonoticGameSettingsTab, rows, float, 15.5)
- ATTRIB(XonoticGameSettingsTab, columns, float, 6.5)
- ATTRIB(XonoticGameSettingsTab, source, DataSource, NEW(SettingSource))
- ATTRIB(XonoticGameSettingsTab, topicList, entity, NEW(XonoticRegisteredSettingsList, this.source))
- ATTRIB(XonoticGameSettingsTab, currentPanel, entity, NEW(XonoticTab))
- ATTRIB(XonoticGameSettingsTab, currentItem, entity, NULL)
+ ATTRIB(XonoticGameSettingsTab, intendedWidth, float, 0.9);
+ ATTRIB(XonoticGameSettingsTab, rows, float, 15.5);
+ ATTRIB(XonoticGameSettingsTab, columns, float, 6.5);
+ ATTRIB(XonoticGameSettingsTab, source, DataSource, NEW(SettingSource));
+ ATTRIB(XonoticGameSettingsTab, topicList, entity, NEW(XonoticRegisteredSettingsList, this.source));
+ ATTRIB(XonoticGameSettingsTab, currentPanel, entity, NEW(XonoticTab));
+ ATTRIB(XonoticGameSettingsTab, currentItem, entity);
METHOD(XonoticGameSettingsTab, topicChangeNotify, void(entity, entity this));
METHOD(XonoticGameSettingsTab, fill, void(entity this));
INIT(XonoticGameSettingsTab)
CLASS(XonoticGameCrosshairSettingsTab, XonoticTab)
METHOD(XonoticGameCrosshairSettingsTab, fill, void(entity));
METHOD(XonoticGameCrosshairSettingsTab, showNotify, void(entity));
- ATTRIB(XonoticGameCrosshairSettingsTab, title, string, _("Crosshair"))
- ATTRIB(XonoticGameCrosshairSettingsTab, intendedWidth, float, 0.9)
- ATTRIB(XonoticGameCrosshairSettingsTab, rows, float, 15.5)
- ATTRIB(XonoticGameCrosshairSettingsTab, columns, float, 6.2)
+ ATTRIB(XonoticGameCrosshairSettingsTab, title, string, _("Crosshair"));
+ ATTRIB(XonoticGameCrosshairSettingsTab, intendedWidth, float, 0.9);
+ ATTRIB(XonoticGameCrosshairSettingsTab, rows, float, 15.5);
+ ATTRIB(XonoticGameCrosshairSettingsTab, columns, float, 6.2);
ENDCLASS(XonoticGameCrosshairSettingsTab)
entity makeXonoticGameCrosshairSettingsTab();
me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Scoreboard")));
me.TR(me);
me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Alpha:")));
- me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.05, "scoreboard_alpha_bg"));
+ me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.05, "hud_panel_scoreboard_bg_alpha"));
me.TR(me);
me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Fading speed:")));
me.TD(me, 1, 2, e = makeXonoticScoreboardFadeTimeSlider());
me.TR(me);
- me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Side padding:")));
- me.TD(me, 1, 2, e = makeXonoticSlider(0.05, 0.3, 0.01, "scoreboard_offset_left"));
- makeMulti(e, "scoreboard_offset_right");
+ me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "hud_panel_scoreboard_table_highlight", _("Enable rows / columns highlighting")));
me.TR(me);
//me.TR(me);
- me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "scoreboard_respawntime_decimals", _("Show decimals in respawn countdown")));
+ me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "hud_panel_scoreboard_respawntime_decimals", _("Show decimals in respawn countdown")));
me.TR(me);
- me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "scoreboard_accuracy", _("Show accuracy underneath scoreboard")));
+ me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "hud_panel_scoreboard_accuracy", _("Show accuracy underneath scoreboard")));
me.TR(me);
me.TR(me);
CLASS(XonoticGameHUDSettingsTab, XonoticTab)
METHOD(XonoticGameHUDSettingsTab, fill, void(entity));
METHOD(XonoticGameHUDSettingsTab, showNotify, void(entity));
- ATTRIB(XonoticGameHUDSettingsTab, title, string, _("HUD"))
- ATTRIB(XonoticGameHUDSettingsTab, intendedWidth, float, 0.9)
- ATTRIB(XonoticGameHUDSettingsTab, rows, float, 15.5)
- ATTRIB(XonoticGameHUDSettingsTab, columns, float, 6.2)
+ ATTRIB(XonoticGameHUDSettingsTab, title, string, _("HUD"));
+ ATTRIB(XonoticGameHUDSettingsTab, intendedWidth, float, 0.9);
+ ATTRIB(XonoticGameHUDSettingsTab, rows, float, 15.5);
+ ATTRIB(XonoticGameHUDSettingsTab, columns, float, 6.2);
ENDCLASS(XonoticGameHUDSettingsTab)
entity makeXonoticGameHUDSettingsTab();
void HUDSetup_Start(entity me, entity btn);
#include "dialog.qh"
CLASS(XonoticHUDConfirmDialog, XonoticDialog)
METHOD(XonoticHUDConfirmDialog, fill, void(entity));
- ATTRIB(XonoticHUDConfirmDialog, title, string, _("Enter HUD editor"))
- ATTRIB(XonoticHUDConfirmDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM)
- ATTRIB(XonoticHUDConfirmDialog, intendedWidth, float, 0.5)
- ATTRIB(XonoticHUDConfirmDialog, rows, float, 4)
- ATTRIB(XonoticHUDConfirmDialog, columns, float, 2)
+ ATTRIB(XonoticHUDConfirmDialog, title, string, _("Enter HUD editor"));
+ ATTRIB(XonoticHUDConfirmDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM);
+ ATTRIB(XonoticHUDConfirmDialog, intendedWidth, float, 0.5);
+ ATTRIB(XonoticHUDConfirmDialog, rows, float, 4);
+ ATTRIB(XonoticHUDConfirmDialog, columns, float, 2);
ENDCLASS(XonoticHUDConfirmDialog)
CLASS(XonoticGameMessageSettingsTab, XonoticTab)
METHOD(XonoticGameMessageSettingsTab, fill, void(entity));
METHOD(XonoticGameMessageSettingsTab, showNotify, void(entity));
- ATTRIB(XonoticGameMessageSettingsTab, title, string, _("Messages"))
- ATTRIB(XonoticGameMessageSettingsTab, intendedWidth, float, 0.9)
- ATTRIB(XonoticGameMessageSettingsTab, rows, float, 15.5)
- ATTRIB(XonoticGameMessageSettingsTab, columns, float, 6)
- ATTRIB(XonoticGameMessageSettingsTab, weaponsList, entity, NULL)
+ ATTRIB(XonoticGameMessageSettingsTab, title, string, _("Messages"));
+ ATTRIB(XonoticGameMessageSettingsTab, intendedWidth, float, 0.9);
+ ATTRIB(XonoticGameMessageSettingsTab, rows, float, 15.5);
+ ATTRIB(XonoticGameMessageSettingsTab, columns, float, 6);
+ ATTRIB(XonoticGameMessageSettingsTab, weaponsList, entity);
ENDCLASS(XonoticGameMessageSettingsTab)
entity makeXonoticGameMessageSettingsTab();
#include "../gamesettings.qh"
CLASS(XonoticGameModelSettingsTab, XonoticTab)
METHOD(XonoticGameModelSettingsTab, fill, void(entity));
METHOD(XonoticGameModelSettingsTab, showNotify, void(entity));
- ATTRIB(XonoticGameModelSettingsTab, title, string, _("Models"))
- ATTRIB(XonoticGameModelSettingsTab, titleTooltip, string, _("Customize how players and items are displayed in game"))
- ATTRIB(XonoticGameModelSettingsTab, intendedWidth, float, 0.9)
- ATTRIB(XonoticGameModelSettingsTab, rows, float, 15.5)
- ATTRIB(XonoticGameModelSettingsTab, columns, float, 5)
+ ATTRIB(XonoticGameModelSettingsTab, title, string, _("Models"));
+ ATTRIB(XonoticGameModelSettingsTab, titleTooltip, string, _("Customize how players and items are displayed in game"));
+ ATTRIB(XonoticGameModelSettingsTab, intendedWidth, float, 0.9);
+ ATTRIB(XonoticGameModelSettingsTab, rows, float, 15.5);
+ ATTRIB(XonoticGameModelSettingsTab, columns, float, 5);
ENDCLASS(XonoticGameModelSettingsTab)
entity makeXonoticGameModelSettingsTab();
#include "../gamesettings.qh"
CLASS(XonoticGameViewSettingsTab, XonoticTab)
METHOD(XonoticGameViewSettingsTab, fill, void(entity));
METHOD(XonoticGameViewSettingsTab, showNotify, void(entity));
- ATTRIB(XonoticGameViewSettingsTab, title, string, _("View"))
- ATTRIB(XonoticGameViewSettingsTab, intendedWidth, float, 0.9)
- ATTRIB(XonoticGameViewSettingsTab, rows, float, 15.5)
- ATTRIB(XonoticGameViewSettingsTab, columns, float, 6.2)
+ ATTRIB(XonoticGameViewSettingsTab, title, string, _("View"));
+ ATTRIB(XonoticGameViewSettingsTab, intendedWidth, float, 0.9);
+ ATTRIB(XonoticGameViewSettingsTab, rows, float, 15.5);
+ ATTRIB(XonoticGameViewSettingsTab, columns, float, 6.2);
ENDCLASS(XonoticGameViewSettingsTab)
entity makeXonoticGameViewSettingsTab();
#include "../gamesettings.qh"
CLASS(XonoticGameWeaponsSettingsTab, XonoticTab)
METHOD(XonoticGameWeaponsSettingsTab, fill, void(entity));
METHOD(XonoticGameWeaponsSettingsTab, showNotify, void(entity));
- ATTRIB(XonoticGameWeaponsSettingsTab, title, string, _("Weapons"))
- ATTRIB(XonoticGameWeaponsSettingsTab, intendedWidth, float, 0.9)
- ATTRIB(XonoticGameWeaponsSettingsTab, rows, float, 15.5)
- ATTRIB(XonoticGameWeaponsSettingsTab, columns, float, 6)
- ATTRIB(XonoticGameWeaponsSettingsTab, weaponsList, entity, NULL)
+ ATTRIB(XonoticGameWeaponsSettingsTab, title, string, _("Weapons"));
+ ATTRIB(XonoticGameWeaponsSettingsTab, intendedWidth, float, 0.9);
+ ATTRIB(XonoticGameWeaponsSettingsTab, rows, float, 15.5);
+ ATTRIB(XonoticGameWeaponsSettingsTab, columns, float, 6);
+ ATTRIB(XonoticGameWeaponsSettingsTab, weaponsList, entity);
ENDCLASS(XonoticGameWeaponsSettingsTab)
entity makeXonoticGameWeaponsSettingsTab();
#include "../gamesettings.qh"
#include "tab.qh"
CLASS(XonoticInputSettingsTab, XonoticTab)
METHOD(XonoticInputSettingsTab, fill, void(entity));
- ATTRIB(XonoticInputSettingsTab, intendedWidth, float, 0.9)
- ATTRIB(XonoticInputSettingsTab, rows, float, 15.5)
- ATTRIB(XonoticInputSettingsTab, columns, float, 6.2) // added extra .2 for center space
+ ATTRIB(XonoticInputSettingsTab, intendedWidth, float, 0.9);
+ ATTRIB(XonoticInputSettingsTab, rows, float, 15.5);
+ ATTRIB(XonoticInputSettingsTab, columns, float, 6.2); // added extra .2 for center space
ENDCLASS(XonoticInputSettingsTab)
entity makeXonoticInputSettingsTab();
CLASS(XonoticUserbindEditDialog, XonoticDialog)
METHOD(XonoticUserbindEditDialog, loadUserBind, void(entity, string, string, string));
METHOD(XonoticUserbindEditDialog, fill, void(entity));
- ATTRIB(XonoticUserbindEditDialog, title, string, _("User defined key bind"))
- ATTRIB(XonoticUserbindEditDialog, color, vector, SKINCOLOR_DIALOG_USERBIND)
- ATTRIB(XonoticUserbindEditDialog, intendedWidth, float, 0.7)
- ATTRIB(XonoticUserbindEditDialog, rows, float, 4)
- ATTRIB(XonoticUserbindEditDialog, columns, float, 3)
- ATTRIB(XonoticUserbindEditDialog, keybindBox, entity, NULL)
+ ATTRIB(XonoticUserbindEditDialog, title, string, _("User defined key bind"));
+ ATTRIB(XonoticUserbindEditDialog, color, vector, SKINCOLOR_DIALOG_USERBIND);
+ ATTRIB(XonoticUserbindEditDialog, intendedWidth, float, 0.7);
+ ATTRIB(XonoticUserbindEditDialog, rows, float, 4);
+ ATTRIB(XonoticUserbindEditDialog, columns, float, 3);
+ ATTRIB(XonoticUserbindEditDialog, keybindBox, entity);
- ATTRIB(XonoticUserbindEditDialog, nameBox, entity, NULL)
- ATTRIB(XonoticUserbindEditDialog, commandPressBox, entity, NULL)
- ATTRIB(XonoticUserbindEditDialog, commandReleaseBox, entity, NULL)
+ ATTRIB(XonoticUserbindEditDialog, nameBox, entity);
+ ATTRIB(XonoticUserbindEditDialog, commandPressBox, entity);
+ ATTRIB(XonoticUserbindEditDialog, commandReleaseBox, entity);
ENDCLASS(XonoticUserbindEditDialog)
#include "tab.qh"
CLASS(XonoticMiscSettingsTab, XonoticTab)
METHOD(XonoticMiscSettingsTab, fill, void(entity));
- ATTRIB(XonoticMiscSettingsTab, intendedWidth, float, 0.9)
- ATTRIB(XonoticMiscSettingsTab, rows, float, 15.5)
- ATTRIB(XonoticMiscSettingsTab, columns, float, 6.2)
+ ATTRIB(XonoticMiscSettingsTab, intendedWidth, float, 0.9);
+ ATTRIB(XonoticMiscSettingsTab, rows, float, 15.5);
+ ATTRIB(XonoticMiscSettingsTab, columns, float, 6.2);
ENDCLASS(XonoticMiscSettingsTab)
entity makeXonoticMiscSettingsTab();
CLASS(XonoticCvarsDialog, XonoticDialog)
METHOD(XonoticCvarsDialog, fill, void(entity));
METHOD(XonoticCvarsDialog, showNotify, void(entity));
- ATTRIB(XonoticCvarsDialog, title, string, _("Advanced settings"))
- ATTRIB(XonoticCvarsDialog, color, vector, SKINCOLOR_DIALOG_CVARS)
- ATTRIB(XonoticCvarsDialog, intendedWidth, float, 0.8)
- ATTRIB(XonoticCvarsDialog, rows, float, 24)
- ATTRIB(XonoticCvarsDialog, columns, float, 6)
+ ATTRIB(XonoticCvarsDialog, title, string, _("Advanced settings"));
+ ATTRIB(XonoticCvarsDialog, color, vector, SKINCOLOR_DIALOG_CVARS);
+ ATTRIB(XonoticCvarsDialog, intendedWidth, float, 0.8);
+ ATTRIB(XonoticCvarsDialog, rows, float, 24);
+ ATTRIB(XonoticCvarsDialog, columns, float, 6);
ENDCLASS(XonoticCvarsDialog)
#include "dialog.qh"
CLASS(XonoticResetDialog, XonoticDialog)
METHOD(XonoticResetDialog, fill, void(entity));
- ATTRIB(XonoticResetDialog, title, string, _("Factory reset"))
- ATTRIB(XonoticResetDialog, color, vector, SKINCOLOR_DIALOG_QUIT)
- ATTRIB(XonoticResetDialog, intendedWidth, float, 0.5)
- ATTRIB(XonoticResetDialog, rows, float, 4)
- ATTRIB(XonoticResetDialog, columns, float, 2)
- ATTRIB(XonoticResetDialog, name, string, "Factory reset")
+ ATTRIB(XonoticResetDialog, title, string, _("Factory reset"));
+ ATTRIB(XonoticResetDialog, color, vector, SKINCOLOR_DIALOG_QUIT);
+ ATTRIB(XonoticResetDialog, intendedWidth, float, 0.5);
+ ATTRIB(XonoticResetDialog, rows, float, 4);
+ ATTRIB(XonoticResetDialog, columns, float, 2);
+ ATTRIB(XonoticResetDialog, name, string, "Factory reset");
ENDCLASS(XonoticResetDialog)
#include "tab.qh"
CLASS(XonoticUserSettingsTab, XonoticTab)
METHOD(XonoticUserSettingsTab, fill, void(entity));
- ATTRIB(XonoticUserSettingsTab, intendedWidth, float, 0.9)
- ATTRIB(XonoticUserSettingsTab, rows, float, 15.5)
- ATTRIB(XonoticUserSettingsTab, columns, float, 6)
+ ATTRIB(XonoticUserSettingsTab, intendedWidth, float, 0.9);
+ ATTRIB(XonoticUserSettingsTab, rows, float, 15.5);
+ ATTRIB(XonoticUserSettingsTab, columns, float, 6);
ENDCLASS(XonoticUserSettingsTab)
entity makeXonoticUserSettingsTab();
#include "dialog.qh"
CLASS(XonoticLanguageWarningDialog, XonoticDialog)
METHOD(XonoticLanguageWarningDialog, fill, void(entity));
- ATTRIB(XonoticLanguageWarningDialog, title, string, _("Warning"))
- ATTRIB(XonoticLanguageWarningDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM)
- ATTRIB(XonoticLanguageWarningDialog, intendedWidth, float, 0.6)
- ATTRIB(XonoticLanguageWarningDialog, rows, float, 5)
- ATTRIB(XonoticLanguageWarningDialog, columns, float, 4)
+ ATTRIB(XonoticLanguageWarningDialog, title, string, _("Warning"));
+ ATTRIB(XonoticLanguageWarningDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM);
+ ATTRIB(XonoticLanguageWarningDialog, intendedWidth, float, 0.6);
+ ATTRIB(XonoticLanguageWarningDialog, rows, float, 5);
+ ATTRIB(XonoticLanguageWarningDialog, columns, float, 4);
ENDCLASS(XonoticLanguageWarningDialog)
#include "tab.qh"
CLASS(XonoticVideoSettingsTab, XonoticTab)
METHOD(XonoticVideoSettingsTab, fill, void(entity));
- ATTRIB(XonoticVideoSettingsTab, intendedWidth, float, 0.9)
- ATTRIB(XonoticVideoSettingsTab, rows, float, 15.5)
- ATTRIB(XonoticVideoSettingsTab, columns, float, 6.2) // added extra .2 for center space
- ATTRIB(XonoticVideoSettingsTab, name, string, "videosettings")
+ ATTRIB(XonoticVideoSettingsTab, intendedWidth, float, 0.9);
+ ATTRIB(XonoticVideoSettingsTab, rows, float, 15.5);
+ ATTRIB(XonoticVideoSettingsTab, columns, float, 6.2); // added extra .2 for center space
+ ATTRIB(XonoticVideoSettingsTab, name, string, "videosettings");
ENDCLASS(XonoticVideoSettingsTab)
entity makeXonoticVideoSettingsTab();
#include "dialog.qh"
CLASS(XonoticSingleplayerDialog, XonoticDialog)
METHOD(XonoticSingleplayerDialog, fill, void(entity));
- ATTRIB(XonoticSingleplayerDialog, title, string, _("Singleplayer"))
- ATTRIB(XonoticSingleplayerDialog, tooltip, string, _("Play the singleplayer campaign or instant action matches against bots"))
- ATTRIB(XonoticSingleplayerDialog, color, vector, SKINCOLOR_DIALOG_SINGLEPLAYER)
- ATTRIB(XonoticSingleplayerDialog, intendedWidth, float, 0.80)
- ATTRIB(XonoticSingleplayerDialog, rows, float, 24)
- ATTRIB(XonoticSingleplayerDialog, columns, float, 5)
- ATTRIB(XonoticSingleplayerDialog, campaignBox, entity, NULL)
+ ATTRIB(XonoticSingleplayerDialog, title, string, _("Singleplayer"));
+ ATTRIB(XonoticSingleplayerDialog, tooltip, string, _("Play the singleplayer campaign or instant action matches against bots"));
+ ATTRIB(XonoticSingleplayerDialog, color, vector, SKINCOLOR_DIALOG_SINGLEPLAYER);
+ ATTRIB(XonoticSingleplayerDialog, intendedWidth, float, 0.80);
+ ATTRIB(XonoticSingleplayerDialog, rows, float, 24);
+ ATTRIB(XonoticSingleplayerDialog, columns, float, 5);
+ ATTRIB(XonoticSingleplayerDialog, campaignBox, entity);
ENDCLASS(XonoticSingleplayerDialog)
CLASS(XonoticWinnerDialog, XonoticDialog)
METHOD(XonoticWinnerDialog, fill, void(entity));
METHOD(XonoticWinnerDialog, focusEnter, void(entity));
- ATTRIB(XonoticWinnerDialog, title, string, _("Winner"))
- ATTRIB(XonoticWinnerDialog, color, vector, SKINCOLOR_DIALOG_SINGLEPLAYER)
- ATTRIB(XonoticWinnerDialog, intendedWidth, float, 0.32)
- ATTRIB(XonoticWinnerDialog, rows, float, 12)
- ATTRIB(XonoticWinnerDialog, columns, float, 3)
+ ATTRIB(XonoticWinnerDialog, title, string, _("Winner"));
+ ATTRIB(XonoticWinnerDialog, color, vector, SKINCOLOR_DIALOG_SINGLEPLAYER);
+ ATTRIB(XonoticWinnerDialog, intendedWidth, float, 0.32);
+ ATTRIB(XonoticWinnerDialog, rows, float, 12);
+ ATTRIB(XonoticWinnerDialog, columns, float, 3);
ENDCLASS(XonoticWinnerDialog)
CLASS(XonoticTeamSelectDialog, XonoticRootDialog)
METHOD(XonoticTeamSelectDialog, fill, void(entity));
METHOD(XonoticTeamSelectDialog, showNotify, void(entity));
- ATTRIB(XonoticTeamSelectDialog, title, string, _("Team Selection"))
- ATTRIB(XonoticTeamSelectDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
- ATTRIB(XonoticTeamSelectDialog, intendedWidth, float, 0.4)
- ATTRIB(XonoticTeamSelectDialog, rows, float, 5)
- ATTRIB(XonoticTeamSelectDialog, columns, float, 4)
- ATTRIB(XonoticTeamSelectDialog, name, string, "TeamSelect")
- ATTRIB(XonoticTeamSelectDialog, team1, entity, NULL)
- ATTRIB(XonoticTeamSelectDialog, team2, entity, NULL)
- ATTRIB(XonoticTeamSelectDialog, team3, entity, NULL)
- ATTRIB(XonoticTeamSelectDialog, team4, entity, NULL)
- ATTRIB(XonoticTeamSelectDialog, requiresConnection, float, true)
+ ATTRIB(XonoticTeamSelectDialog, title, string, _("Team Selection"));
+ ATTRIB(XonoticTeamSelectDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
+ ATTRIB(XonoticTeamSelectDialog, intendedWidth, float, 0.4);
+ ATTRIB(XonoticTeamSelectDialog, rows, float, 5);
+ ATTRIB(XonoticTeamSelectDialog, columns, float, 4);
+ ATTRIB(XonoticTeamSelectDialog, name, string, "TeamSelect");
+ ATTRIB(XonoticTeamSelectDialog, team1, entity);
+ ATTRIB(XonoticTeamSelectDialog, team2, entity);
+ ATTRIB(XonoticTeamSelectDialog, team3, entity);
+ ATTRIB(XonoticTeamSelectDialog, team4, entity);
+ ATTRIB(XonoticTeamSelectDialog, requiresConnection, float, true);
ENDCLASS(XonoticTeamSelectDialog)
#include "rootdialog.qh"
CLASS(XonoticUid2NameDialog, XonoticRootDialog)
METHOD(XonoticUid2NameDialog, fill, void(entity));
- ATTRIB(XonoticUid2NameDialog, title, string, string_null)
- ATTRIB(XonoticUid2NameDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
- ATTRIB(XonoticUid2NameDialog, intendedWidth, float, 0.5)
- ATTRIB(XonoticUid2NameDialog, rows, float, 4)
- ATTRIB(XonoticUid2NameDialog, columns, float, 2)
- ATTRIB(XonoticUid2NameDialog, name, string, "Uid2Name")
- ATTRIB(XonoticUid2NameDialog, closable, float, 0)
+ ATTRIB(XonoticUid2NameDialog, title, string);
+ ATTRIB(XonoticUid2NameDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
+ ATTRIB(XonoticUid2NameDialog, intendedWidth, float, 0.5);
+ ATTRIB(XonoticUid2NameDialog, rows, float, 4);
+ ATTRIB(XonoticUid2NameDialog, columns, float, 2);
+ ATTRIB(XonoticUid2NameDialog, name, string, "Uid2Name");
+ ATTRIB(XonoticUid2NameDialog, closable, float, 0);
ENDCLASS(XonoticUid2NameDialog)
}
void XonoticGametypeList_loadCvars(entity me)
{
- float t;
- t = MapInfo_CurrentGametype();
+ Gametype t = MapInfo_CurrentGametype();
float i;
for(i = 0; i < GameType_GetCount(); ++i)
if(t == GameType_GetID(i))
}
void XonoticGametypeList_saveCvars(entity me)
{
- int t = GameType_GetID(me.selectedItem);
+ Gametype t = GameType_GetID(me.selectedItem);
if (t == MapInfo_CurrentGametype()) {
return;
}
#include "listbox.qh"
CLASS(XonoticGametypeList, XonoticListBox)
METHOD(XonoticGametypeList, configureXonoticGametypeList, void(entity));
- ATTRIB(XonoticGametypeList, rowsPerItem, float, 2)
+ ATTRIB(XonoticGametypeList, rowsPerItem, float, 2);
METHOD(XonoticGametypeList, draw, void(entity));
METHOD(XonoticGametypeList, drawListBoxItem, void(entity, int, vector, bool, bool));
METHOD(XonoticGametypeList, resizeNotify, void(entity, vector, vector, vector, vector));
METHOD(XonoticGametypeList, clickListBoxItem, void(entity, float, vector));
METHOD(XonoticGametypeList, focusedItemChangeNotify, void(entity));
- ATTRIB(XonoticGametypeList, realFontSize, vector, '0 0 0')
- ATTRIB(XonoticGametypeList, realUpperMargin, float, 0)
- ATTRIB(XonoticGametypeList, columnIconOrigin, float, 0)
- ATTRIB(XonoticGametypeList, columnIconSize, float, 0)
- ATTRIB(XonoticGametypeList, columnNameOrigin, float, 0)
- ATTRIB(XonoticGametypeList, columnNameSize, float, 0)
+ ATTRIB(XonoticGametypeList, realFontSize, vector, '0 0 0');
+ ATTRIB(XonoticGametypeList, realUpperMargin, float, 0);
+ ATTRIB(XonoticGametypeList, columnIconOrigin, float, 0);
+ ATTRIB(XonoticGametypeList, columnIconSize, float, 0);
+ ATTRIB(XonoticGametypeList, columnNameOrigin, float, 0);
+ ATTRIB(XonoticGametypeList, columnNameSize, float, 0);
ENDCLASS(XonoticGametypeList)
entity makeXonoticGametypeList();
#include "listbox.qh"
CLASS(XonoticHUDSkinList, XonoticListBox)
METHOD(XonoticHUDSkinList, configureXonoticHUDSkinList, void(entity));
- ATTRIB(XonoticHUDSkinList, rowsPerItem, float, 1)
+ ATTRIB(XonoticHUDSkinList, rowsPerItem, float, 1);
METHOD(XonoticHUDSkinList, resizeNotify, void(entity, vector, vector, vector, vector));
METHOD(XonoticHUDSkinList, draw, void(entity));
METHOD(XonoticHUDSkinList, drawListBoxItem, void(entity, int, vector, bool, bool));
METHOD(XonoticHUDSkinList, destroy, void(entity));
METHOD(XonoticHUDSkinList, showNotify, void(entity));
- ATTRIB(XonoticHUDSkinList, listHUDSkin, float, -1)
- ATTRIB(XonoticHUDSkinList, realFontSize, vector, '0 0 0')
- ATTRIB(XonoticHUDSkinList, columnNameOrigin, float, 0)
- ATTRIB(XonoticHUDSkinList, columnNameSize, float, 0)
- ATTRIB(XonoticHUDSkinList, realUpperMargin, float, 0)
- ATTRIB(XonoticHUDSkinList, origin, vector, '0 0 0')
- ATTRIB(XonoticHUDSkinList, itemAbsSize, vector, '0 0 0')
+ ATTRIB(XonoticHUDSkinList, listHUDSkin, float, -1);
+ ATTRIB(XonoticHUDSkinList, realFontSize, vector, '0 0 0');
+ ATTRIB(XonoticHUDSkinList, columnNameOrigin, float, 0);
+ ATTRIB(XonoticHUDSkinList, columnNameSize, float, 0);
+ ATTRIB(XonoticHUDSkinList, realUpperMargin, float, 0);
+ ATTRIB(XonoticHUDSkinList, origin, vector, '0 0 0');
+ ATTRIB(XonoticHUDSkinList, itemAbsSize, vector, '0 0 0');
- ATTRIB(XonoticHUDSkinList, filterString, string, string_null)
- ATTRIB(XonoticHUDSkinList, delayedRefreshTime, float, 0)
- ATTRIB(XonoticHUDSkinList, savedName, string, string_null)
+ ATTRIB(XonoticHUDSkinList, filterString, string);
+ ATTRIB(XonoticHUDSkinList, delayedRefreshTime, float, 0);
+ ATTRIB(XonoticHUDSkinList, savedName, string);
ENDCLASS(XonoticHUDSkinList)
entity hudskinlist;
entity makeXonoticHUDSkinList();
METHOD(XonoticInputBox, focusLeave, void(entity));
METHOD(XonoticInputBox, setText, void(entity, string));
METHOD(XonoticInputBox, keyDown, float(entity, float, float, float));
- ATTRIB(XonoticInputBox, fontSize, float, SKINFONTSIZE_NORMAL)
- ATTRIB(XonoticInputBox, image, string, SKINGFX_INPUTBOX)
- ATTRIB(XonoticInputBox, onChange, void(entity, entity), func_null)
- ATTRIB(XonoticInputBox, onChangeEntity, entity, NULL)
- ATTRIB(XonoticInputBox, onEnter, void(entity, entity), func_null)
- ATTRIB(XonoticInputBox, onEnterEntity, entity, NULL)
- ATTRIB(XonoticInputBox, marginLeft, float, SKINMARGIN_INPUTBOX_CHARS)
- ATTRIB(XonoticInputBox, marginRight, float, SKINMARGIN_INPUTBOX_CHARS)
- ATTRIB(XonoticInputBox, color, vector, SKINCOLOR_INPUTBOX_N)
- ATTRIB(XonoticInputBox, colorF, vector, SKINCOLOR_INPUTBOX_F)
+ ATTRIB(XonoticInputBox, fontSize, float, SKINFONTSIZE_NORMAL);
+ ATTRIB(XonoticInputBox, image, string, SKINGFX_INPUTBOX);
+ ATTRIB(XonoticInputBox, onChange, void(entity, entity));
+ ATTRIB(XonoticInputBox, onChangeEntity, entity);
+ ATTRIB(XonoticInputBox, onEnter, void(entity, entity));
+ ATTRIB(XonoticInputBox, onEnterEntity, entity);
+ ATTRIB(XonoticInputBox, marginLeft, float, SKINMARGIN_INPUTBOX_CHARS);
+ ATTRIB(XonoticInputBox, marginRight, float, SKINMARGIN_INPUTBOX_CHARS);
+ ATTRIB(XonoticInputBox, color, vector, SKINCOLOR_INPUTBOX_N);
+ ATTRIB(XonoticInputBox, colorF, vector, SKINCOLOR_INPUTBOX_F);
- ATTRIB(XonoticInputBox, alpha, float, SKINALPHA_TEXT)
+ ATTRIB(XonoticInputBox, alpha, float, SKINALPHA_TEXT);
// Clear button attributes
- ATTRIB(XonoticInputBox, cb_offset, float, SKINOFFSET_CLEARBUTTON) // bound to range -1, 0
- ATTRIB(XonoticInputBox, cb_src, string, SKINGFX_CLEARBUTTON)
- ATTRIB(XonoticInputBox, cb_color, vector, SKINCOLOR_CLEARBUTTON_N)
- ATTRIB(XonoticInputBox, cb_colorF, vector, SKINCOLOR_CLEARBUTTON_F)
- ATTRIB(XonoticInputBox, cb_colorC, vector, SKINCOLOR_CLEARBUTTON_C)
+ ATTRIB(XonoticInputBox, cb_offset, float, SKINOFFSET_CLEARBUTTON); // bound to range -1, 0
+ ATTRIB(XonoticInputBox, cb_src, string, SKINGFX_CLEARBUTTON);
+ ATTRIB(XonoticInputBox, cb_color, vector, SKINCOLOR_CLEARBUTTON_N);
+ ATTRIB(XonoticInputBox, cb_colorF, vector, SKINCOLOR_CLEARBUTTON_F);
+ ATTRIB(XonoticInputBox, cb_colorC, vector, SKINCOLOR_CLEARBUTTON_C);
- ATTRIB(XonoticInputBox, cvarName, string, string_null)
+ ATTRIB(XonoticInputBox, cvarName, string);
METHOD(XonoticInputBox, loadCvars, void(entity));
METHOD(XonoticInputBox, saveCvars, void(entity));
- ATTRIB(XonoticInputBox, sendCvars, float, 0)
+ ATTRIB(XonoticInputBox, sendCvars, float, 0);
- ATTRIB(XonoticInputBox, saveImmediately, float, 0)
+ ATTRIB(XonoticInputBox, saveImmediately, float, 0);
ENDCLASS(XonoticInputBox)
entity makeXonoticInputBox_T(float, string, string theTooltip);
entity makeXonoticInputBox(float, string);
KEYBIND_DEF("+fire2" , _("secondary fire"));
KEYBIND_DEF("" , "");
KEYBIND_DEF("" , _("Weapon switching"));
- KEYBIND_DEF("weapprev" , _("previous"));
- KEYBIND_DEF("weapnext" , _("next"));
- KEYBIND_DEF("weaplast" , _("previously used"));
- KEYBIND_DEF("weapbest" , _("best"));
+ KEYBIND_DEF("weapprev" , CTX(_("WEAPON^previous")));
+ KEYBIND_DEF("weapnext" , CTX(_("WEAPON^next")));
+ KEYBIND_DEF("weaplast" , CTX(_("WEAPON^previously used")));
+ KEYBIND_DEF("weapbest" , CTX(_("WEAPON^best")));
KEYBIND_DEF("reload" , _("reload"));
int i;
#include "listbox.qh"
CLASS(XonoticKeyBinder, XonoticListBox)
METHOD(XonoticKeyBinder, configureXonoticKeyBinder, void(entity));
- ATTRIB(XonoticKeyBinder, rowsPerItem, int, 1)
+ ATTRIB(XonoticKeyBinder, rowsPerItem, int, 1);
METHOD(XonoticKeyBinder, drawListBoxItem, void(entity, int, vector, bool, bool));
METHOD(XonoticKeyBinder, doubleClickListBoxItem, void(entity, float, vector));
METHOD(XonoticKeyBinder, resizeNotify, void(entity, vector, vector, vector, vector));
METHOD(XonoticKeyBinder, keyGrabbed, void(entity, float, float));
METHOD(XonoticKeyBinder, destroy, void(entity));
- ATTRIB(XonoticKeyBinder, realFontSize, vector, '0 0 0')
- ATTRIB(XonoticKeyBinder, realUpperMargin, float, 0)
- ATTRIB(XonoticKeyBinder, columnFunctionOrigin, float, 0)
- ATTRIB(XonoticKeyBinder, columnFunctionSize, float, 0)
- ATTRIB(XonoticKeyBinder, columnKeysOrigin, float, 0)
- ATTRIB(XonoticKeyBinder, columnKeysSize, float, 0)
+ ATTRIB(XonoticKeyBinder, realFontSize, vector, '0 0 0');
+ ATTRIB(XonoticKeyBinder, realUpperMargin, float, 0);
+ ATTRIB(XonoticKeyBinder, columnFunctionOrigin, float, 0);
+ ATTRIB(XonoticKeyBinder, columnFunctionSize, float, 0);
+ ATTRIB(XonoticKeyBinder, columnKeysOrigin, float, 0);
+ ATTRIB(XonoticKeyBinder, columnKeysSize, float, 0);
METHOD(XonoticKeyBinder, loadKeyBinds, void(entity));
- ATTRIB(XonoticKeyBinder, previouslySelected, int, -1)
- ATTRIB(XonoticKeyBinder, inMouseHandler, float, 0)
- ATTRIB(XonoticKeyBinder, userbindEditButton, entity, NULL)
- ATTRIB(XonoticKeyBinder, keyGrabButton, entity, NULL)
- ATTRIB(XonoticKeyBinder, clearButton, entity, NULL)
- ATTRIB(XonoticKeyBinder, userbindEditDialog, entity, NULL)
+ ATTRIB(XonoticKeyBinder, previouslySelected, int, -1);
+ ATTRIB(XonoticKeyBinder, inMouseHandler, float, 0);
+ ATTRIB(XonoticKeyBinder, userbindEditButton, entity);
+ ATTRIB(XonoticKeyBinder, keyGrabButton, entity);
+ ATTRIB(XonoticKeyBinder, clearButton, entity);
+ ATTRIB(XonoticKeyBinder, userbindEditDialog, entity);
METHOD(XonoticKeyBinder, editUserbind, void(entity, string, string, string));
ENDCLASS(XonoticKeyBinder)
entity makeXonoticKeyBinder();
#include "listbox.qh"
CLASS(XonoticLanguageList, XonoticListBox)
METHOD(XonoticLanguageList, configureXonoticLanguageList, void(entity));
- ATTRIB(XonoticLanguageList, rowsPerItem, float, 1)
+ ATTRIB(XonoticLanguageList, rowsPerItem, float, 1);
METHOD(XonoticLanguageList, drawListBoxItem, void(entity, int, vector, bool, bool));
METHOD(XonoticLanguageList, resizeNotify, void(entity, vector, vector, vector, vector));
METHOD(XonoticLanguageList, setSelected, void(entity, float));
METHOD(XonoticLanguageList, loadCvars, void(entity));
METHOD(XonoticLanguageList, saveCvars, void(entity));
- ATTRIB(XonoticLanguageList, realFontSize, vector, '0 0 0')
- ATTRIB(XonoticLanguageList, realUpperMargin, float, 0)
- ATTRIB(XonoticLanguageList, columnNameOrigin, float, 0)
- ATTRIB(XonoticLanguageList, columnNameSize, float, 0)
- ATTRIB(XonoticLanguageList, columnPercentageOrigin, float, 0)
- ATTRIB(XonoticLanguageList, columnPercentageSize, float, 0)
+ ATTRIB(XonoticLanguageList, realFontSize, vector, '0 0 0');
+ ATTRIB(XonoticLanguageList, realUpperMargin, float, 0);
+ ATTRIB(XonoticLanguageList, columnNameOrigin, float, 0);
+ ATTRIB(XonoticLanguageList, columnNameSize, float, 0);
+ ATTRIB(XonoticLanguageList, columnPercentageOrigin, float, 0);
+ ATTRIB(XonoticLanguageList, columnPercentageSize, float, 0);
METHOD(XonoticLanguageList, doubleClickListBoxItem, void(entity, float, vector));
METHOD(XonoticLanguageList, keyDown, float(entity, float, float, float)); // enter handling
METHOD(XonoticLanguageList, destroy, void(entity));
- ATTRIB(XonoticLanguageList, languagelist, float, -1)
+ ATTRIB(XonoticLanguageList, languagelist, float, -1);
METHOD(XonoticLanguageList, getLanguages, void(entity));
METHOD(XonoticLanguageList, setLanguage, void(entity));
METHOD(XonoticLanguageList, languageParameter, string(entity, float, float));
- ATTRIB(XonoticLanguageList, name, string, "languageselector") // change this to make it noninteractive (for first run dialog)
+ ATTRIB(XonoticLanguageList, name, string, "languageselector"); // change this to make it noninteractive (for first run dialog);
ENDCLASS(XonoticLanguageList)
entity makeXonoticLanguageList();
#include "../item/listbox.qh"
CLASS(XonoticListBox, ListBox)
METHOD(XonoticListBox, configureXonoticListBox, void(entity));
- ATTRIB(XonoticListBox, fontSize, float, SKINFONTSIZE_NORMAL)
- ATTRIB(XonoticListBox, scrollbarWidth, float, SKINWIDTH_SCROLLBAR)
- ATTRIB(XonoticListBox, src, string, SKINGFX_SCROLLBAR)
- ATTRIB(XonoticListBox, tolerance, vector, SKINTOLERANCE_SLIDER)
- ATTRIB(XonoticListBox, rowsPerItem, float, 1)
+ ATTRIB(XonoticListBox, fontSize, float, SKINFONTSIZE_NORMAL);
+ ATTRIB(XonoticListBox, scrollbarWidth, float, SKINWIDTH_SCROLLBAR);
+ ATTRIB(XonoticListBox, src, string, SKINGFX_SCROLLBAR);
+ ATTRIB(XonoticListBox, tolerance, vector, SKINTOLERANCE_SLIDER);
+ ATTRIB(XonoticListBox, rowsPerItem, float, 1);
METHOD(XonoticListBox, resizeNotify, void(entity, vector, vector, vector, vector));
- ATTRIB(XonoticListBox, color, vector, SKINCOLOR_SCROLLBAR_N)
- ATTRIB(XonoticListBox, colorF, vector, SKINCOLOR_SCROLLBAR_F)
- ATTRIB(XonoticListBox, color2, vector, SKINCOLOR_SCROLLBAR_S)
- ATTRIB(XonoticListBox, colorC, vector, SKINCOLOR_SCROLLBAR_C)
- ATTRIB(XonoticListBox, colorBG, vector, SKINCOLOR_LISTBOX_BACKGROUND)
- ATTRIB(XonoticListBox, alphaBG, float, SKINALPHA_LISTBOX_BACKGROUND)
+ ATTRIB(XonoticListBox, color, vector, SKINCOLOR_SCROLLBAR_N);
+ ATTRIB(XonoticListBox, colorF, vector, SKINCOLOR_SCROLLBAR_F);
+ ATTRIB(XonoticListBox, color2, vector, SKINCOLOR_SCROLLBAR_S);
+ ATTRIB(XonoticListBox, colorC, vector, SKINCOLOR_SCROLLBAR_C);
+ ATTRIB(XonoticListBox, colorBG, vector, SKINCOLOR_LISTBOX_BACKGROUND);
+ ATTRIB(XonoticListBox, alphaBG, float, SKINALPHA_LISTBOX_BACKGROUND);
ENDCLASS(XonoticListBox)
entity makeXonoticListBox();
CLASS(MainWindow, ModalController)
METHOD(MainWindow, configureMainWindow, void(entity));
METHOD(MainWindow, draw, void(entity));
- ATTRIB(MainWindow, firstRunDialog, entity, NULL)
- ATTRIB(MainWindow, advancedDialog, entity, NULL)
- ATTRIB(MainWindow, mutatorsDialog, entity, NULL)
- ATTRIB(MainWindow, mapInfoDialog, entity, NULL)
- ATTRIB(MainWindow, userbindEditDialog, entity, NULL)
- ATTRIB(MainWindow, winnerDialog, entity, NULL)
- ATTRIB(MainWindow, serverInfoDialog, entity, NULL)
- ATTRIB(MainWindow, cvarsDialog, entity, NULL)
- ATTRIB(MainWindow, screenshotViewerDialog, entity, NULL)
- ATTRIB(MainWindow, viewDialog, entity, NULL)
- ATTRIB(MainWindow, hudconfirmDialog, entity, NULL)
- ATTRIB(MainWindow, languageWarningDialog, entity, NULL)
- ATTRIB(MainWindow, mainNexposee, entity, NULL)
- ATTRIB(MainWindow, fadedAlpha, float, SKINALPHA_BEHIND)
- ATTRIB(MainWindow, dialogToShow, entity, NULL)
- ATTRIB(MainWindow, demostartconfirmDialog, entity, NULL)
- ATTRIB(MainWindow, demotimeconfirmDialog, entity, NULL)
- ATTRIB(MainWindow, resetDialog, entity, NULL)
+ ATTRIB(MainWindow, firstRunDialog, entity);
+ ATTRIB(MainWindow, advancedDialog, entity);
+ ATTRIB(MainWindow, mutatorsDialog, entity);
+ ATTRIB(MainWindow, mapInfoDialog, entity);
+ ATTRIB(MainWindow, userbindEditDialog, entity);
+ ATTRIB(MainWindow, winnerDialog, entity);
+ ATTRIB(MainWindow, serverInfoDialog, entity);
+ ATTRIB(MainWindow, cvarsDialog, entity);
+ ATTRIB(MainWindow, screenshotViewerDialog, entity);
+ ATTRIB(MainWindow, viewDialog, entity);
+ ATTRIB(MainWindow, hudconfirmDialog, entity);
+ ATTRIB(MainWindow, languageWarningDialog, entity);
+ ATTRIB(MainWindow, mainNexposee, entity);
+ ATTRIB(MainWindow, fadedAlpha, float, SKINALPHA_BEHIND);
+ ATTRIB(MainWindow, dialogToShow, entity);
+ ATTRIB(MainWindow, demostartconfirmDialog, entity);
+ ATTRIB(MainWindow, demotimeconfirmDialog, entity);
+ ATTRIB(MainWindow, resetDialog, entity);
ENDCLASS(MainWindow)
{
float i, j, n;
string s;
- float gt, f;
- gt = MapInfo_CurrentGametype();
- f = MapInfo_CurrentFeatures();
+ Gametype gt = MapInfo_CurrentGametype();
+ int f = MapInfo_CurrentFeatures();
MapInfo_FilterGametype(gt, f, MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
if (me.stringFilter)
MapInfo_FilterString(me.stringFilter);
{
float i;
string s;
- MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 0, MapInfo_ForbiddenFlags(), 0); // all
+ _MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 0, MapInfo_ForbiddenFlags(), 0); // all
s = "";
for(i = 0; i < MapInfo_count; ++i)
s = strcat(s, " ", MapInfo_BSPName_ByID(i));
#include "listbox.qh"
CLASS(XonoticMapList, XonoticListBox)
METHOD(XonoticMapList, configureXonoticMapList, void(entity));
- ATTRIB(XonoticMapList, rowsPerItem, float, 4)
+ ATTRIB(XonoticMapList, rowsPerItem, float, 4);
METHOD(XonoticMapList, draw, void(entity));
METHOD(XonoticMapList, drawListBoxItem, void(entity, int, vector, bool, bool));
METHOD(XonoticMapList, clickListBoxItem, void(entity, float, vector));
METHOD(XonoticMapList, refilterCallback, void(entity, entity));
METHOD(XonoticMapList, keyDown, float(entity, float, float, float));
- ATTRIB(XonoticMapList, realFontSize, vector, '0 0 0')
- ATTRIB(XonoticMapList, columnPreviewOrigin, float, 0)
- ATTRIB(XonoticMapList, columnPreviewSize, float, 0)
- ATTRIB(XonoticMapList, columnNameOrigin, float, 0)
- ATTRIB(XonoticMapList, columnNameSize, float, 0)
- ATTRIB(XonoticMapList, checkMarkOrigin, vector, '0 0 0')
- ATTRIB(XonoticMapList, checkMarkSize, vector, '0 0 0')
- ATTRIB(XonoticMapList, realUpperMargin1, float, 0)
- ATTRIB(XonoticMapList, realUpperMargin2, float, 0)
+ ATTRIB(XonoticMapList, realFontSize, vector, '0 0 0');
+ ATTRIB(XonoticMapList, columnPreviewOrigin, float, 0);
+ ATTRIB(XonoticMapList, columnPreviewSize, float, 0);
+ ATTRIB(XonoticMapList, columnNameOrigin, float, 0);
+ ATTRIB(XonoticMapList, columnNameSize, float, 0);
+ ATTRIB(XonoticMapList, checkMarkOrigin, vector, '0 0 0');
+ ATTRIB(XonoticMapList, checkMarkSize, vector, '0 0 0');
+ ATTRIB(XonoticMapList, realUpperMargin1, float, 0);
+ ATTRIB(XonoticMapList, realUpperMargin2, float, 0);
- ATTRIB(XonoticMapList, lastGametype, float, 0)
- ATTRIB(XonoticMapList, lastFeatures, float, 0)
+ ATTRIB(XonoticMapList, lastGametype, entity);
+ ATTRIB(XonoticMapList, lastFeatures, float, 0);
- ATTRIB(XonoticMapList, origin, vector, '0 0 0')
- ATTRIB(XonoticMapList, itemAbsSize, vector, '0 0 0')
+ ATTRIB(XonoticMapList, origin, vector, '0 0 0');
+ ATTRIB(XonoticMapList, itemAbsSize, vector, '0 0 0');
- ATTRIB(XonoticMapList, g_maplistCache, string, string_null)
+ ATTRIB(XonoticMapList, g_maplistCache, string);
METHOD(XonoticMapList, g_maplistCacheToggle, void(entity, float));
METHOD(XonoticMapList, g_maplistCacheQuery, float(entity, float));
- ATTRIB(XonoticMapList, stringFilter, string, string_null)
- ATTRIB(XonoticMapList, stringFilterBox, entity, NULL)
+ ATTRIB(XonoticMapList, stringFilter, string);
+ ATTRIB(XonoticMapList, stringFilterBox, entity);
- ATTRIB(XonoticMapList, startButton, entity, NULL)
+ ATTRIB(XonoticMapList, startButton, entity);
METHOD(XonoticMapList, loadCvars, void(entity));
- ATTRIB(XonoticMapList, typeToSearchString, string, string_null)
- ATTRIB(XonoticMapList, typeToSearchTime, float, 0)
+ ATTRIB(XonoticMapList, typeToSearchString, string);
+ ATTRIB(XonoticMapList, typeToSearchTime, float, 0);
METHOD(XonoticMapList, destroy, void(entity));
- ATTRIB(XonoticMapList, alphaBG, float, 0)
+ ATTRIB(XonoticMapList, alphaBG, float, 0);
ENDCLASS(XonoticMapList)
entity makeXonoticMapList();
void MapList_StringFilterBox_Change(entity box, entity me);
METHOD(XonoticPicker, mouseDrag, float(entity, vector));
METHOD(XonoticPicker, keyDown, float(entity, float, float, float));
METHOD(XonoticPicker, draw, void(entity));
- ATTRIB(XonoticPicker, focusable, float, 1)
- ATTRIB(XonoticPicker, disabled, float, 0)
- ATTRIB(XonoticPicker, alpha, float, 1)
- ATTRIB(XonoticPicker, disabledAlpha, float, SKINALPHA_DISABLED)
+ ATTRIB(XonoticPicker, focusable, float, 1);
+ ATTRIB(XonoticPicker, disabled, float, 0);
+ ATTRIB(XonoticPicker, alpha, float, 1);
+ ATTRIB(XonoticPicker, disabledAlpha, float, SKINALPHA_DISABLED);
- ATTRIB(XonoticPicker, rows, float, 3)
- ATTRIB(XonoticPicker, columns, float, 2)
+ ATTRIB(XonoticPicker, rows, float, 3);
+ ATTRIB(XonoticPicker, columns, float, 2);
METHOD(XonoticPicker, moveFocus, void(entity, vector, vector));
METHOD(XonoticPicker, cellSelect, void(entity, vector));
METHOD(XonoticPicker, cellDraw, void(entity, vector, vector));
METHOD(XonoticPicker, cellIsValid, bool(entity, vector));
- ATTRIB(XonoticPicker, realCellSize, vector, '0 0 0')
- ATTRIB(XonoticPicker, selectedCell, vector, '-1 -1 0')
- ATTRIB(XonoticPicker, focusedCell, vector, '-1 -1 0')
- ATTRIB(XonoticPicker, focusedCellAlpha, float, 0)
- ATTRIB(XonoticPicker, focusedCellTime, float, 0)
- ATTRIB(XonoticPicker, pressedCell, vector, '-1 -1 0')
+ ATTRIB(XonoticPicker, realCellSize, vector, '0 0 0');
+ ATTRIB(XonoticPicker, selectedCell, vector, '-1 -1 0');
+ ATTRIB(XonoticPicker, focusedCell, vector, '-1 -1 0');
+ ATTRIB(XonoticPicker, focusedCellAlpha, float, 0);
+ ATTRIB(XonoticPicker, focusedCellTime, float, 0);
+ ATTRIB(XonoticPicker, pressedCell, vector, '-1 -1 0');
ENDCLASS(XonoticPicker)
entity makeXonoticPicker();
#include "listbox.qh"
CLASS(XonoticPlayerList, XonoticListBox)
- ATTRIB(XonoticPlayerList, rowsPerItem, float, 1)
+ ATTRIB(XonoticPlayerList, rowsPerItem, float, 1);
METHOD(XonoticPlayerList, resizeNotify, void(entity, vector, vector, vector, vector));
METHOD(XonoticPlayerList, drawListBoxItem, void(entity, int, vector, bool, bool));
- ATTRIB(XonoticPlayerList, allowFocusSound, float, 0)
- ATTRIB(XonoticPlayerList, realFontSize, vector, '0 0 0')
- ATTRIB(XonoticPlayerList, columnNameOrigin, float, 0)
- ATTRIB(XonoticPlayerList, columnNameSize, float, 0)
- ATTRIB(XonoticPlayerList, columnScoreOrigin, float, 0)
- ATTRIB(XonoticPlayerList, columnScoreSize, float, 0)
- ATTRIB(XonoticPlayerList, realUpperMargin, float, 0)
- ATTRIB(XonoticPlayerList, origin, vector, '0 0 0')
- ATTRIB(XonoticPlayerList, itemAbsSize, vector, '0 0 0')
+ ATTRIB(XonoticPlayerList, allowFocusSound, float, 0);
+ ATTRIB(XonoticPlayerList, realFontSize, vector, '0 0 0');
+ ATTRIB(XonoticPlayerList, columnNameOrigin, float, 0);
+ ATTRIB(XonoticPlayerList, columnNameSize, float, 0);
+ ATTRIB(XonoticPlayerList, columnScoreOrigin, float, 0);
+ ATTRIB(XonoticPlayerList, columnScoreSize, float, 0);
+ ATTRIB(XonoticPlayerList, realUpperMargin, float, 0);
+ ATTRIB(XonoticPlayerList, origin, vector, '0 0 0');
+ ATTRIB(XonoticPlayerList, itemAbsSize, vector, '0 0 0');
METHOD(XonoticPlayerList, setPlayerList, void(entity, string));
METHOD(XonoticPlayerList, getPlayerList, string(entity, float, float));
- ATTRIB(XonoticPlayerList, playerList, float, -1)
- ATTRIB(XonoticPlayerList, selectionDoesntMatter, bool, true)
+ ATTRIB(XonoticPlayerList, playerList, float, -1);
+ ATTRIB(XonoticPlayerList, selectionDoesntMatter, bool, true);
ENDCLASS(XonoticPlayerList)
entity makeXonoticPlayerList();
METHOD(XonoticPlayerModelSelector, draw, void(entity));
METHOD(XonoticPlayerModelSelector, resizeNotify, void(entity, vector, vector, vector, vector));
METHOD(XonoticPlayerModelSelector, showNotify, void(entity));
- ATTRIB(XonoticPlayerModelSelector, currentModel, string, string_null)
- ATTRIB(XonoticPlayerModelSelector, currentSkin, float, 0)
- ATTRIB(XonoticPlayerModelSelector, currentModelImage, string, string_null)
- ATTRIB(XonoticPlayerModelSelector, currentModelTitle, string, string_null)
- ATTRIB(XonoticPlayerModelSelector, currentModelDescription, string, string_null)
+ ATTRIB(XonoticPlayerModelSelector, currentModel, string);
+ ATTRIB(XonoticPlayerModelSelector, currentSkin, float, 0);
+ ATTRIB(XonoticPlayerModelSelector, currentModelImage, string);
+ ATTRIB(XonoticPlayerModelSelector, currentModelTitle, string);
+ ATTRIB(XonoticPlayerModelSelector, currentModelDescription, string);
METHOD(XonoticPlayerModelSelector, go, void(entity, float));
METHOD(XonoticPlayerModelSelector, destroy, void(entity));
- ATTRIB(XonoticPlayerModelSelector, origin, vector, '0 0 0')
- ATTRIB(XonoticPlayerModelSelector, size, vector, '0 0 0')
- ATTRIB(XonoticPlayerModelSelector, realFontSize, vector, '0 0 0')
- ATTRIB(XonoticPlayerModelSelector, fontSize, float, SKINFONTSIZE_NORMAL)
- ATTRIB(XonoticPlayerModelSelector, titleFontSize, float, SKINFONTSIZE_TITLE)
- ATTRIB(XonoticPlayerModelSelector, bufModels, float, -1)
- ATTRIB(XonoticPlayerModelSelector, numModels, float, -1)
- ATTRIB(XonoticPlayerModelSelector, idxModels, float, -1)
+ ATTRIB(XonoticPlayerModelSelector, origin, vector, '0 0 0');
+ ATTRIB(XonoticPlayerModelSelector, size, vector, '0 0 0');
+ ATTRIB(XonoticPlayerModelSelector, realFontSize, vector, '0 0 0');
+ ATTRIB(XonoticPlayerModelSelector, fontSize, float, SKINFONTSIZE_NORMAL);
+ ATTRIB(XonoticPlayerModelSelector, titleFontSize, float, SKINFONTSIZE_TITLE);
+ ATTRIB(XonoticPlayerModelSelector, bufModels, float, -1);
+ ATTRIB(XonoticPlayerModelSelector, numModels, float, -1);
+ ATTRIB(XonoticPlayerModelSelector, idxModels, float, -1);
ENDCLASS(XonoticPlayerModelSelector)
entity makeXonoticPlayerModelSelector();
void PlayerModelSelector_Next_Click(entity btn, entity me);
#include "listbox.qh"
CLASS(XonoticPlayList, XonoticListBox)
METHOD(XonoticPlayList, configureXonoticPlayList, void(entity));
- ATTRIB(XonoticPlayList, rowsPerItem, float, 1)
+ ATTRIB(XonoticPlayList, rowsPerItem, float, 1);
METHOD(XonoticPlayList, resizeNotify, void(entity, vector, vector, vector, vector));
METHOD(XonoticPlayList, draw, void(entity));
METHOD(XonoticPlayList, drawListBoxItem, void(entity, int, vector, bool, bool));
METHOD(XonoticPlayList, addToPlayList, void(entity, string));
METHOD(XonoticPlayList, removeSelectedFromPlayList, void(entity));
- ATTRIB(XonoticPlayList, playingTrack, float, -1)
+ ATTRIB(XonoticPlayList, playingTrack, float, -1);
- ATTRIB(XonoticPlayList, realFontSize, vector, '0 0 0')
- ATTRIB(XonoticPlayList, columnNameOrigin, float, 0)
- ATTRIB(XonoticPlayList, columnNameSize, float, 0)
- ATTRIB(XonoticPlayList, columnNumberOrigin, float, 0)
- ATTRIB(XonoticPlayList, columnNumberSize, float, 0)
- ATTRIB(XonoticPlayList, realUpperMargin, float, 0)
- ATTRIB(XonoticPlayList, origin, vector, '0 0 0')
- ATTRIB(XonoticPlayList, itemAbsSize, vector, '0 0 0')
+ ATTRIB(XonoticPlayList, realFontSize, vector, '0 0 0');
+ ATTRIB(XonoticPlayList, columnNameOrigin, float, 0);
+ ATTRIB(XonoticPlayList, columnNameSize, float, 0);
+ ATTRIB(XonoticPlayList, columnNumberOrigin, float, 0);
+ ATTRIB(XonoticPlayList, columnNumberSize, float, 0);
+ ATTRIB(XonoticPlayList, realUpperMargin, float, 0);
+ ATTRIB(XonoticPlayList, origin, vector, '0 0 0');
+ ATTRIB(XonoticPlayList, itemAbsSize, vector, '0 0 0');
ENDCLASS(XonoticPlayList)
entity makeXonoticPlayList();
METHOD(XonoticRadioButton, configureXonoticRadioButton, void(entity, float, string, string, string, string));
METHOD(XonoticRadioButton, draw, void(entity));
METHOD(XonoticRadioButton, setChecked, void(entity, float));
- ATTRIB(XonoticRadioButton, fontSize, float, SKINFONTSIZE_NORMAL)
- ATTRIB(XonoticRadioButton, image, string, SKINGFX_RADIOBUTTON)
- ATTRIB(XonoticRadioButton, color, vector, SKINCOLOR_RADIOBUTTON_N)
- ATTRIB(XonoticRadioButton, colorC, vector, SKINCOLOR_RADIOBUTTON_C)
- ATTRIB(XonoticRadioButton, colorF, vector, SKINCOLOR_RADIOBUTTON_F)
- ATTRIB(XonoticRadioButton, colorD, vector, SKINCOLOR_RADIOBUTTON_D)
+ ATTRIB(XonoticRadioButton, fontSize, float, SKINFONTSIZE_NORMAL);
+ ATTRIB(XonoticRadioButton, image, string, SKINGFX_RADIOBUTTON);
+ ATTRIB(XonoticRadioButton, color, vector, SKINCOLOR_RADIOBUTTON_N);
+ ATTRIB(XonoticRadioButton, colorC, vector, SKINCOLOR_RADIOBUTTON_C);
+ ATTRIB(XonoticRadioButton, colorF, vector, SKINCOLOR_RADIOBUTTON_F);
+ ATTRIB(XonoticRadioButton, colorD, vector, SKINCOLOR_RADIOBUTTON_D);
- ATTRIB(XonoticRadioButton, cvarName, string, string_null)
- ATTRIB(XonoticRadioButton, cvarValue, string, string_null)
- ATTRIB(XonoticRadioButton, cvarOffValue, string, string_null)
- ATTRIB(XonoticRadioButton, cvarValueIsAnotherCvar, float, 0)
+ ATTRIB(XonoticRadioButton, cvarName, string);
+ ATTRIB(XonoticRadioButton, cvarValue, string);
+ ATTRIB(XonoticRadioButton, cvarOffValue, string);
+ ATTRIB(XonoticRadioButton, cvarValueIsAnotherCvar, float, 0);
METHOD(XonoticRadioButton, loadCvars, void(entity));
METHOD(XonoticRadioButton, saveCvars, void(entity));
- ATTRIB(XonoticRadioButton, alpha, float, SKINALPHA_TEXT)
- ATTRIB(XonoticRadioButton, disabledAlpha, float, SKINALPHA_DISABLED)
+ ATTRIB(XonoticRadioButton, alpha, float, SKINALPHA_TEXT);
+ ATTRIB(XonoticRadioButton, disabledAlpha, float, SKINALPHA_DISABLED);
ENDCLASS(XonoticRadioButton)
entity makeXonoticRadioButton_T(float, string, string, string, string theTooltip);
entity makeXonoticRadioButton(float, string, string, string);
CLASS(XonoticRootDialog, XonoticDialog)
// still to be customized by user
/*
- ATTRIB(XonoticDialog, closable, float, 1)
- ATTRIB(XonoticDialog, title, string, _("Form1")) // ;)
- ATTRIB(XonoticDialog, color, vector, '1 0.5 1')
- ATTRIB(XonoticDialog, intendedWidth, float, 0)
- ATTRIB(XonoticDialog, rows, float, 3)
- ATTRIB(XonoticDialog, columns, float, 2)
+ ATTRIB(XonoticDialog, closable, float, 1);
+ ATTRIB(XonoticDialog, title, string, _("Form1")); // ;);
+ ATTRIB(XonoticDialog, color, vector, '1 0.5 1');
+ ATTRIB(XonoticDialog, intendedWidth, float, 0);
+ ATTRIB(XonoticDialog, rows, float, 3);
+ ATTRIB(XonoticDialog, columns, float, 2);
*/
METHOD(XonoticRootDialog, close, void(entity));
ENDCLASS(XonoticRootDialog)
METHOD(XonoticScreenshotImage, configureXonoticScreenshotImage, void(entity));
METHOD(XonoticScreenshotImage, load, void(entity, string));
METHOD(XonoticScreenshotImage, draw, void(entity));
- ATTRIB(XonoticScreenshotImage, focusable, float, 1) // mousePress and mouseDrag work only if focusable is set
+ ATTRIB(XonoticScreenshotImage, focusable, float, 1); // mousePress and mouseDrag work only if focusable is set
METHOD(XonoticScreenshotImage, mousePress, float(entity, vector));
METHOD(XonoticScreenshotImage, mouseDrag, float(entity, vector));
METHOD(XonoticScreenshotImage, mouseMove, float(entity, vector));
METHOD(XonoticScreenshotImage, resizeNotify, void(entity, vector, vector, vector, vector));
- ATTRIB(XonoticScreenshotImage, realFontSize, vector, '0 0 0')
- ATTRIB(XonoticScreenshotImage, fontSize, float, SKINFONTSIZE_NORMAL)
- ATTRIB(XonoticScreenshotImage, showTitle, float, 1)
- ATTRIB(XonoticScreenshotImage, screenshotTime, float, 0)
- ATTRIB(XonoticScreenshotImage, screenshotTitle, string, string_null)
+ ATTRIB(XonoticScreenshotImage, realFontSize, vector, '0 0 0');
+ ATTRIB(XonoticScreenshotImage, fontSize, float, SKINFONTSIZE_NORMAL);
+ ATTRIB(XonoticScreenshotImage, showTitle, float, 1);
+ ATTRIB(XonoticScreenshotImage, screenshotTime, float, 0);
+ ATTRIB(XonoticScreenshotImage, screenshotTitle, string);
ENDCLASS(XonoticScreenshotImage)
entity makeXonoticScreenshotImage();
#include "listbox.qh"
CLASS(XonoticScreenshotList, XonoticListBox)
METHOD(XonoticScreenshotList, configureXonoticScreenshotList, void(entity));
- ATTRIB(XonoticScreenshotList, rowsPerItem, float, 1)
+ ATTRIB(XonoticScreenshotList, rowsPerItem, float, 1);
METHOD(XonoticScreenshotList, resizeNotify, void(entity, vector, vector, vector, vector));
METHOD(XonoticScreenshotList, setSelected, void(entity, float));
METHOD(XonoticScreenshotList, draw, void(entity));
METHOD(XonoticScreenshotList, keyDown, float(entity, float, float, float));
METHOD(XonoticScreenshotList, destroy, void(entity));
METHOD(XonoticScreenshotList, showNotify, void(entity));
- ATTRIB(XonoticScreenshotList, listScreenshot, float, -1)
- ATTRIB(XonoticScreenshotList, realFontSize, vector, '0 0 0')
- ATTRIB(XonoticScreenshotList, columnNameOrigin, float, 0)
- ATTRIB(XonoticScreenshotList, columnNameSize, float, 0)
- ATTRIB(XonoticScreenshotList, realUpperMargin, float, 0)
- ATTRIB(XonoticScreenshotList, origin, vector, '0 0 0')
- ATTRIB(XonoticScreenshotList, itemAbsSize, vector, '0 0 0')
- ATTRIB(XonoticScreenshotList, filterString, string, string_null)
- ATTRIB(XonoticScreenshotList, filterBox, entity, NULL)
- ATTRIB(XonoticScreenshotList, filterTime, float, 0)
+ ATTRIB(XonoticScreenshotList, listScreenshot, float, -1);
+ ATTRIB(XonoticScreenshotList, realFontSize, vector, '0 0 0');
+ ATTRIB(XonoticScreenshotList, columnNameOrigin, float, 0);
+ ATTRIB(XonoticScreenshotList, columnNameSize, float, 0);
+ ATTRIB(XonoticScreenshotList, realUpperMargin, float, 0);
+ ATTRIB(XonoticScreenshotList, origin, vector, '0 0 0');
+ ATTRIB(XonoticScreenshotList, itemAbsSize, vector, '0 0 0');
+ ATTRIB(XonoticScreenshotList, filterString, string);
+ ATTRIB(XonoticScreenshotList, filterBox, entity);
+ ATTRIB(XonoticScreenshotList, filterTime, float, 0);
- ATTRIB(XonoticScreenshotList, newScreenshotTime, float, 0)
- ATTRIB(XonoticScreenshotList, newSlideShowScreenshotTime, float, 0)
+ ATTRIB(XonoticScreenshotList, newScreenshotTime, float, 0);
+ ATTRIB(XonoticScreenshotList, newSlideShowScreenshotTime, float, 0);
- ATTRIB(XonoticScreenshotList, screenshotBrowserDialog, entity, NULL)
- ATTRIB(XonoticScreenshotList, screenshotPreview, entity, NULL)
- ATTRIB(XonoticScreenshotList, screenshotViewerDialog, entity, NULL)
+ ATTRIB(XonoticScreenshotList, screenshotBrowserDialog, entity);
+ ATTRIB(XonoticScreenshotList, screenshotPreview, entity);
+ ATTRIB(XonoticScreenshotList, screenshotViewerDialog, entity);
METHOD(XonoticScreenshotList, goScreenshot, void(entity, float));
METHOD(XonoticScreenshotList, startSlideShow, void(entity));
METHOD(XonoticScreenshotList, stopSlideShow, void(entity));
case "cts":
case "xdf": { return CAT_DEFRAG; }
- default: { LOG_TRACEF("Found strange mod type: %s\n", modtype); return CAT_MODIFIED; }
+ default: { LOG_TRACEF("Found strange mod type: %s", modtype); return CAT_MODIFIED; }
}
}
}
void ServerList_TypeSort_Click(entity btn, entity me)
{
- string s, t;
- float i, m;
- s = me.filterString;
- m = strstrofs(s, ":", 0);
+ string s = me.filterString;
+ int m = strstrofs(s, ":", 0);
if(m >= 0)
{
s = substring(s, 0, m);
else
s = "";
- for(i = 1; ; i *= 2) // 20 modes ought to be enough for anyone
- {
- t = MapInfo_Type_ToString(i);
- if(i > 1)
- if(t == "") // it repeats (default case)
- {
- // no type was found
- // choose the first one
- s = MapInfo_Type_ToString(1);
- break;
- }
- if(s == t)
- {
- // the type was found
- // choose the next one
- s = MapInfo_Type_ToString(i * 2);
- if(s == "")
- s = MapInfo_Type_ToString(1);
- break;
- }
+ Gametype first = NULL; FOREACH(Gametypes, !first, first = it; break);
+ bool flag = false;
+ FOREACH(Gametypes, s == MapInfo_Type_ToString(it), {
+ // the type was found
+ // choose the next one
+ flag = true;
+ s = MapInfo_Type_ToString(Gametypes_from(it.m_id + 1));
+ if (s == "") s = MapInfo_Type_ToString(first);
+ break;
+ });
+ if (!flag) {
+ // no type was found
+ // choose the first one
+ s = MapInfo_Type_ToString(first);
}
- if(s != "")
- s = strcat(s, ":");
+ if(s != "") s = strcat(s, ":");
s = strcat(s, substring(me.filterString, m+1, strlen(me.filterString) - m - 1));
me.controlledTextbox.setText(me.controlledTextbox, s);
#include "listbox.qh"
CLASS(XonoticServerList, XonoticListBox)
METHOD(XonoticServerList, configureXonoticServerList, void(entity));
- ATTRIB(XonoticServerList, rowsPerItem, float, 1)
+ ATTRIB(XonoticServerList, rowsPerItem, float, 1);
METHOD(XonoticServerList, draw, void(entity));
METHOD(XonoticServerList, drawListBoxItem, void(entity, int, vector, bool, bool));
METHOD(XonoticServerList, doubleClickListBoxItem, void(entity, float, vector));
METHOD(XonoticServerList, keyDown, float(entity, float, float, float));
METHOD(XonoticServerList, toggleFavorite, void(entity, string));
- ATTRIB(XonoticServerList, iconsSizeFactor, float, 0.85)
+ ATTRIB(XonoticServerList, iconsSizeFactor, float, 0.85);
METHOD(XonoticServerList, mouseMove, float(entity, vector));
- ATTRIB(XonoticServerList, mouseOverIcons, bool, false)
+ ATTRIB(XonoticServerList, mouseOverIcons, bool, false);
METHOD(XonoticServerList, focusedItemChangeNotify, void(entity));
- ATTRIB(XonoticServerList, realFontSize, vector, '0 0 0')
- ATTRIB(XonoticServerList, realUpperMargin, float, 0)
- ATTRIB(XonoticServerList, columnIconsOrigin, float, 0)
- ATTRIB(XonoticServerList, columnIconsSize, float, 0)
- ATTRIB(XonoticServerList, columnPingOrigin, float, 0)
- ATTRIB(XonoticServerList, columnPingSize, float, 0)
- ATTRIB(XonoticServerList, columnNameOrigin, float, 0)
- ATTRIB(XonoticServerList, columnNameSize, float, 0)
- ATTRIB(XonoticServerList, columnMapOrigin, float, 0)
- ATTRIB(XonoticServerList, columnMapSize, float, 0)
- ATTRIB(XonoticServerList, columnTypeOrigin, float, 0)
- ATTRIB(XonoticServerList, columnTypeSize, float, 0)
- ATTRIB(XonoticServerList, columnPlayersOrigin, float, 0)
- ATTRIB(XonoticServerList, columnPlayersSize, float, 0)
- ATTRIB(XonoticServerList, lockedSelectedItem, bool, true) // initially keep selected the first item of the list, avoiding an unwanted scrolling
-
- ATTRIB(XonoticServerList, selectedServer, string, string_null) // to restore selected server when needed
+ ATTRIB(XonoticServerList, realFontSize, vector, '0 0 0');
+ ATTRIB(XonoticServerList, realUpperMargin, float, 0);
+ ATTRIB(XonoticServerList, columnIconsOrigin, float, 0);
+ ATTRIB(XonoticServerList, columnIconsSize, float, 0);
+ ATTRIB(XonoticServerList, columnPingOrigin, float, 0);
+ ATTRIB(XonoticServerList, columnPingSize, float, 0);
+ ATTRIB(XonoticServerList, columnNameOrigin, float, 0);
+ ATTRIB(XonoticServerList, columnNameSize, float, 0);
+ ATTRIB(XonoticServerList, columnMapOrigin, float, 0);
+ ATTRIB(XonoticServerList, columnMapSize, float, 0);
+ ATTRIB(XonoticServerList, columnTypeOrigin, float, 0);
+ ATTRIB(XonoticServerList, columnTypeSize, float, 0);
+ ATTRIB(XonoticServerList, columnPlayersOrigin, float, 0);
+ ATTRIB(XonoticServerList, columnPlayersSize, float, 0);
+ ATTRIB(XonoticServerList, lockedSelectedItem, bool, true); // initially keep selected the first item of the list, avoiding an unwanted scrolling
+
+ ATTRIB(XonoticServerList, selectedServer, string); // to restore selected server when needed
METHOD(XonoticServerList, setSelected, void(entity, float));
METHOD(XonoticServerList, setSortOrder, void(entity, float, float));
- ATTRIB(XonoticServerList, filterShowEmpty, float, 1)
- ATTRIB(XonoticServerList, filterShowFull, float, 1)
- ATTRIB(XonoticServerList, filterString, string, string_null)
- ATTRIB(XonoticServerList, controlledTextbox, entity, NULL)
- ATTRIB(XonoticServerList, ipAddressBox, entity, NULL)
- ATTRIB(XonoticServerList, favoriteButton, entity, NULL)
- ATTRIB(XonoticServerList, nextRefreshTime, float, 0)
+ ATTRIB(XonoticServerList, filterShowEmpty, float, 1);
+ ATTRIB(XonoticServerList, filterShowFull, float, 1);
+ ATTRIB(XonoticServerList, filterString, string);
+ ATTRIB(XonoticServerList, controlledTextbox, entity);
+ ATTRIB(XonoticServerList, ipAddressBox, entity);
+ ATTRIB(XonoticServerList, favoriteButton, entity);
+ ATTRIB(XonoticServerList, nextRefreshTime, float, 0);
METHOD(XonoticServerList, refreshServerList, void(entity, float)); // refresh mode: REFRESHSERVERLIST_*
- ATTRIB(XonoticServerList, needsRefresh, float, 1)
+ ATTRIB(XonoticServerList, needsRefresh, float, 1);
METHOD(XonoticServerList, focusEnter, void(entity));
METHOD(XonoticServerList, positionSortButton, void(entity, entity, float, float, string, void(entity, entity)));
- ATTRIB(XonoticServerList, sortButton1, entity, NULL)
- ATTRIB(XonoticServerList, sortButton2, entity, NULL)
- ATTRIB(XonoticServerList, sortButton3, entity, NULL)
- ATTRIB(XonoticServerList, sortButton4, entity, NULL)
- ATTRIB(XonoticServerList, sortButton5, entity, NULL)
- ATTRIB(XonoticServerList, connectButton, entity, NULL)
- ATTRIB(XonoticServerList, infoButton, entity, NULL)
- ATTRIB(XonoticServerList, currentSortOrder, float, 0)
- ATTRIB(XonoticServerList, currentSortField, float, -1)
-
- ATTRIB(XonoticServerList, ipAddressBoxFocused, float, -1)
-
- ATTRIB(XonoticServerList, seenIPv4, float, 0)
- ATTRIB(XonoticServerList, seenIPv6, float, 0)
- ATTRIB(XonoticServerList, categoriesHeight, float, 1.25)
+ ATTRIB(XonoticServerList, sortButton1, entity);
+ ATTRIB(XonoticServerList, sortButton2, entity);
+ ATTRIB(XonoticServerList, sortButton3, entity);
+ ATTRIB(XonoticServerList, sortButton4, entity);
+ ATTRIB(XonoticServerList, sortButton5, entity);
+ ATTRIB(XonoticServerList, connectButton, entity);
+ ATTRIB(XonoticServerList, infoButton, entity);
+ ATTRIB(XonoticServerList, currentSortOrder, float, 0);
+ ATTRIB(XonoticServerList, currentSortField, float, -1);
+
+ ATTRIB(XonoticServerList, ipAddressBoxFocused, float, -1);
+
+ ATTRIB(XonoticServerList, seenIPv4, float, 0);
+ ATTRIB(XonoticServerList, seenIPv6, float, 0);
+ ATTRIB(XonoticServerList, categoriesHeight, float, 1.25);
METHOD(XonoticServerList, getTotalHeight, float(entity));
METHOD(XonoticServerList, getItemAtPos, float(entity, float));
#include "listbox.qh"
CLASS(XonoticSkinList, XonoticListBox)
METHOD(XonoticSkinList, configureXonoticSkinList, void(entity));
- ATTRIB(XonoticSkinList, rowsPerItem, float, 4)
+ ATTRIB(XonoticSkinList, rowsPerItem, float, 4);
METHOD(XonoticSkinList, resizeNotify, void(entity, vector, vector, vector, vector));
METHOD(XonoticSkinList, drawListBoxItem, void(entity, int, vector, bool, bool));
METHOD(XonoticSkinList, getSkins, void(entity));
METHOD(XonoticSkinList, keyDown, float(entity, float, float, float));
METHOD(XonoticSkinList, destroy, void(entity));
- ATTRIB(XonoticSkinList, skinlist, float, -1)
- ATTRIB(XonoticSkinList, realFontSize, vector, '0 0 0')
- ATTRIB(XonoticSkinList, columnPreviewOrigin, float, 0)
- ATTRIB(XonoticSkinList, columnPreviewSize, float, 0)
- ATTRIB(XonoticSkinList, columnNameOrigin, float, 0)
- ATTRIB(XonoticSkinList, columnNameSize, float, 0)
- ATTRIB(XonoticSkinList, realUpperMargin1, float, 0)
- ATTRIB(XonoticSkinList, realUpperMargin2, float, 0)
- ATTRIB(XonoticSkinList, origin, vector, '0 0 0')
- ATTRIB(XonoticSkinList, itemAbsSize, vector, '0 0 0')
+ ATTRIB(XonoticSkinList, skinlist, float, -1);
+ ATTRIB(XonoticSkinList, realFontSize, vector, '0 0 0');
+ ATTRIB(XonoticSkinList, columnPreviewOrigin, float, 0);
+ ATTRIB(XonoticSkinList, columnPreviewSize, float, 0);
+ ATTRIB(XonoticSkinList, columnNameOrigin, float, 0);
+ ATTRIB(XonoticSkinList, columnNameSize, float, 0);
+ ATTRIB(XonoticSkinList, realUpperMargin1, float, 0);
+ ATTRIB(XonoticSkinList, realUpperMargin2, float, 0);
+ ATTRIB(XonoticSkinList, origin, vector, '0 0 0');
+ ATTRIB(XonoticSkinList, itemAbsSize, vector, '0 0 0');
- ATTRIB(XonoticSkinList, name, string, "skinselector")
+ ATTRIB(XonoticSkinList, name, string, "skinselector");
ENDCLASS(XonoticSkinList)
entity makeXonoticSkinList();
METHOD(XonoticSlider, configureXonoticSlider, void(entity, float, float, float, string, string));
METHOD(XonoticSlider, setValue, void(entity, float));
METHOD(XonoticSlider, setValue_noAnim, void(entity, float));
- ATTRIB(XonoticSlider, fontSize, float, SKINFONTSIZE_NORMAL)
- ATTRIB(XonoticSlider, valueSpace, float, SKINWIDTH_SLIDERTEXT)
- ATTRIB(XonoticSlider, image, string, SKINGFX_SLIDER)
- ATTRIB(XonoticSlider, tolerance, vector, SKINTOLERANCE_SLIDER)
- ATTRIB(XonoticSlider, align, float, 0.5)
- ATTRIB(XonoticSlider, color, vector, SKINCOLOR_SLIDER_N)
- ATTRIB(XonoticSlider, colorC, vector, SKINCOLOR_SLIDER_C)
- ATTRIB(XonoticSlider, colorF, vector, SKINCOLOR_SLIDER_F)
- ATTRIB(XonoticSlider, colorD, vector, SKINCOLOR_SLIDER_D)
- ATTRIB(XonoticSlider, color2, vector, SKINCOLOR_SLIDER_S)
+ ATTRIB(XonoticSlider, fontSize, float, SKINFONTSIZE_NORMAL);
+ ATTRIB(XonoticSlider, valueSpace, float, SKINWIDTH_SLIDERTEXT);
+ ATTRIB(XonoticSlider, image, string, SKINGFX_SLIDER);
+ ATTRIB(XonoticSlider, tolerance, vector, SKINTOLERANCE_SLIDER);
+ ATTRIB(XonoticSlider, align, float, 0.5);
+ ATTRIB(XonoticSlider, color, vector, SKINCOLOR_SLIDER_N);
+ ATTRIB(XonoticSlider, colorC, vector, SKINCOLOR_SLIDER_C);
+ ATTRIB(XonoticSlider, colorF, vector, SKINCOLOR_SLIDER_F);
+ ATTRIB(XonoticSlider, colorD, vector, SKINCOLOR_SLIDER_D);
+ ATTRIB(XonoticSlider, color2, vector, SKINCOLOR_SLIDER_S);
- ATTRIB(XonoticSlider, cvarName, string, string_null)
+ ATTRIB(XonoticSlider, cvarName, string);
METHOD(XonoticSlider, loadCvars, void(entity));
METHOD(XonoticSlider, saveCvars, void(entity));
- ATTRIB(XonoticSlider, sendCvars, float, 0)
+ ATTRIB(XonoticSlider, sendCvars, float, 0);
- ATTRIB(XonoticSlider, alpha, float, SKINALPHA_TEXT)
- ATTRIB(XonoticSlider, disabledAlpha, float, SKINALPHA_DISABLED)
+ ATTRIB(XonoticSlider, alpha, float, SKINALPHA_TEXT);
+ ATTRIB(XonoticSlider, disabledAlpha, float, SKINALPHA_DISABLED);
ENDCLASS(XonoticSlider)
entity makeXonoticSlider_T(float, float, float, string, string theTooltip);
entity makeXonoticSlider(float, float, float, string);
METHOD(XonoticPicmipSlider, configureXonoticPicmipSlider, void(entity));
METHOD(XonoticPicmipSlider, draw, void(entity));
METHOD(XonoticPicmipSlider, autofix, void(entity));
- ATTRIB(XonoticPicmipSlider, have_s3tc, float, 0)
+ ATTRIB(XonoticPicmipSlider, have_s3tc, float, 0);
ENDCLASS(XonoticPicmipSlider)
entity makeXonoticPicmipSlider(); // note: you still need to call addValue and configureXonoticTextSliderValues!
minfactor = min(1, 640 / c.x); // can be > 1 only if c_x is <640
maxfactor = max(1, r.x / c.x, r.y / c.y); // can be < 1 only if r_x < c_x and r_y < c_y
- LOG_TRACE("min factor: ", ftos(minfactor), "\n");
- LOG_TRACE("max factor: ", ftos(maxfactor), "\n");
+ LOG_TRACE("min factor: ", ftos(minfactor));
+ LOG_TRACE("max factor: ", ftos(maxfactor));
if(sz < 0)
f = 1 - (maxfactor - 1) * sz;
r = getresolution(-1);
if(r.x != 0 || r.y != 0)
me.addResolution(me, r.x, r.y, r.z);
- LOG_TRACE("Added system resolutions.\n");
+ LOG_TRACE("Added system resolutions.");
}
if(me.nValues == 0)
me.addResolution(me, 1280, 960, 1); // pc res
me.addResolution(me, 1280, 1024, 1); // pc res
me.addResolution(me, 1920, 1080, 1); // 1080p
- LOG_TRACE("Added default resolutions.\n");
+ LOG_TRACE("Added default resolutions.");
}
- LOG_TRACE("Total number of resolutions detected: ", ftos(me.nValues), "\n");
+ LOG_TRACE("Total number of resolutions detected: ", ftos(me.nValues));
me.vid_fullscreen = fullscreen;
METHOD(XonoticResolutionSlider, loadCvars, void(entity));
METHOD(XonoticResolutionSlider, saveCvars, void(entity));
METHOD(XonoticResolutionSlider, draw, void(entity));
- ATTRIB(XonoticResolutionSlider, vid_fullscreen, float, -1)
- ATTRIB(XonoticResolutionSlider, maxAllowedWidth, float, 0)
- ATTRIB(XonoticResolutionSlider, maxAllowedHeight, float, 0)
+ ATTRIB(XonoticResolutionSlider, vid_fullscreen, float, -1);
+ ATTRIB(XonoticResolutionSlider, maxAllowedWidth, float, 0);
+ ATTRIB(XonoticResolutionSlider, maxAllowedHeight, float, 0);
ENDCLASS(XonoticResolutionSlider)
entity makeXonoticResolutionSlider();
float updateConwidths(float width, float height, float pixelheight);
}
void XonoticScoreboardFadeTimeSlider_configureXonoticScoreboardFadeTimeSlider(entity me)
{
- me.configureXonoticTextSlider(me, "scoreboard_fadeinspeed", string_null);
+ me.configureXonoticTextSlider(me, "hud_panel_scoreboard_fadeinspeed", string_null);
me.addValue(me, ZCTX(_("PART^Slow")), "5 2.5");
me.addValue(me, ZCTX(_("PART^Normal")), "10 5");
me.addValue(me, ZCTX(_("PART^Fast")), "15 7.5");
void XonoticScoreboardFadeTimeSlider_loadCvars(entity me)
{
me.setValueFromIdentifier_noAnim(me, sprintf("%s %s",
- cvar_string("scoreboard_fadeinspeed"),
- cvar_string("scoreboard_fadeoutspeed")
+ cvar_string("hud_panel_scoreboard_fadeinspeed"),
+ cvar_string("hud_panel_scoreboard_fadeoutspeed")
));
}
void XonoticScoreboardFadeTimeSlider_saveCvars(entity me)
if(me.value >= 0 || me.value < me.nValues)
{
tokenize_console(me.getIdentifier(me));
- cvar_set("scoreboard_fadeinspeed", argv(0));
- cvar_set("scoreboard_fadeoutspeed", argv(1));
+ cvar_set("hud_panel_scoreboard_fadeinspeed", argv(0));
+ cvar_set("hud_panel_scoreboard_fadeoutspeed", argv(1));
}
}
#include "listbox.qh"
CLASS(XonoticSoundList, XonoticListBox)
METHOD(XonoticSoundList, configureXonoticSoundList, void(entity));
- ATTRIB(XonoticSoundList, rowsPerItem, float, 1)
+ ATTRIB(XonoticSoundList, rowsPerItem, float, 1);
METHOD(XonoticSoundList, resizeNotify, void(entity, vector, vector, vector, vector));
METHOD(XonoticSoundList, drawListBoxItem, void(entity, int, vector, bool, bool));
METHOD(XonoticSoundList, getSounds, void(entity));
METHOD(XonoticSoundList, destroy, void(entity));
METHOD(XonoticSoundList, showNotify, void(entity));
- ATTRIB(XonoticSoundList, listSound, int, -1)
- ATTRIB(XonoticSoundList, realFontSize, vector, '0 0 0')
- ATTRIB(XonoticSoundList, columnNameOrigin, float, 0)
- ATTRIB(XonoticSoundList, columnNameSize, float, 0)
- ATTRIB(XonoticSoundList, columnNumberOrigin, float, 0)
- ATTRIB(XonoticSoundList, columnNumberSize, float, 0)
- ATTRIB(XonoticSoundList, realUpperMargin, float, 0)
- ATTRIB(XonoticSoundList, origin, vector, '0 0 0')
- ATTRIB(XonoticSoundList, itemAbsSize, vector, '0 0 0')
+ ATTRIB(XonoticSoundList, listSound, int, -1);
+ ATTRIB(XonoticSoundList, realFontSize, vector, '0 0 0');
+ ATTRIB(XonoticSoundList, columnNameOrigin, float, 0);
+ ATTRIB(XonoticSoundList, columnNameSize, float, 0);
+ ATTRIB(XonoticSoundList, columnNumberOrigin, float, 0);
+ ATTRIB(XonoticSoundList, columnNumberSize, float, 0);
+ ATTRIB(XonoticSoundList, realUpperMargin, float, 0);
+ ATTRIB(XonoticSoundList, origin, vector, '0 0 0');
+ ATTRIB(XonoticSoundList, itemAbsSize, vector, '0 0 0');
- ATTRIB(XonoticSoundList, filterString, string, string_null)
- ATTRIB(XonoticSoundList, playlist, entity, NULL)
+ ATTRIB(XonoticSoundList, filterString, string);
+ ATTRIB(XonoticSoundList, playlist, entity);
ENDCLASS(XonoticSoundList)
entity makeXonoticSoundList();
void XonoticStatsList_getStats(entity me)
{
- LOG_TRACE("XonoticStatsList_getStats() at time: ", ftos(time), "\n");
+ LOG_TRACE("XonoticStatsList_getStats() at time: ", ftos(time));
// delete the old buffer if it exists
if(me.listStats >= 0)
buf_del(me.listStats);
#include "listbox.qh"
CLASS(XonoticStatsList, XonoticListBox)
METHOD(XonoticStatsList, configureXonoticStatsList, void(entity));
- ATTRIB(XonoticStatsList, rowsPerItem, float, 1.4)
+ ATTRIB(XonoticStatsList, rowsPerItem, float, 1.4);
METHOD(XonoticStatsList, resizeNotify, void(entity, vector, vector, vector, vector));
METHOD(XonoticStatsList, drawListBoxItem, void(entity, int, vector, bool, bool));
METHOD(XonoticStatsList, getStats, void(entity));
METHOD(XonoticStatsList, keyDown, float(entity, float, float, float));
METHOD(XonoticStatsList, destroy, void(entity));
METHOD(XonoticStatsList, showNotify, void(entity));
- ATTRIB(XonoticStatsList, selectionDoesntMatter, bool, true)
+ ATTRIB(XonoticStatsList, selectionDoesntMatter, bool, true);
- ATTRIB(XonoticStatsList, listStats, float, -1)
- ATTRIB(XonoticStatsList, realFontSize, vector, '0 0 0')
- ATTRIB(XonoticStatsList, realUpperMargin, float, 0)
- ATTRIB(XonoticStatsList, columnNameOrigin, float, 0)
- ATTRIB(XonoticStatsList, columnNameSize, float, 0)
+ ATTRIB(XonoticStatsList, listStats, float, -1);
+ ATTRIB(XonoticStatsList, realFontSize, vector, '0 0 0');
+ ATTRIB(XonoticStatsList, realUpperMargin, float, 0);
+ ATTRIB(XonoticStatsList, columnNameOrigin, float, 0);
+ ATTRIB(XonoticStatsList, columnNameSize, float, 0);
ENDCLASS(XonoticStatsList)
entity statslist; // for reference elsewhere
CLASS(XonoticTab, Tab)
// still to be customized by user
/*
- ATTRIB(XonoticTab, intendedWidth, float, 0)
- ATTRIB(XonoticTab, rows, float, 3)
- ATTRIB(XonoticTab, columns, float, 2)
+ ATTRIB(XonoticTab, intendedWidth, float, 0);
+ ATTRIB(XonoticTab, rows, float, 3);
+ ATTRIB(XonoticTab, columns, float, 2);
*/
METHOD(XonoticTab, showNotify, void(entity));
- ATTRIB(XonoticTab, marginTop, float, 0) // pixels
- ATTRIB(XonoticTab, marginBottom, float, 0) // pixels
- ATTRIB(XonoticTab, marginLeft, float, 0) // pixels
- ATTRIB(XonoticTab, marginRight, float, 0) // pixels
- ATTRIB(XonoticTab, columnSpacing, float, SKINMARGIN_COLUMNS) // pixels
- ATTRIB(XonoticTab, rowSpacing, float, SKINMARGIN_ROWS) // pixels
- ATTRIB(XonoticTab, rowHeight, float, SKINFONTSIZE_NORMAL * SKINHEIGHT_NORMAL) // pixels
+ ATTRIB(XonoticTab, marginTop, float, 0); // pixels
+ ATTRIB(XonoticTab, marginBottom, float, 0); // pixels
+ ATTRIB(XonoticTab, marginLeft, float, 0); // pixels
+ ATTRIB(XonoticTab, marginRight, float, 0); // pixels
+ ATTRIB(XonoticTab, columnSpacing, float, SKINMARGIN_COLUMNS); // pixels
+ ATTRIB(XonoticTab, rowSpacing, float, SKINMARGIN_ROWS); // pixels
+ ATTRIB(XonoticTab, rowHeight, float, SKINFONTSIZE_NORMAL * SKINHEIGHT_NORMAL); // pixels
- ATTRIB(XonoticTab, backgroundImage, string, string_null)
+ ATTRIB(XonoticTab, backgroundImage, string);
// using "titleTooltip" instead of "tooltip" so that
// the tooltip search function doesn't find it
// .tooltip should be set only in the item displaying the tab title
- ATTRIB(XonoticTab, titleTooltip, string, string_null)
+ ATTRIB(XonoticTab, titleTooltip, string);
ENDCLASS(XonoticTab)
METHOD(XonoticTabController, configureXonoticTabController, void(entity, float));
METHOD(XonoticTabController, makeTabButton_T, entity(entity, string, entity, string));
METHOD(XonoticTabController, makeTabButton, entity(entity, string, entity));
- ATTRIB(XonoticTabController, rows, float, 0)
- ATTRIB(XonoticTabController, fontSize, float, SKINFONTSIZE_NORMAL)
- ATTRIB(XonoticTabController, image, string, SKINGFX_BUTTON)
+ ATTRIB(XonoticTabController, rows, float, 0);
+ ATTRIB(XonoticTabController, fontSize, float, SKINFONTSIZE_NORMAL);
+ ATTRIB(XonoticTabController, image, string, SKINGFX_BUTTON);
ENDCLASS(XonoticTabController)
entity makeXonoticTabController(float theRows);
CLASS(XonoticTextLabel, Label)
METHOD(XonoticTextLabel, configureXonoticTextLabel, void(entity, float, string));
METHOD(XonoticTextLabel, draw, void(entity));
- ATTRIB(XonoticTextLabel, fontSize, float, SKINFONTSIZE_NORMAL)
- ATTRIB(XonoticTextLabel, alpha, float, SKINALPHA_TEXT)
- ATTRIB(XonoticTextLabel, disabledAlpha, float, SKINALPHA_DISABLED)
+ ATTRIB(XonoticTextLabel, fontSize, float, SKINFONTSIZE_NORMAL);
+ ATTRIB(XonoticTextLabel, alpha, float, SKINALPHA_TEXT);
+ ATTRIB(XonoticTextLabel, disabledAlpha, float, SKINALPHA_DISABLED);
ENDCLASS(XonoticTextLabel)
entity makeXonoticTextLabel(float theAlign, string theText);
entity makeXonoticHeaderLabel(string theText);
METHOD(XonoticTextSlider, setValue, void(entity, float));
METHOD(XonoticTextSlider, setValue_noAnim, void(entity, float));
METHOD(XonoticTextSlider, configureXonoticTextSliderValues, void(entity));
- ATTRIB(XonoticTextSlider, fontSize, float, SKINFONTSIZE_NORMAL)
- ATTRIB(XonoticTextSlider, valueSpace, float, SKINWIDTH_SLIDERTEXT)
- ATTRIB(XonoticTextSlider, image, string, SKINGFX_SLIDER)
- ATTRIB(XonoticTextSlider, tolerance, vector, SKINTOLERANCE_SLIDER)
- ATTRIB(XonoticTextSlider, align, float, 0.5)
- ATTRIB(XonoticTextSlider, color, vector, SKINCOLOR_SLIDER_N)
- ATTRIB(XonoticTextSlider, colorC, vector, SKINCOLOR_SLIDER_C)
- ATTRIB(XonoticTextSlider, colorF, vector, SKINCOLOR_SLIDER_F)
- ATTRIB(XonoticTextSlider, colorD, vector, SKINCOLOR_SLIDER_D)
- ATTRIB(XonoticTextSlider, color2, vector, SKINCOLOR_SLIDER_S)
+ ATTRIB(XonoticTextSlider, fontSize, float, SKINFONTSIZE_NORMAL);
+ ATTRIB(XonoticTextSlider, valueSpace, float, SKINWIDTH_SLIDERTEXT);
+ ATTRIB(XonoticTextSlider, image, string, SKINGFX_SLIDER);
+ ATTRIB(XonoticTextSlider, tolerance, vector, SKINTOLERANCE_SLIDER);
+ ATTRIB(XonoticTextSlider, align, float, 0.5);
+ ATTRIB(XonoticTextSlider, color, vector, SKINCOLOR_SLIDER_N);
+ ATTRIB(XonoticTextSlider, colorC, vector, SKINCOLOR_SLIDER_C);
+ ATTRIB(XonoticTextSlider, colorF, vector, SKINCOLOR_SLIDER_F);
+ ATTRIB(XonoticTextSlider, colorD, vector, SKINCOLOR_SLIDER_D);
+ ATTRIB(XonoticTextSlider, color2, vector, SKINCOLOR_SLIDER_S);
- ATTRIB(XonoticTextSlider, cvarName, string, string_null)
+ ATTRIB(XonoticTextSlider, cvarName, string);
METHOD(XonoticTextSlider, loadCvars, void(entity));
METHOD(XonoticTextSlider, saveCvars, void(entity));
- ATTRIB(XonoticTextSlider, sendCvars, float, 0)
+ ATTRIB(XonoticTextSlider, sendCvars, float, 0);
- ATTRIB(XonoticTextSlider, alpha, float, SKINALPHA_TEXT)
- ATTRIB(XonoticTextSlider, disabledAlpha, float, SKINALPHA_DISABLED)
+ ATTRIB(XonoticTextSlider, alpha, float, SKINALPHA_TEXT);
+ ATTRIB(XonoticTextSlider, disabledAlpha, float, SKINALPHA_DISABLED);
ENDCLASS(XonoticTextSlider)
entity makeXonoticTextSlider_T(string, string theTooltip);
entity makeXonoticTextSlider(string); // note: you still need to call addValue and configureXonoticTextSliderValues!
if(_Nex_ExtResponseSystem_UpdateTo)
{
- LOG_TRACE("error: UpdateNotification_URI_Get_Callback has been called before\n");
+ LOG_TRACE("error: UpdateNotification_URI_Get_Callback has been called before");
return;
}
if(status != 0)
{
- LOG_TRACEF("error receiving update notification: status is %d\n", status);
+ LOG_TRACEF("error receiving update notification: status is %d", status);
return;
}
if(substring(data, 0, 1) == "<")
{
- LOG_TRACE("error: received HTML instead of an update notification\n");
+ LOG_TRACE("error: received HTML instead of an update notification");
return;
}
if(strstrofs(data, "\r", 0) != -1)
{
- LOG_TRACE("error: received carriage returns from update notification server\n");
+ LOG_TRACE("error: received carriage returns from update notification server");
return;
}
MapInfo_Cache_Create();
MapInfo_Enumerate();
- if(!MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 0, 0, 1))
+ if(!_MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 0, 0, 1))
{
draw_reset_cropped();
/* GAMETYPE(MAPINFO_TYPE_INVASION) */ \
/**/
-int GameType_GetID(int cnt)
+Gametype GameType_GetID(int cnt)
{
int i = 0;
-
- #define GAMETYPE(id) { if (i++ == cnt) return id; }
+ #define GAMETYPE(it) { if (i++ == cnt) return it; }
GAMETYPES
#undef GAMETYPE
-
- unused_float = i;
-
- return 0;
+ return NULL;
}
int GameType_GetCount()
{
int i = 0;
-
#define GAMETYPE(id) ++i;
GAMETYPES
#undef GAMETYPE
-
return i;
}
string GameType_GetName(int cnt)
{
- int i = GameType_GetID(cnt);
-
- if(i)
- return MapInfo_Type_ToText(i);
-
- return "";
+ Gametype i = GameType_GetID(cnt);
+ return i ? MapInfo_Type_ToText(i) : "";
}
string GameType_GetIcon(int cnt)
{
- int i = GameType_GetID(cnt);
-
- if(i)
- return strcat("gametype_", MapInfo_Type_ToString(i));
-
- return "";
+ Gametype i = GameType_GetID(cnt);
+ return i ? strcat("gametype_", MapInfo_Type_ToString(i)) : "";
}
.void(entity) TR;
// game type list box stuff (does not NEED to contain all game types, other
// types stay available via console)
-int GameType_GetID(int cnt);
+entity GameType_GetID(int cnt);
string GameType_GetName(int cnt);
string GameType_GetIcon(int cnt);
//string GameType_GetTeams(float cnt);
CLASS(XonoticWeaponarenaCheckBox, CheckBox)
METHOD(XonoticWeaponarenaCheckBox, configureXonoticWeaponarenaCheckBox, void(entity, string, string));
METHOD(XonoticWeaponarenaCheckBox, setChecked, void(entity, float));
- ATTRIB(XonoticWeaponarenaCheckBox, fontSize, float, SKINFONTSIZE_NORMAL)
- ATTRIB(XonoticWeaponarenaCheckBox, image, string, SKINGFX_CHECKBOX)
- ATTRIB(XonoticWeaponarenaCheckBox, netname, string, string_null)
+ ATTRIB(XonoticWeaponarenaCheckBox, fontSize, float, SKINFONTSIZE_NORMAL);
+ ATTRIB(XonoticWeaponarenaCheckBox, image, string, SKINGFX_CHECKBOX);
+ ATTRIB(XonoticWeaponarenaCheckBox, netname, string);
METHOD(XonoticWeaponarenaCheckBox, loadCvars, void(entity));
METHOD(XonoticWeaponarenaCheckBox, saveCvars, void(entity));
CLASS(XonoticWeaponsList, XonoticListBox)
METHOD(XonoticWeaponsList, configureXonoticWeaponsList, void(entity));
METHOD(XonoticWeaponsList, toString, string(entity));
- ATTRIB(XonoticWeaponsList, rowsPerItem, float, 1)
+ ATTRIB(XonoticWeaponsList, rowsPerItem, float, 1);
METHOD(XonoticWeaponsList, draw, void(entity));
METHOD(XonoticWeaponsList, drawListBoxItem, void(entity, int, vector, bool, bool));
METHOD(XonoticWeaponsList, resizeNotify, void(entity, vector, vector, vector, vector));
METHOD(XonoticWeaponsList, keyDown, float(entity, float, float, float));
- ATTRIB(XonoticWeaponsList, realFontSize, vector, '0 0 0')
- ATTRIB(XonoticWeaponsList, realUpperMargin, float, 0)
+ ATTRIB(XonoticWeaponsList, realFontSize, vector, '0 0 0');
+ ATTRIB(XonoticWeaponsList, realUpperMargin, float, 0);
METHOD(XonoticWeaponsList, mouseDrag, float(entity, vector));
- ATTRIB(XonoticWeaponsList, applyButton, entity, NULL)
+ ATTRIB(XonoticWeaponsList, applyButton, entity);
ENDCLASS(XonoticWeaponsList)
entity makeXonoticWeaponsList();
void WeaponsList_MoveUp_Click(entity btn, entity me);
spawnfunc(worldspawn)
{
float r;
- LOG_TRACE("TESTCASE: START\n");
+ LOG_TRACE("TESTCASE: START");
r = test();
if(r == 1)
error("TESTCASE: PASS");
int autocvar__campaign_index;
string autocvar__campaign_name;
bool autocvar__sv_init;
-float autocvar_bot_ai_aimskill_blendrate;
-float autocvar_bot_ai_aimskill_firetolerance_distdegrees;
-float autocvar_bot_ai_aimskill_firetolerance_maxdegrees;
-float autocvar_bot_ai_aimskill_firetolerance_mindegrees;
-float autocvar_bot_ai_aimskill_fixedrate;
-float autocvar_bot_ai_aimskill_mouse;
-float autocvar_bot_ai_aimskill_offset;
-float autocvar_bot_ai_aimskill_order_filter_1st;
-float autocvar_bot_ai_aimskill_order_filter_2nd;
-float autocvar_bot_ai_aimskill_order_filter_3th;
-float autocvar_bot_ai_aimskill_order_filter_4th;
-float autocvar_bot_ai_aimskill_order_filter_5th;
-float autocvar_bot_ai_aimskill_order_mix_1st;
-float autocvar_bot_ai_aimskill_order_mix_2nd;
-float autocvar_bot_ai_aimskill_order_mix_3th;
-float autocvar_bot_ai_aimskill_order_mix_4th;
-float autocvar_bot_ai_aimskill_order_mix_5th;
-float autocvar_bot_ai_aimskill_think;
-float autocvar_bot_ai_bunnyhop_firstjumpdelay;
-float autocvar_bot_ai_bunnyhop_skilloffset;
-float autocvar_bot_ai_bunnyhop_startdistance;
-float autocvar_bot_ai_bunnyhop_stopdistance;
-float autocvar_bot_ai_chooseweaponinterval;
-string autocvar_bot_ai_custom_weapon_priority_close;
-string autocvar_bot_ai_custom_weapon_priority_distances;
-string autocvar_bot_ai_custom_weapon_priority_far;
-string autocvar_bot_ai_custom_weapon_priority_mid;
-float autocvar_bot_ai_dangerdetectioninterval;
-float autocvar_bot_ai_dangerdetectionupdates;
-float autocvar_bot_ai_enemydetectioninterval;
-float autocvar_bot_ai_enemydetectionradius;
-float autocvar_bot_ai_friends_aware_pickup_radius;
-float autocvar_bot_ai_ignoregoal_timeout;
-float autocvar_bot_ai_keyboard_distance;
-float autocvar_bot_ai_keyboard_threshold;
-float autocvar_bot_ai_navigation_jetpack;
-float autocvar_bot_ai_navigation_jetpack_mindistance;
float autocvar_bot_ai_strategyinterval;
-float autocvar_bot_ai_thinkinterval;
-bool autocvar_bot_ai_weapon_combo;
-float autocvar_bot_ai_weapon_combo_threshold;
-string autocvar_bot_config_file;
-bool autocvar_bot_god;
-bool autocvar_bot_ignore_bots;
-bool autocvar_bot_join_empty;
-bool autocvar_bot_navigation_ignoreplayers;
-bool autocvar_bot_nofire;
#define autocvar_bot_number cvar("bot_number")
-#define autocvar_bot_prefix cvar_string("bot_prefix")
-#define autocvar_bot_suffix cvar_string("bot_suffix")
-bool autocvar_bot_usemodelnames;
int autocvar_bot_vs_human;
-bool autocvar_bot_debug_tracewalk;
-bool autocvar_bot_debug_goalstack;
-bool autocvar_bot_wander_enable;
int autocvar_captureleadlimit_override;
#define autocvar_capturelimit_override cvar("capturelimit_override")
float autocvar_ekg;
int autocvar_g_chat_nospectators;
bool autocvar_g_chat_teamcolors;
bool autocvar_g_chat_tellprivacy;
-bool autocvar_g_debug_bot_commands;
bool autocvar_g_forced_respawn;
string autocvar_g_forced_team_blue;
string autocvar_g_forced_team_otherwise;
float autocvar_g_turrets_targetscan_mindelay;
bool autocvar_g_use_ammunition;
bool autocvar_g_waypointeditor;
-int autocvar_g_waypointeditor_auto;
bool autocvar_g_waypoints_for_items;
#define autocvar_g_weapon_stay cvar("g_weapon_stay")
bool autocvar_g_weapon_throwable;
bool autocvar_samelevel;
string autocvar_sessionid;
#define autocvar_skill cvar("skill")
-float autocvar_skill_auto;
#define autocvar_slowmo cvar("slowmo")
float autocvar_snd_soundradius;
int autocvar_spawn_debug;
int autocvar_timelimit_overtimes;
float autocvar_timelimit_suddendeath;
#define autocvar_utf8_enable cvar("utf8_enable")
-bool autocvar_waypoint_benchmark;
float autocvar_sv_gameplayfix_gravityunaffectedbyticrate;
bool autocvar_sv_gameplayfix_upwardvelocityclearsongroundflag;
float autocvar_g_trueaim_minrange;
float autocvar_sv_airaccelerate;
float autocvar_sv_airstopaccelerate;
float autocvar_sv_track_canjump;
+bool autocvar_sv_showspectators;
// generated file; do not modify
-#include <server/bot/aim.qc>
-#include <server/bot/bot.qc>
-#include <server/bot/navigation.qc>
-#include <server/bot/scripting.qc>
-#include <server/bot/waypoints.qc>
+#include <server/bot/api.qc>
// generated file; do not modify
-#include <server/bot/aim.qh>
-#include <server/bot/bot.qh>
-#include <server/bot/navigation.qh>
-#include <server/bot/scripting.qh>
-#include <server/bot/waypoints.qh>
+#include <server/bot/api.qh>
+++ /dev/null
-#include "aim.qh"
-
-#include "bot.qh"
-
-#include <common/physics/player.qh>
-#include <common/state.qh>
-
-#include "../weapons/weaponsystem.qh"
-
-#include "../mutators/all.qh"
-
-// traces multiple trajectories to find one that will impact the target
-// 'end' vector is the place it aims for,
-// returns true only if it hit targ (don't target non-solid entities)
-
-float findtrajectorywithleading(vector org, vector m1, vector m2, entity targ, float shotspeed, float shotspeedupward, float maxtime, float shotdelay, entity ignore)
-{
- float c, savesolid, shottime;
- vector dir, end, v, o;
- if (shotspeed < 1)
- return false; // could cause division by zero if calculated
- if (targ.solid < SOLID_BBOX) // SOLID_NOT and SOLID_TRIGGER
- return false; // could never hit it
- if (!tracetossent)
- tracetossent = new(tracetossent);
- tracetossent.owner = ignore;
- setsize(tracetossent, m1, m2);
- savesolid = targ.solid;
- targ.solid = SOLID_NOT;
- o = (targ.absmin + targ.absmax) * 0.5;
- shottime = ((vlen(o - org) / shotspeed) + shotdelay);
- v = targ.velocity * shottime + o;
- tracebox(o, targ.mins, targ.maxs, v, false, targ);
- v = trace_endpos;
- end = v + (targ.mins + targ.maxs) * 0.5;
- if ((vlen(end - org) / shotspeed + 0.2) > maxtime)
- {
- // out of range
- targ.solid = savesolid;
- return false;
- }
-
- if (!tracetossfaketarget)
- tracetossfaketarget = new(tracetossfaketarget);
- tracetossfaketarget.solid = savesolid;
- set_movetype(tracetossfaketarget, targ.move_movetype);
- _setmodel(tracetossfaketarget, targ.model); // no low precision
- tracetossfaketarget.model = targ.model;
- tracetossfaketarget.modelindex = targ.modelindex;
- setsize(tracetossfaketarget, targ.mins, targ.maxs);
- setorigin(tracetossfaketarget, v);
-
- c = 0;
- dir = normalize(end - org);
- while (c < 10) // 10 traces
- {
- setorigin(tracetossent, org); // reset
- tracetossent.velocity = findtrajectory_velocity = normalize(dir) * shotspeed + shotspeedupward * '0 0 1';
- tracetoss(tracetossent, ignore); // love builtin functions...
- if (trace_ent == tracetossfaketarget) // done
- {
- targ.solid = savesolid;
-
- // make it disappear
- tracetossfaketarget.solid = SOLID_NOT;
- set_movetype(tracetossfaketarget, MOVETYPE_NONE);
- tracetossfaketarget.model = "";
- tracetossfaketarget.modelindex = 0;
- // relink to remove it from physics considerations
- setorigin(tracetossfaketarget, v);
-
- return true;
- }
- dir.z = dir.z + 0.1; // aim up a little more
- c = c + 1;
- }
- targ.solid = savesolid;
-
- // make it disappear
- tracetossfaketarget.solid = SOLID_NOT;
- set_movetype(tracetossfaketarget, MOVETYPE_NONE);
- tracetossfaketarget.model = "";
- tracetossfaketarget.modelindex = 0;
- // relink to remove it from physics considerations
- setorigin(tracetossfaketarget, v);
-
- // leave a valid one even if it won't reach
- findtrajectory_velocity = normalize(end - org) * shotspeed + shotspeedupward * '0 0 1';
- return false;
-}
-
-void lag_update(entity this)
-{
- if (this.lag1_time) if (time > this.lag1_time) {this.lag_func(this, this.lag1_time, this.lag1_float1, this.lag1_float2, this.lag1_entity1, this.lag1_vec1, this.lag1_vec2, this.lag1_vec3, this.lag1_vec4);this.lag1_time = 0;}
- if (this.lag2_time) if (time > this.lag2_time) {this.lag_func(this, this.lag2_time, this.lag2_float1, this.lag2_float2, this.lag2_entity1, this.lag2_vec1, this.lag2_vec2, this.lag2_vec3, this.lag2_vec4);this.lag2_time = 0;}
- if (this.lag3_time) if (time > this.lag3_time) {this.lag_func(this, this.lag3_time, this.lag3_float1, this.lag3_float2, this.lag3_entity1, this.lag3_vec1, this.lag3_vec2, this.lag3_vec3, this.lag3_vec4);this.lag3_time = 0;}
- if (this.lag4_time) if (time > this.lag4_time) {this.lag_func(this, this.lag4_time, this.lag4_float1, this.lag4_float2, this.lag4_entity1, this.lag4_vec1, this.lag4_vec2, this.lag4_vec3, this.lag4_vec4);this.lag4_time = 0;}
- if (this.lag5_time) if (time > this.lag5_time) {this.lag_func(this, this.lag5_time, this.lag5_float1, this.lag5_float2, this.lag5_entity1, this.lag5_vec1, this.lag5_vec2, this.lag5_vec3, this.lag5_vec4);this.lag5_time = 0;}
-}
-
-float lag_additem(entity this, float t, float f1, float f2, entity e1, vector v1, vector v2, vector v3, vector v4)
-{
- if (this.lag1_time == 0) {this.lag1_time = t;this.lag1_float1 = f1;this.lag1_float2 = f2;this.lag1_entity1 = e1;this.lag1_vec1 = v1;this.lag1_vec2 = v2;this.lag1_vec3 = v3;this.lag1_vec4 = v4;return true;}
- if (this.lag2_time == 0) {this.lag2_time = t;this.lag2_float1 = f1;this.lag2_float2 = f2;this.lag2_entity1 = e1;this.lag2_vec1 = v1;this.lag2_vec2 = v2;this.lag2_vec3 = v3;this.lag2_vec4 = v4;return true;}
- if (this.lag3_time == 0) {this.lag3_time = t;this.lag3_float1 = f1;this.lag3_float2 = f2;this.lag3_entity1 = e1;this.lag3_vec1 = v1;this.lag3_vec2 = v2;this.lag3_vec3 = v3;this.lag3_vec4 = v4;return true;}
- if (this.lag4_time == 0) {this.lag4_time = t;this.lag4_float1 = f1;this.lag4_float2 = f2;this.lag4_entity1 = e1;this.lag4_vec1 = v1;this.lag4_vec2 = v2;this.lag4_vec3 = v3;this.lag4_vec4 = v4;return true;}
- if (this.lag5_time == 0) {this.lag5_time = t;this.lag5_float1 = f1;this.lag5_float2 = f2;this.lag5_entity1 = e1;this.lag5_vec1 = v1;this.lag5_vec2 = v2;this.lag5_vec3 = v3;this.lag5_vec4 = v4;return true;}
- // no room for it (what is the best thing to do here??)
- return false;
-}
-
-bool bot_shouldattack(entity this, entity targ)
-{
- if (targ.team == this.team)
- {
- if (targ == this)
- return false;
- if (teamplay)
- if (targ.team != 0)
- return false;
- }
-
- if(STAT(FROZEN, targ))
- return false;
-
- if(teamplay)
- {
- if(targ.team==0)
- return false;
- }
- else if(bot_ignore_bots)
- if(IS_BOT_CLIENT(targ))
- return false;
-
- if (!targ.takedamage)
- return false;
- if (IS_DEAD(targ))
- return false;
- if (PHYS_INPUT_BUTTON_CHAT(targ))
- return false;
- if(targ.flags & FL_NOTARGET)
- return false;
-
- if(MUTATOR_CALLHOOK(BotShouldAttack, this, targ))
- return false;
-
- return true;
-}
-
-void bot_lagfunc(entity this, float t, float f1, float f2, entity e1, vector v1, vector v2, vector v3, vector v4)
-{
- if(this.flags & FL_INWATER)
- {
- this.bot_aimtarg = NULL;
- return;
- }
- this.bot_aimtarg = e1;
- this.bot_aimlatency = this.ping; // FIXME? Shouldn't this be in the lag item?
- //this.bot_aimorigin = v1;
- //this.bot_aimvelocity = v2;
- this.bot_aimtargorigin = v3;
- this.bot_aimtargvelocity = v4;
- if(skill <= 0)
- this.bot_canfire = (random() < 0.8);
- else if(skill <= 1)
- this.bot_canfire = (random() < 0.9);
- else if(skill <= 2)
- this.bot_canfire = (random() < 0.95);
- else
- this.bot_canfire = 1;
-}
-
-float bot_aimdir(entity this, vector v, float maxfiredeviation)
-{
- float dist, delta_t, blend;
- vector desiredang, diffang;
-
- //dprint("aim ", this.netname, ": old:", vtos(this.v_angle));
- // make sure v_angle is sane first
- this.v_angle_y = this.v_angle.y - floor(this.v_angle.y / 360) * 360;
- this.v_angle_z = 0;
-
- // get the desired angles to aim at
- //dprint(" at:", vtos(v));
- v = normalize(v);
- //te_lightning2(NULL, this.origin + this.view_ofs, this.origin + this.view_ofs + v * 200);
- if (time >= this.bot_badaimtime)
- {
- this.bot_badaimtime = max(this.bot_badaimtime + 0.3, time);
- this.bot_badaimoffset = randomvec() * bound(0, 5 - 0.5 * (skill+this.bot_offsetskill), 5) * autocvar_bot_ai_aimskill_offset;
- }
- desiredang = vectoangles(v) + this.bot_badaimoffset;
- //dprint(" desired:", vtos(desiredang));
- if (desiredang.x >= 180)
- desiredang.x = desiredang.x - 360;
- desiredang.x = bound(-90, 0 - desiredang.x, 90);
- desiredang.z = this.v_angle.z;
- //dprint(" / ", vtos(desiredang));
-
- //// pain throws off aim
- //if (this.bot_painintensity)
- //{
- // // shake from pain
- // desiredang = desiredang + randomvec() * this.bot_painintensity * 0.2;
- //}
-
- // calculate turn angles
- diffang = (desiredang - this.bot_olddesiredang);
- // wrap yaw turn
- diffang.y = diffang.y - floor(diffang.y / 360) * 360;
- if (diffang.y >= 180)
- diffang.y = diffang.y - 360;
- this.bot_olddesiredang = desiredang;
- //dprint(" diff:", vtos(diffang));
-
- delta_t = time-this.bot_prevaimtime;
- this.bot_prevaimtime = time;
- // Here we will try to anticipate the comming aiming direction
- this.bot_1st_order_aimfilter= this.bot_1st_order_aimfilter
- + (diffang * (1 / delta_t) - this.bot_1st_order_aimfilter) * bound(0, autocvar_bot_ai_aimskill_order_filter_1st,1);
- this.bot_2nd_order_aimfilter= this.bot_2nd_order_aimfilter
- + (this.bot_1st_order_aimfilter - this.bot_2nd_order_aimfilter) * bound(0, autocvar_bot_ai_aimskill_order_filter_2nd,1);
- this.bot_3th_order_aimfilter= this.bot_3th_order_aimfilter
- + (this.bot_2nd_order_aimfilter - this.bot_3th_order_aimfilter) * bound(0, autocvar_bot_ai_aimskill_order_filter_3th,1);
- this.bot_4th_order_aimfilter= this.bot_4th_order_aimfilter
- + (this.bot_3th_order_aimfilter - this.bot_4th_order_aimfilter) * bound(0, autocvar_bot_ai_aimskill_order_filter_4th,1);
- this.bot_5th_order_aimfilter= this.bot_5th_order_aimfilter
- + (this.bot_4th_order_aimfilter - this.bot_5th_order_aimfilter) * bound(0, autocvar_bot_ai_aimskill_order_filter_5th,1);
-
- //blend = (bound(0,skill,10)*0.1)*pow(1-bound(0,skill,10)*0.05,2.5)*5.656854249; //Plot formule before changing !
- blend = bound(0,skill+this.bot_aimskill,10)*0.1;
- desiredang = desiredang + blend *
- (
- this.bot_1st_order_aimfilter * autocvar_bot_ai_aimskill_order_mix_1st
- + this.bot_2nd_order_aimfilter * autocvar_bot_ai_aimskill_order_mix_2nd
- + this.bot_3th_order_aimfilter * autocvar_bot_ai_aimskill_order_mix_3th
- + this.bot_4th_order_aimfilter * autocvar_bot_ai_aimskill_order_mix_4th
- + this.bot_5th_order_aimfilter * autocvar_bot_ai_aimskill_order_mix_5th
- );
-
- // calculate turn angles
- diffang = desiredang - this.bot_mouseaim;
- // wrap yaw turn
- diffang.y = diffang.y - floor(diffang.y / 360) * 360;
- if (diffang.y >= 180)
- diffang.y = diffang.y - 360;
- //dprint(" diff:", vtos(diffang));
-
- if (time >= this.bot_aimthinktime)
- {
- this.bot_aimthinktime = max(this.bot_aimthinktime + 0.5 - 0.05*(skill+this.bot_thinkskill), time);
- this.bot_mouseaim = this.bot_mouseaim + diffang * (1-random()*0.1*bound(1,10-(skill+this.bot_thinkskill),10));
- }
-
- //this.v_angle = this.v_angle + diffang * bound(0, r * frametime * (skill * 0.5 + 2), 1);
-
- diffang = this.bot_mouseaim - desiredang;
- // wrap yaw turn
- diffang.y = diffang.y - floor(diffang.y / 360) * 360;
- if (diffang.y >= 180)
- diffang.y = diffang.y - 360;
- desiredang = desiredang + diffang * bound(0,autocvar_bot_ai_aimskill_think,1);
-
- // calculate turn angles
- diffang = desiredang - this.v_angle;
- // wrap yaw turn
- diffang.y = diffang.y - floor(diffang.y / 360) * 360;
- if (diffang.y >= 180)
- diffang.y = diffang.y - 360;
- //dprint(" diff:", vtos(diffang));
-
- // jitter tracking
- dist = vlen(diffang);
- //diffang = diffang + randomvec() * (dist * 0.05 * (3.5 - bound(0, skill, 3)));
-
- // turn
- float r, fixedrate, blendrate;
- fixedrate = autocvar_bot_ai_aimskill_fixedrate / bound(1,dist,1000);
- blendrate = autocvar_bot_ai_aimskill_blendrate;
- r = max(fixedrate, blendrate);
- //this.v_angle = this.v_angle + diffang * bound(frametime, r * frametime * (2+skill*skill*0.05-random()*0.05*(10-skill)), 1);
- this.v_angle = this.v_angle + diffang * bound(delta_t, r * delta_t * (2+pow(skill+this.bot_mouseskill,3)*0.005-random()), 1);
- this.v_angle = this.v_angle * bound(0,autocvar_bot_ai_aimskill_mouse,1) + desiredang * bound(0,(1-autocvar_bot_ai_aimskill_mouse),1);
- //this.v_angle = this.v_angle + diffang * bound(0, r * frametime * (skill * 0.5 + 2), 1);
- //this.v_angle = this.v_angle + diffang * (1/ blendrate);
- this.v_angle_z = 0;
- this.v_angle_y = this.v_angle.y - floor(this.v_angle.y / 360) * 360;
- //dprint(" turn:", vtos(this.v_angle));
-
- makevectors(this.v_angle);
- shotorg = this.origin + this.view_ofs;
- shotdir = v_forward;
-
- //dprint(" dir:", vtos(v_forward));
- //te_lightning2(NULL, shotorg, shotorg + shotdir * 100);
-
- // calculate turn angles again
- //diffang = desiredang - this.v_angle;
- //diffang_y = diffang_y - floor(diffang_y / 360) * 360;
- //if (diffang_y >= 180)
- // diffang_y = diffang_y - 360;
-
- //dprint("e ", vtos(diffang), " < ", ftos(maxfiredeviation), "\n");
-
- // decide whether to fire this time
- // note the maxfiredeviation is in degrees so this has to convert to radians first
- //if ((normalize(v) * shotdir) >= cos(maxfiredeviation * (3.14159265358979323846 / 180)))
- if ((normalize(v) * shotdir) >= cos(maxfiredeviation * (3.14159265358979323846 / 180)))
- if(vdist(trace_endpos-shotorg, <, 500 + 500 * bound(0, skill + this.bot_aggresskill, 10)) || random()*random()>bound(0,(skill+this.bot_aggresskill)*0.05,1))
- this.bot_firetimer = time + bound(0.1, 0.5-(skill+this.bot_aggresskill)*0.05, 0.5);
- //traceline(shotorg,shotorg+shotdir*1000,false,NULL);
- //dprint(ftos(maxfiredeviation),"\n");
- //dprint(" diff:", vtos(diffang), "\n");
-
- return this.bot_canfire && (time < this.bot_firetimer);
-}
-
-vector bot_shotlead(vector targorigin, vector targvelocity, float shotspeed, float shotdelay)
-{
- // Try to add code here that predicts gravity effect here, no clue HOW to though ... well not yet atleast...
- return targorigin + targvelocity * (shotdelay + vlen(targorigin - shotorg) / shotspeed);
-}
-
-bool bot_aim(entity this, float shotspeed, float shotspeedupward, float maxshottime, bool applygravity)
-{
- float f, r, hf, distanceratio;
- vector v;
- /*
- eprint(this);
- dprint("bot_aim(", ftos(shotspeed));
- dprint(", ", ftos(shotspeedupward));
- dprint(", ", ftos(maxshottime));
- dprint(", ", ftos(applygravity));
- dprint(");\n");
- */
-
- hf = this.dphitcontentsmask;
- this.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
-
- shotspeed *= W_WeaponSpeedFactor(this);
- shotspeedupward *= W_WeaponSpeedFactor(this);
- if (!shotspeed)
- {
- LOG_TRACE("bot_aim: WARNING: weapon ", PS(this).m_weapon.m_name, " shotspeed is zero!\n");
- shotspeed = 1000000;
- }
- if (!maxshottime)
- {
- LOG_TRACE("bot_aim: WARNING: weapon ", PS(this).m_weapon.m_name, " maxshottime is zero!\n");
- maxshottime = 1;
- }
- makevectors(this.v_angle);
- shotorg = this.origin + this.view_ofs;
- shotdir = v_forward;
- v = bot_shotlead(this.bot_aimtargorigin, this.bot_aimtargvelocity, shotspeed, this.bot_aimlatency);
- distanceratio = sqrt(bound(0,skill,10000))*0.3*(vlen(v-shotorg)-100)/autocvar_bot_ai_aimskill_firetolerance_distdegrees;
- distanceratio = bound(0,distanceratio,1);
- r = (autocvar_bot_ai_aimskill_firetolerance_maxdegrees-autocvar_bot_ai_aimskill_firetolerance_mindegrees)
- * (1-distanceratio) + autocvar_bot_ai_aimskill_firetolerance_mindegrees;
- if (applygravity && this.bot_aimtarg)
- {
- if (!findtrajectorywithleading(shotorg, '0 0 0', '0 0 0', this.bot_aimtarg, shotspeed, shotspeedupward, maxshottime, 0, this))
- {
- this.dphitcontentsmask = hf;
- return false;
- }
-
- f = bot_aimdir(this, findtrajectory_velocity - shotspeedupward * '0 0 1', r);
- }
- else
- {
- f = bot_aimdir(this, v - shotorg, r);
- //dprint("AIM: ");dprint(vtos(this.bot_aimtargorigin));dprint(" + ");dprint(vtos(this.bot_aimtargvelocity));dprint(" * ");dprint(ftos(this.bot_aimlatency + vlen(this.bot_aimtargorigin - shotorg) / shotspeed));dprint(" = ");dprint(vtos(v));dprint(" : aimdir = ");dprint(vtos(normalize(v - shotorg)));dprint(" : ");dprint(vtos(shotdir));dprint("\n");
- //traceline(shotorg, shotorg + shotdir * 10000, false, this);
- //if (trace_ent.takedamage)
- //if (trace_fraction < 1)
- //if (!bot_shouldattack(this, trace_ent))
- // return false;
- traceline(shotorg, this.bot_aimtargorigin, false, this);
- if (trace_fraction < 1)
- if (trace_ent != this.enemy)
- if (!bot_shouldattack(this, trace_ent))
- {
- this.dphitcontentsmask = hf;
- return false;
- }
- }
-
- //if (r > maxshottime * shotspeed)
- // return false;
- this.dphitcontentsmask = hf;
- return true;
-}
+++ /dev/null
-#pragma once
-/*
- * Globals and Fields
- */
-
-entity tracetossent;
-entity tracetossfaketarget;
-vector findtrajectory_velocity;
-
-
-
-vector shotorg;
-vector shotdir;
-
-// lag simulation
-// upto 5 queued messages
-.float lag1_time;
-.float lag1_float1;
-.float lag1_float2;
-.entity lag1_entity1;
-.vector lag1_vec1;
-.vector lag1_vec2;
-.vector lag1_vec3;
-.vector lag1_vec4;
-
-.float lag2_time;
-.float lag2_float1;
-.float lag2_float2;
-.entity lag2_entity1;
-.vector lag2_vec1;
-.vector lag2_vec2;
-.vector lag2_vec3;
-.vector lag2_vec4;
-
-.float lag3_time;
-.float lag3_float1;
-.float lag3_float2;
-.entity lag3_entity1;
-.vector lag3_vec1;
-.vector lag3_vec2;
-.vector lag3_vec3;
-.vector lag3_vec4;
-
-.float lag4_time;
-.float lag4_float1;
-.float lag4_float2;
-.entity lag4_entity1;
-.vector lag4_vec1;
-.vector lag4_vec2;
-.vector lag4_vec3;
-.vector lag4_vec4;
-
-.float lag5_time;
-.float lag5_float1;
-.float lag5_float2;
-.entity lag5_entity1;
-.vector lag5_vec1;
-.vector lag5_vec2;
-.vector lag5_vec3;
-.vector lag5_vec4;
-
-.float bot_badaimtime;
-.float bot_aimthinktime;
-.float bot_prevaimtime;
-.float bot_firetimer;
-.float bot_aimlatency;
-
-.vector bot_mouseaim;
-.vector bot_badaimoffset;
-.vector bot_1st_order_aimfilter;
-.vector bot_2nd_order_aimfilter;
-.vector bot_3th_order_aimfilter;
-.vector bot_4th_order_aimfilter;
-.vector bot_5th_order_aimfilter;
-.vector bot_olddesiredang;
-
-//.vector bot_aimorigin;
-//.vector bot_aimvelocity;
-.vector bot_aimtargorigin;
-.vector bot_aimtargvelocity;
-
-.entity bot_aimtarg;
-
-/*
- * Functions
- */
-
-float lag_additem(entity this, float t, float f1, float f2, entity e1, vector v1, vector v2, vector v3, vector v4);
-void lag_update(entity this);
-void bot_lagfunc(entity this, float t, float f1, float f2, entity e1, vector v1, vector v2, vector v3, vector v4);
-
-float bot_shouldattack(entity this, entity targ);
-float bot_aimdir(entity this, vector v, float maxfiredeviation);
-bool bot_aim(entity this, float shotspeed, float shotspeedupward, float maxshottime, bool applygravity);
-float findtrajectorywithleading(vector org, vector m1, vector m2, entity targ, float shotspeed, float shotspeedupward, float maxtime, float shotdelay, entity ignore);
-
-vector bot_shotlead(vector targorigin, vector targvelocity, float shotspeed, float shotdelay);
-
-.void(entity this, float t, float f1, float f2, entity e1, vector v1, vector v2, vector v3, vector v4) lag_func;
--- /dev/null
+#include "api.qh"
+
+#if 1
+
+#include "default/_mod.inc"
+#include "default/havocbot/_mod.inc"
+
+#else
+
+bool bot_aim(entity this, float shotspeed, float shotspeedupward, float maxshottime, float applygravity) { return false; }
+void bot_clientconnect(entity this) { }
+void bot_clientdisconnect(entity this) { }
+void bot_cmdhelp(string scmd) { }
+void bot_endgame() { }
+bool bot_fixcount() { return true; }
+void bot_list_commands() { }
+void bot_queuecommand(entity bot, string cmdstring) { }
+void bot_relinkplayerlist() { }
+void bot_resetqueues() { }
+void bot_serverframe() { }
+bool bot_shouldattack(entity this, entity e) { return false; }
+void bot_think(entity this) { }
+
+entity find_bot_by_name(string name) { return NULL; }
+entity find_bot_by_number(float number) { return NULL; }
+
+void havocbot_goalrating_controlpoints(entity this, float ratingscale, vector org, float sradius) { }
+void havocbot_goalrating_enemyplayers(entity this, float ratingscale, vector org, float sradius) { }
+void havocbot_goalrating_items(entity this, float ratingscale, vector org, float sradius) { }
+
+entity navigation_findnearestwaypoint(entity ent, float walkfromwp) { return NULL; }
+void navigation_goalrating_end(entity this) { }
+void navigation_goalrating_start(entity this) { }
+void navigation_markroutes(entity this, entity fixed_source_waypoint) { }
+void navigation_markroutes_inverted(entity fixed_source_waypoint) { }
+void navigation_routerating(entity this, entity e, float f, float rangebias) { }
+
+bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float movemode) { return false; }
+
+void waypoint_remove(entity e) { }
+void waypoint_saveall() { }
+void waypoint_schedulerelinkall() { }
+void waypoint_schedulerelink(entity wp) { }
+void waypoint_spawnforitem(entity e) { }
+void waypoint_spawnforitem_force(entity e, vector org) { }
+void waypoint_spawnforteleporter(entity e, vector destination, float timetaken) { }
+void waypoint_spawnforteleporter_v(entity e, vector org, vector destination, float timetaken) { }
+entity waypoint_spawn(vector m1, vector m2, float f) { return NULL; }
+#endif
--- /dev/null
+#pragma once
+
+#include <common/weapons/all.qh>
+
+const int WAYPOINTFLAG_GENERATED = BIT(23);
+const int WAYPOINTFLAG_ITEM = BIT(22);
+const int WAYPOINTFLAG_TELEPORT = BIT(21);
+const int WAYPOINTFLAG_NORELINK = BIT(20);
+const int WAYPOINTFLAG_PERSONAL = BIT(19);
+const int WAYPOINTFLAG_PROTECTED = BIT(18); // Useless WP detection never kills these.
+const int WAYPOINTFLAG_USEFUL = BIT(17); // Useless WP detection temporary flag.
+const int WAYPOINTFLAG_DEAD_END = BIT(16); // Useless WP detection temporary flag.
+
+entity kh_worldkeylist;
+.entity kh_worldkeynext;
+
+float bot_custom_weapon;
+float bot_weapons_close[Weapons_MAX];
+float bot_weapons_far[Weapons_MAX];
+float bot_weapons_mid[Weapons_MAX];
+float skill;
+
+.float bot_attack;
+.float bot_dodgerating;
+.float bot_dodge;
+.float bot_forced_team;
+.float bot_moveskill; // moving technique
+.float bot_pickup;
+.float(entity player, entity item) bot_pickupevalfunc;
+.float bot_strategytime;
+.string cleanname;
+.float havocbot_role_timeout;
+.float isbot; // true if this client is actually a bot
+.float lastteleporttime;
+.float navigation_hasgoals;
+.float nearestwaypointtimeout;
+.entity nearestwaypoint;
+.float speed;
+.entity wp00, wp01, wp02, wp03, wp04, wp05, wp06, wp07, wp08, wp09, wp10, wp11, wp12, wp13, wp14, wp15;
+.entity wp16, wp17, wp18, wp19, wp20, wp21, wp22, wp23, wp24, wp25, wp26, wp27, wp28, wp29, wp30, wp31;
+.float wp00mincost, wp01mincost, wp02mincost, wp03mincost, wp04mincost, wp05mincost, wp06mincost, wp07mincost;
+.float wp08mincost, wp09mincost, wp10mincost, wp11mincost, wp12mincost, wp13mincost, wp14mincost, wp15mincost;
+.float wp16mincost, wp17mincost, wp18mincost, wp19mincost, wp20mincost, wp21mincost, wp22mincost, wp23mincost;
+.float wp24mincost, wp25mincost, wp26mincost, wp27mincost, wp28mincost, wp29mincost, wp30mincost, wp31mincost;
+.float wpconsidered;
+.float wpcost;
+.int wpflags;
+
+bool bot_aim(entity this, float shotspeed, float shotspeedupward, float maxshottime, float applygravity);
+void bot_clientconnect(entity this);
+void bot_clientdisconnect(entity this);
+void bot_cmdhelp(string scmd);
+void bot_endgame();
+bool bot_fixcount();
+void bot_list_commands();
+void bot_queuecommand(entity bot, string cmdstring);
+void bot_relinkplayerlist();
+void bot_resetqueues();
+void bot_serverframe();
+bool bot_shouldattack(entity this, entity e);
+void bot_think(entity this);
+
+entity find_bot_by_name(string name);
+entity find_bot_by_number(float number);
+
+void havocbot_goalrating_controlpoints(entity this, float ratingscale, vector org, float sradius);
+void havocbot_goalrating_enemyplayers(entity this, float ratingscale, vector org, float sradius);
+void havocbot_goalrating_items(entity this, float ratingscale, vector org, float sradius);
+
+entity navigation_findnearestwaypoint(entity ent, float walkfromwp);
+void navigation_goalrating_end(entity this);
+void navigation_goalrating_start(entity this);
+void navigation_markroutes(entity this, entity fixed_source_waypoint);
+void navigation_markroutes_inverted(entity fixed_source_waypoint);
+void navigation_routerating(entity this, entity e, float f, float rangebias);
+
+bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float movemode);
+
+void waypoint_remove(entity e);
+void waypoint_saveall();
+void waypoint_schedulerelinkall();
+void waypoint_schedulerelink(entity wp);
+void waypoint_spawnforitem(entity e);
+void waypoint_spawnforitem_force(entity e, vector org);
+void waypoint_spawnforteleporter(entity e, vector destination, float timetaken);
+void waypoint_spawnforteleporter_v(entity e, vector org, vector destination, float timetaken);
+entity waypoint_spawn(vector m1, vector m2, float f);
+++ /dev/null
-#include "bot.qh"
-
-#include "aim.qh"
-#include "navigation.qh"
-#include "scripting.qh"
-#include "waypoints.qh"
-
-#include "havocbot/havocbot.qh"
-#include "havocbot/scripting.qh"
-
-#include "../teamplay.qh"
-
-#include "../antilag.qh"
-#include "../autocvars.qh"
-#include "../campaign.qh"
-#include "../cl_client.qh"
-#include "../constants.qh"
-#include "../defs.qh"
-#include "../race.qh"
-#include <common/t_items.qh>
-
-#include "../mutators/all.qh"
-
-#include "../weapons/accuracy.qh"
-
-#include <common/physics/player.qh>
-#include <common/constants.qh>
-#include <common/mapinfo.qh>
-#include <common/teams.qh>
-#include <common/util.qh>
-
-#include <common/weapons/all.qh>
-
-#include <lib/csqcmodel/sv_model.qh>
-
-#include <lib/warpzone/common.qh>
-#include <lib/warpzone/util_server.qh>
-
-entity bot_spawn()
-{
- entity bot = spawnclient();
- if (bot)
- {
- currentbots = currentbots + 1;
- bot_setnameandstuff(bot);
- ClientConnect(bot);
- PutClientInServer(bot);
- }
- return bot;
-}
-
-void bot_think(entity this)
-{
- if (this.bot_nextthink > time)
- return;
-
- this.flags &= ~FL_GODMODE;
- if(autocvar_bot_god)
- this.flags |= FL_GODMODE;
-
- this.bot_nextthink = this.bot_nextthink + autocvar_bot_ai_thinkinterval * pow(0.5, this.bot_aiskill);
- //if (this.bot_painintensity > 0)
- // this.bot_painintensity = this.bot_painintensity - (skill + 1) * 40 * frametime;
-
- //this.bot_painintensity = this.bot_painintensity + this.bot_oldhealth - this.health;
- //this.bot_painintensity = bound(0, this.bot_painintensity, 100);
-
- if (!IS_PLAYER(this) || (autocvar_g_campaign && !campaign_bots_may_start))
- {
- this.bot_nextthink = time + 0.5;
- return;
- }
-
- if (this.fixangle)
- {
- this.v_angle = this.angles;
- this.v_angle_z = 0;
- this.fixangle = false;
- }
-
- this.dmg_take = 0;
- this.dmg_save = 0;
- this.dmg_inflictor = NULL;
-
- // calculate an aiming latency based on the skill setting
- // (simulated network latency + naturally delayed reflexes)
- //this.ping = 0.7 - bound(0, 0.05 * skill, 0.5); // moved the reflexes to bot_aimdir (under the name 'think')
- // minimum ping 20+10 random
- this.ping = bound(0,0.07 - bound(0, (skill + this.bot_pingskill) * 0.005,0.05)+random()*0.01,0.65); // Now holds real lag to server, and higer skill players take a less laggy server
- // skill 10 = ping 0.2 (adrenaline)
- // skill 0 = ping 0.7 (slightly drunk)
-
- // clear buttons
- PHYS_INPUT_BUTTON_ATCK(this) = false;
- PHYS_INPUT_BUTTON_JUMP(this) = false;
- PHYS_INPUT_BUTTON_ATCK2(this) = false;
- PHYS_INPUT_BUTTON_ZOOM(this) = false;
- PHYS_INPUT_BUTTON_CROUCH(this) = false;
- PHYS_INPUT_BUTTON_HOOK(this) = false;
- PHYS_INPUT_BUTTON_INFO(this) = false;
- PHYS_INPUT_BUTTON_DRAG(this) = false;
- PHYS_INPUT_BUTTON_CHAT(this) = false;
- PHYS_INPUT_BUTTON_USE(this) = false;
-
- if (time < game_starttime)
- {
- // block the bot during the countdown to game start
- this.movement = '0 0 0';
- this.bot_nextthink = game_starttime;
- return;
- }
-
- // if dead, just wait until we can respawn
- if (IS_DEAD(this))
- {
- if (this.deadflag == DEAD_DEAD)
- {
- PHYS_INPUT_BUTTON_JUMP(this) = true; // press jump to respawn
- this.bot_strategytime = 0;
- }
- }
- else if(this.aistatus & AI_STATUS_STUCK)
- navigation_unstuck(this);
-
- // now call the current bot AI (havocbot for example)
- this.bot_ai(this);
-}
-
-void bot_setnameandstuff(entity this)
-{
- string readfile, s;
- float file, tokens, prio;
-
- string bot_name, bot_model, bot_skin, bot_shirt, bot_pants;
- string name, prefix, suffix;
-
- if(autocvar_g_campaign)
- {
- prefix = "";
- suffix = "";
- }
- else
- {
- prefix = autocvar_bot_prefix;
- suffix = autocvar_bot_suffix;
- }
-
- file = fopen(autocvar_bot_config_file, FILE_READ);
-
- if(file < 0)
- {
- LOG_INFO(strcat("Error: Can not open the bot configuration file '",autocvar_bot_config_file,"'\n"));
- readfile = "";
- }
- else
- {
- RandomSelection_Init();
- while((readfile = fgets(file)))
- {
- if(substring(readfile, 0, 2) == "//")
- continue;
- if(substring(readfile, 0, 1) == "#")
- continue;
- tokens = tokenizebyseparator(readfile, "\t");
- if(tokens == 0)
- continue;
- s = argv(0);
- prio = 1;
- FOREACH_CLIENT(IS_BOT_CLIENT(it), LAMBDA(
- if(s == it.cleanname)
- {
- prio = 0;
- break;
- }
- ));
- RandomSelection_Add(NULL, 0, readfile, 1, prio);
- }
- readfile = RandomSelection_chosen_string;
- fclose(file);
- }
-
- tokens = tokenizebyseparator(readfile, "\t");
- if(argv(0) != "") bot_name = argv(0);
- else bot_name = "Bot";
-
- if(argv(1) != "") bot_model = argv(1);
- else bot_model = "";
-
- if(argv(2) != "") bot_skin = argv(2);
- else bot_skin = "0";
-
- if(argv(3) != "" && stof(argv(3)) >= 0) bot_shirt = argv(3);
- else bot_shirt = ftos(floor(random() * 15));
-
- if(argv(4) != "" && stof(argv(4)) >= 0) bot_pants = argv(4);
- else bot_pants = ftos(floor(random() * 15));
-
- this.bot_forced_team = stof(argv(5));
-
- prio = 6;
-
- #define READSKILL(f,w,r) if(argv(prio) != "") this.f = stof(argv(prio)) * (w); else this.f = (!autocvar_g_campaign) * (2 * random() - 1) * (r) * (w); ++prio
- //print(bot_name, ": ping=", argv(9), "\n");
-
- READSKILL(havocbot_keyboardskill, 0.5, 0.5); // keyboard skill
- READSKILL(bot_moveskill, 2, 0); // move skill
- READSKILL(bot_dodgeskill, 2, 0); // dodge skill
-
- READSKILL(bot_pingskill, 0.5, 0); // ping skill
-
- READSKILL(bot_weaponskill, 2, 0); // weapon skill
- READSKILL(bot_aggresskill, 1, 0); // aggre skill
- READSKILL(bot_rangepreference, 1, 0); // read skill
-
- READSKILL(bot_aimskill, 2, 0); // aim skill
- READSKILL(bot_offsetskill, 2, 0.5); // offset skill
- READSKILL(bot_mouseskill, 1, 0.5); // mouse skill
-
- READSKILL(bot_thinkskill, 1, 0.5); // think skill
- READSKILL(bot_aiskill, 2, 0); // "ai" skill
-
- this.bot_config_loaded = true;
-
- // this is really only a default, JoinBestTeam is called later
- setcolor(this, stof(bot_shirt) * 16 + stof(bot_pants));
- this.bot_preferredcolors = this.clientcolors;
-
- // pick the name
- if (autocvar_bot_usemodelnames)
- name = bot_model;
- else
- name = bot_name;
-
- // number bots with identical names
- int j = 0;
- FOREACH_CLIENT(IS_BOT_CLIENT(it), LAMBDA(
- if(it.cleanname == name)
- ++j;
- ));
- if (j)
- this.netname = this.netname_freeme = strzone(strcat(prefix, name, "(", ftos(j), ")", suffix));
- else
- this.netname = this.netname_freeme = strzone(strcat(prefix, name, suffix));
-
- this.cleanname = strzone(name);
-
- // pick the model and skin
- if(substring(bot_model, -4, 1) != ".")
- bot_model = strcat(bot_model, ".iqm");
- this.playermodel = this.playermodel_freeme = strzone(strcat("models/player/", bot_model));
- this.playerskin = this.playerskin_freeme = strzone(bot_skin);
-
- this.cvar_cl_accuracy_data_share = 1; // share the bots weapon accuracy data with the NULL
- this.cvar_cl_accuracy_data_receive = 0; // don't receive any weapon accuracy data
-}
-
-void bot_custom_weapon_priority_setup()
-{
- float tokens, i, w;
-
- bot_custom_weapon = false;
-
- if( autocvar_bot_ai_custom_weapon_priority_far == "" ||
- autocvar_bot_ai_custom_weapon_priority_mid == "" ||
- autocvar_bot_ai_custom_weapon_priority_close == "" ||
- autocvar_bot_ai_custom_weapon_priority_distances == ""
- )
- return;
-
- // Parse distances
- tokens = tokenizebyseparator(autocvar_bot_ai_custom_weapon_priority_distances," ");
-
- if (tokens!=2)
- return;
-
- bot_distance_far = stof(argv(0));
- bot_distance_close = stof(argv(1));
-
- if(bot_distance_far < bot_distance_close){
- bot_distance_far = stof(argv(1));
- bot_distance_close = stof(argv(0));
- }
-
- // Initialize list of weapons
- bot_weapons_far[0] = -1;
- bot_weapons_mid[0] = -1;
- bot_weapons_close[0] = -1;
-
- // Parse far distance weapon priorities
- tokens = tokenizebyseparator(W_NumberWeaponOrder(autocvar_bot_ai_custom_weapon_priority_far)," ");
-
- int c = 0;
- for(i=0; i < tokens && c < Weapons_COUNT; ++i){
- w = stof(argv(i));
- if ( w >= WEP_FIRST && w <= WEP_LAST) {
- bot_weapons_far[c] = w;
- ++c;
- }
- }
- if(c < Weapons_COUNT)
- bot_weapons_far[c] = -1;
-
- // Parse mid distance weapon priorities
- tokens = tokenizebyseparator(W_NumberWeaponOrder(autocvar_bot_ai_custom_weapon_priority_mid)," ");
-
- c = 0;
- for(i=0; i < tokens && c < Weapons_COUNT; ++i){
- w = stof(argv(i));
- if ( w >= WEP_FIRST && w <= WEP_LAST) {
- bot_weapons_mid[c] = w;
- ++c;
- }
- }
- if(c < Weapons_COUNT)
- bot_weapons_mid[c] = -1;
-
- // Parse close distance weapon priorities
- tokens = tokenizebyseparator(W_NumberWeaponOrder(autocvar_bot_ai_custom_weapon_priority_close)," ");
-
- c = 0;
- for(i=0; i < tokens && i < Weapons_COUNT; ++i){
- w = stof(argv(i));
- if ( w >= WEP_FIRST && w <= WEP_LAST) {
- bot_weapons_close[c] = w;
- ++c;
- }
- }
- if(c < Weapons_COUNT)
- bot_weapons_close[c] = -1;
-
- bot_custom_weapon = true;
-}
-
-void bot_endgame()
-{
- entity e;
- //dprint("bot_endgame\n");
- e = bot_list;
- while (e)
- {
- setcolor(e, e.bot_preferredcolors);
- e = e.nextbot;
- }
- // if dynamic waypoints are ever implemented, save them here
-}
-
-void bot_relinkplayerlist()
-{
- player_count = 0;
- currentbots = 0;
- bot_list = NULL;
-
- entity prevbot = NULL;
- FOREACH_CLIENT(true,
- {
- ++player_count;
-
- if(IS_BOT_CLIENT(it))
- {
- if(prevbot)
- prevbot.nextbot = it;
- else
- {
- bot_list = it;
- bot_list.nextbot = NULL;
- }
- prevbot = it;
- ++currentbots;
- }
- });
- LOG_TRACE(strcat("relink: ", ftos(currentbots), " bots seen.\n"));
- bot_strategytoken = bot_list;
- bot_strategytoken_taken = true;
-}
-
-void bot_clientdisconnect(entity this)
-{
- if (!IS_BOT_CLIENT(this))
- return;
- bot_clearqueue(this);
- if(this.cleanname)
- strunzone(this.cleanname);
- if(this.netname_freeme)
- strunzone(this.netname_freeme);
- if(this.playermodel_freeme)
- strunzone(this.playermodel_freeme);
- if(this.playerskin_freeme)
- strunzone(this.playerskin_freeme);
- this.cleanname = string_null;
- this.netname_freeme = string_null;
- this.playermodel_freeme = string_null;
- this.playerskin_freeme = string_null;
- if(this.bot_cmd_current)
- remove(this.bot_cmd_current);
- if(bot_waypoint_queue_owner==this)
- bot_waypoint_queue_owner = NULL;
-}
-
-void bot_clientconnect(entity this)
-{
- if (!IS_BOT_CLIENT(this)) return;
- this.bot_preferredcolors = this.clientcolors;
- this.bot_nextthink = time - random();
- this.lag_func = bot_lagfunc;
- this.isbot = true;
- this.createdtime = this.bot_nextthink;
-
- if(!this.bot_config_loaded) // This is needed so team overrider doesn't break between matches
- bot_setnameandstuff(this);
-
- if(this.bot_forced_team==1)
- this.team = NUM_TEAM_1;
- else if(this.bot_forced_team==2)
- this.team = NUM_TEAM_2;
- else if(this.bot_forced_team==3)
- this.team = NUM_TEAM_3;
- else if(this.bot_forced_team==4)
- this.team = NUM_TEAM_4;
- else
- JoinBestTeam(this, false, true);
-
- havocbot_setupbot(this);
-}
-
-void bot_removefromlargestteam()
-{
- CheckAllowedTeams(NULL);
- GetTeamCounts(NULL);
-
- entity best = NULL;
- float besttime = 0;
- int bestcount = 0;
-
- int bcount = 0;
- FOREACH_ENTITY_FLOAT(isbot, true,
- {
- ++bcount;
-
- if(!best)
- {
- best = it;
- besttime = it.createdtime;
- }
-
- int thiscount = 0;
-
- switch(it.team)
- {
- case NUM_TEAM_1: thiscount = c1; break;
- case NUM_TEAM_2: thiscount = c2; break;
- case NUM_TEAM_3: thiscount = c3; break;
- case NUM_TEAM_4: thiscount = c4; break;
- }
-
- if(thiscount > bestcount)
- {
- bestcount = thiscount;
- besttime = it.createdtime;
- best = it;
- }
- else if(thiscount == bestcount && besttime < it.createdtime)
- {
- besttime = it.createdtime;
- best = it;
- }
- });
- if(!bcount)
- return; // no bots to remove
- currentbots = currentbots - 1;
- dropclient(best);
-}
-
-void bot_removenewest()
-{
- if(teamplay)
- {
- bot_removefromlargestteam();
- return;
- }
-
- float besttime = 0;
- entity best = NULL;
- int bcount = 0;
-
- FOREACH_ENTITY_FLOAT(isbot, true,
- {
- ++bcount;
-
- if(!best)
- {
- best = it;
- besttime = it.createdtime;
- }
-
- if(besttime < it.createdtime)
- {
- besttime = it.createdtime;
- best = it;
- }
- });
-
- if(!bcount)
- return; // no bots to remove
-
- currentbots = currentbots - 1;
- dropclient(best);
-}
-
-void autoskill(float factor)
-{
- float bestbot;
- float bestplayer;
-
- bestbot = -1;
- bestplayer = -1;
- FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
- if(IS_REAL_CLIENT(it))
- bestplayer = max(bestplayer, it.totalfrags - it.totalfrags_lastcheck);
- else
- bestbot = max(bestbot, it.totalfrags - it.totalfrags_lastcheck);
- ));
-
- LOG_TRACE("autoskill: best player got ", ftos(bestplayer), ", ");
- LOG_TRACE("best bot got ", ftos(bestbot), "; ");
- if(bestbot < 0 || bestplayer < 0)
- {
- LOG_TRACE("not doing anything\n");
- // don't return, let it reset all counters below
- }
- else if(bestbot <= bestplayer * factor - 2)
- {
- if(autocvar_skill < 17)
- {
- LOG_TRACE("2 frags difference, increasing skill\n");
- cvar_set("skill", ftos(autocvar_skill + 1));
- bprint("^2SKILL UP!^7 Now at level ", ftos(autocvar_skill), "\n");
- }
- }
- else if(bestbot >= bestplayer * factor + 2)
- {
- if(autocvar_skill > 0)
- {
- LOG_TRACE("2 frags difference, decreasing skill\n");
- cvar_set("skill", ftos(autocvar_skill - 1));
- bprint("^1SKILL DOWN!^7 Now at level ", ftos(autocvar_skill), "\n");
- }
- }
- else
- {
- LOG_TRACE("not doing anything\n");
- return;
- // don't reset counters, wait for them to accumulate
- }
-
- FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(it.totalfrags_lastcheck = it.totalfrags));
-}
-
-void bot_calculate_stepheightvec()
-{
- stepheightvec = autocvar_sv_stepheight * '0 0 1';
- jumpstepheightvec = stepheightvec +
- ((autocvar_sv_jumpvelocity * autocvar_sv_jumpvelocity) / (2 * autocvar_sv_gravity)) * '0 0 0.85';
- // 0.75 factor is for safety to make the jumps easy
-}
-
-float bot_fixcount()
-{
- int activerealplayers = 0;
- int realplayers = 0;
- if (MUTATOR_CALLHOOK(Bot_FixCount, activerealplayers, realplayers)) {
- activerealplayers = M_ARGV(0, int);
- realplayers = M_ARGV(1, int);
- } else {
- FOREACH_CLIENT(IS_REAL_CLIENT(it), LAMBDA(
- if(IS_PLAYER(it))
- ++activerealplayers;
- ++realplayers;
- ));
- }
-
- int bots;
- // add/remove bots if needed to make sure there are at least
- // minplayers+bot_number, or remove all bots if no one is playing
- // But don't remove bots immediately on level change, as the real players
- // usually haven't rejoined yet
- bots_would_leave = false;
- if (teamplay && autocvar_bot_vs_human && AvailableTeams() == 2)
- bots = min(ceil(fabs(autocvar_bot_vs_human) * activerealplayers), maxclients - realplayers);
- else if ((realplayers || autocvar_bot_join_empty || (currentbots > 0 && time < 5)))
- {
- float realminplayers, minplayers;
- realminplayers = autocvar_minplayers;
- minplayers = max(0, floor(realminplayers));
-
- float realminbots, minbots;
- realminbots = autocvar_bot_number;
- minbots = max(0, floor(realminbots));
-
- bots = min(max(minbots, minplayers - activerealplayers), maxclients - realplayers);
- if(bots > minbots)
- bots_would_leave = true;
- }
- else
- {
- // if there are no players, remove bots
- bots = 0;
- }
-
- // only add one bot per frame to avoid utter chaos
- if(time > botframe_nextthink)
- {
- //dprint(ftos(bots), " ? ", ftos(currentbots), "\n");
- while (currentbots < bots)
- {
- if (bot_spawn() == NULL)
- {
- bprint("Can not add bot, server full.\n");
- return false;
- }
- }
- while (currentbots > bots)
- bot_removenewest();
- }
-
- return true;
-}
-
-void bot_serverframe()
-{
- if (intermission_running)
- return;
-
- if (time < 2)
- return;
-
- bot_calculate_stepheightvec();
- bot_navigation_movemode = ((autocvar_bot_navigation_ignoreplayers) ? MOVE_NOMONSTERS : MOVE_NORMAL);
-
- if(time > autoskill_nextthink)
- {
- float a;
- a = autocvar_skill_auto;
- if(a)
- autoskill(a);
- autoskill_nextthink = time + 5;
- }
-
- if(time > botframe_nextthink)
- {
- if(!bot_fixcount())
- botframe_nextthink = time + 10;
- }
-
- bot_ignore_bots = autocvar_bot_ignore_bots;
-
- if(botframe_spawnedwaypoints)
- {
- if(autocvar_waypoint_benchmark)
- localcmd("quit\n");
- }
-
- if (currentbots > 0 || autocvar_g_waypointeditor || autocvar_g_waypointeditor_auto)
- if (botframe_spawnedwaypoints)
- {
- if(botframe_cachedwaypointlinks)
- {
- if(!botframe_loadedforcedlinks)
- waypoint_load_links_hardwired();
- }
- else
- {
- // TODO: Make this check cleaner
- IL_EACH(g_waypoints, time - it.nextthink > 10,
- {
- waypoint_save_links();
- break;
- });
- }
- }
- else
- {
- botframe_spawnedwaypoints = true;
- waypoint_loadall();
- if(!waypoint_load_links())
- waypoint_schedulerelinkall();
- }
-
- if (bot_list)
- {
- // cycle the goal token from one bot to the next each frame
- // (this prevents them from all doing spawnfunc_waypoint searches on the same
- // frame, which causes choppy framerates)
- if (bot_strategytoken_taken)
- {
- bot_strategytoken_taken = false;
- if (bot_strategytoken)
- bot_strategytoken = bot_strategytoken.nextbot;
- if (!bot_strategytoken)
- bot_strategytoken = bot_list;
- }
-
- if (botframe_nextdangertime < time)
- {
- float interval;
- interval = autocvar_bot_ai_dangerdetectioninterval;
- if (botframe_nextdangertime < time - interval * 1.5)
- botframe_nextdangertime = time;
- botframe_nextdangertime = botframe_nextdangertime + interval;
- botframe_updatedangerousobjects(autocvar_bot_ai_dangerdetectionupdates);
- }
- }
-
- if (autocvar_g_waypointeditor)
- botframe_showwaypointlinks();
-
- if (autocvar_g_waypointeditor_auto)
- botframe_autowaypoints();
-
- if(time > bot_cvar_nextthink)
- {
- if(currentbots>0)
- bot_custom_weapon_priority_setup();
- bot_cvar_nextthink = time + 5;
- }
-}
+++ /dev/null
-#pragma once
-/*
- * Globals and Fields
- */
-
-const int AI_STATUS_ROAMING = BIT(0); // Bot is just crawling the map. No enemies at sight
-const int AI_STATUS_ATTACKING = BIT(1); // There are enemies at sight
-const int AI_STATUS_RUNNING = BIT(2); // Bot is bunny hopping
-const int AI_STATUS_DANGER_AHEAD = BIT(3); // There is lava/slime/trigger_hurt ahead
-const int AI_STATUS_OUT_JUMPPAD = BIT(4); // Trying to get out of a "vertical" jump pad
-const int AI_STATUS_OUT_WATER = BIT(5); // Trying to get out of water
-const int AI_STATUS_WAYPOINT_PERSONAL_LINKING = BIT(6); // Waiting for the personal waypoint to be linked
-const int AI_STATUS_WAYPOINT_PERSONAL_GOING = BIT(7); // Going to a personal waypoint
-const int AI_STATUS_WAYPOINT_PERSONAL_REACHED = BIT(8); // Personal waypoint reached
-const int AI_STATUS_JETPACK_FLYING = BIT(9);
-const int AI_STATUS_JETPACK_LANDING = BIT(10);
-const int AI_STATUS_STUCK = BIT(11); // Cannot reach any goal
-
-.float isbot; // true if this client is actually a bot
-.int aistatus;
-
-// Skill system
-float skill;
-float autoskill_nextthink;
-
-// havocbot_keyboardskill // keyboard movement
-.float bot_moveskill; // moving technique
-.float bot_dodgeskill; // dodging
-
-.float bot_pingskill; // ping offset
-
-.float bot_weaponskill; // weapon usage skill (combos, e.g.)
-.float bot_aggresskill; // aggressivity, controls "think before fire" behaviour
-.float bot_rangepreference; // weapon choice offset for range (>0 = prefer long range earlier "sniper", <0 = prefer short range "spammer")
-
-.float bot_aimskill; // aim accuracy
-.float bot_offsetskill; // aim breakage
-.float bot_mouseskill; // mouse "speed"
-
-.float bot_thinkskill; // target choice
-.float bot_aiskill; // strategy choice
-
-.float totalfrags_lastcheck;
-
-// Custom weapon priorities
-float bot_custom_weapon;
-float bot_distance_far;
-float bot_distance_close;
-
-float bot_weapons_far[Weapons_MAX];
-float bot_weapons_mid[Weapons_MAX];
-float bot_weapons_close[Weapons_MAX];
-
-entity bot_list;
-.entity nextbot;
-.string cleanname;
-.string netname_freeme;
-.string playermodel_freeme;
-.string playerskin_freeme;
-
-.float bot_nextthink;
-
-.float createdtime;
-.float bot_preferredcolors;
-.float bot_attack;
-.float bot_dodge;
-.float bot_dodgerating;
-
-.float bot_pickup;
-.float bot_pickupbasevalue;
-.float bot_canfire;
-.float bot_strategytime;
-
-.float bot_forced_team;
-.float bot_config_loaded;
-
-float bot_strategytoken_taken;
-entity bot_strategytoken;
-
-float botframe_spawnedwaypoints;
-float botframe_nextthink;
-float botframe_nextdangertime;
-float bot_cvar_nextthink;
-float bot_ignore_bots; // let bots not attack other bots (only works in non-teamplay)
-
-/*
- * Functions
- */
-
-entity bot_spawn();
-float bot_fixcount();
-
-void bot_think(entity this);
-void bot_setnameandstuff(entity this);
-void bot_custom_weapon_priority_setup();
-void bot_endgame();
-void bot_relinkplayerlist();
-void bot_clientdisconnect(entity this);
-void bot_clientconnect(entity this);
-void bot_removefromlargestteam();
-void bot_removenewest();
-void autoskill(float factor);
-void bot_serverframe();
-
-.void(entity this) bot_ai;
-.float(entity player, entity item) bot_pickupevalfunc;
-
-/*
- * Imports
- */
-
-void(entity this) havocbot_setupbot;
-
-void bot_calculate_stepheightvec();
--- /dev/null
+// generated file; do not modify
+#include <server/bot/default/aim.qc>
+#include <server/bot/default/bot.qc>
+#include <server/bot/default/cvars.qc>
+#include <server/bot/default/navigation.qc>
+#include <server/bot/default/scripting.qc>
+#include <server/bot/default/waypoints.qc>
--- /dev/null
+// generated file; do not modify
+#include <server/bot/default/aim.qh>
+#include <server/bot/default/bot.qh>
+#include <server/bot/default/cvars.qh>
+#include <server/bot/default/navigation.qh>
+#include <server/bot/default/scripting.qh>
+#include <server/bot/default/waypoints.qh>
--- /dev/null
+#include "aim.qh"
+
+#include "cvars.qh"
+
+#include "bot.qh"
+
+#include <common/physics/player.qh>
+#include <common/state.qh>
+
+#include "../../weapons/weaponsystem.qh"
+
+#include "../../mutators/all.qh"
+
+// traces multiple trajectories to find one that will impact the target
+// 'end' vector is the place it aims for,
+// returns true only if it hit targ (don't target non-solid entities)
+
+float findtrajectorywithleading(vector org, vector m1, vector m2, entity targ, float shotspeed, float shotspeedupward, float maxtime, float shotdelay, entity ignore)
+{
+ float c, savesolid, shottime;
+ vector dir, end, v, o;
+ if (shotspeed < 1)
+ return false; // could cause division by zero if calculated
+ if (targ.solid < SOLID_BBOX) // SOLID_NOT and SOLID_TRIGGER
+ return false; // could never hit it
+ if (!tracetossent)
+ tracetossent = new(tracetossent);
+ tracetossent.owner = ignore;
+ setsize(tracetossent, m1, m2);
+ savesolid = targ.solid;
+ targ.solid = SOLID_NOT;
+ o = (targ.absmin + targ.absmax) * 0.5;
+ shottime = ((vlen(o - org) / shotspeed) + shotdelay);
+ v = targ.velocity * shottime + o;
+ tracebox(o, targ.mins, targ.maxs, v, false, targ);
+ v = trace_endpos;
+ end = v + (targ.mins + targ.maxs) * 0.5;
+ if ((vlen(end - org) / shotspeed + 0.2) > maxtime)
+ {
+ // out of range
+ targ.solid = savesolid;
+ return false;
+ }
+
+ if (!tracetossfaketarget)
+ tracetossfaketarget = new(tracetossfaketarget);
+ tracetossfaketarget.solid = savesolid;
+ set_movetype(tracetossfaketarget, targ.move_movetype);
+ _setmodel(tracetossfaketarget, targ.model); // no low precision
+ tracetossfaketarget.model = targ.model;
+ tracetossfaketarget.modelindex = targ.modelindex;
+ setsize(tracetossfaketarget, targ.mins, targ.maxs);
+ setorigin(tracetossfaketarget, v);
+
+ c = 0;
+ dir = normalize(end - org);
+ while (c < 10) // 10 traces
+ {
+ setorigin(tracetossent, org); // reset
+ tracetossent.velocity = findtrajectory_velocity = normalize(dir) * shotspeed + shotspeedupward * '0 0 1';
+ tracetoss(tracetossent, ignore); // love builtin functions...
+ if (trace_ent == tracetossfaketarget) // done
+ {
+ targ.solid = savesolid;
+
+ // make it disappear
+ tracetossfaketarget.solid = SOLID_NOT;
+ set_movetype(tracetossfaketarget, MOVETYPE_NONE);
+ tracetossfaketarget.model = "";
+ tracetossfaketarget.modelindex = 0;
+ // relink to remove it from physics considerations
+ setorigin(tracetossfaketarget, v);
+
+ return true;
+ }
+ dir.z = dir.z + 0.1; // aim up a little more
+ c = c + 1;
+ }
+ targ.solid = savesolid;
+
+ // make it disappear
+ tracetossfaketarget.solid = SOLID_NOT;
+ set_movetype(tracetossfaketarget, MOVETYPE_NONE);
+ tracetossfaketarget.model = "";
+ tracetossfaketarget.modelindex = 0;
+ // relink to remove it from physics considerations
+ setorigin(tracetossfaketarget, v);
+
+ // leave a valid one even if it won't reach
+ findtrajectory_velocity = normalize(end - org) * shotspeed + shotspeedupward * '0 0 1';
+ return false;
+}
+
+void lag_update(entity this)
+{
+ if (this.lag1_time) if (time > this.lag1_time) {this.lag_func(this, this.lag1_time, this.lag1_float1, this.lag1_float2, this.lag1_entity1, this.lag1_vec1, this.lag1_vec2, this.lag1_vec3, this.lag1_vec4);this.lag1_time = 0;}
+ if (this.lag2_time) if (time > this.lag2_time) {this.lag_func(this, this.lag2_time, this.lag2_float1, this.lag2_float2, this.lag2_entity1, this.lag2_vec1, this.lag2_vec2, this.lag2_vec3, this.lag2_vec4);this.lag2_time = 0;}
+ if (this.lag3_time) if (time > this.lag3_time) {this.lag_func(this, this.lag3_time, this.lag3_float1, this.lag3_float2, this.lag3_entity1, this.lag3_vec1, this.lag3_vec2, this.lag3_vec3, this.lag3_vec4);this.lag3_time = 0;}
+ if (this.lag4_time) if (time > this.lag4_time) {this.lag_func(this, this.lag4_time, this.lag4_float1, this.lag4_float2, this.lag4_entity1, this.lag4_vec1, this.lag4_vec2, this.lag4_vec3, this.lag4_vec4);this.lag4_time = 0;}
+ if (this.lag5_time) if (time > this.lag5_time) {this.lag_func(this, this.lag5_time, this.lag5_float1, this.lag5_float2, this.lag5_entity1, this.lag5_vec1, this.lag5_vec2, this.lag5_vec3, this.lag5_vec4);this.lag5_time = 0;}
+}
+
+float lag_additem(entity this, float t, float f1, float f2, entity e1, vector v1, vector v2, vector v3, vector v4)
+{
+ if (this.lag1_time == 0) {this.lag1_time = t;this.lag1_float1 = f1;this.lag1_float2 = f2;this.lag1_entity1 = e1;this.lag1_vec1 = v1;this.lag1_vec2 = v2;this.lag1_vec3 = v3;this.lag1_vec4 = v4;return true;}
+ if (this.lag2_time == 0) {this.lag2_time = t;this.lag2_float1 = f1;this.lag2_float2 = f2;this.lag2_entity1 = e1;this.lag2_vec1 = v1;this.lag2_vec2 = v2;this.lag2_vec3 = v3;this.lag2_vec4 = v4;return true;}
+ if (this.lag3_time == 0) {this.lag3_time = t;this.lag3_float1 = f1;this.lag3_float2 = f2;this.lag3_entity1 = e1;this.lag3_vec1 = v1;this.lag3_vec2 = v2;this.lag3_vec3 = v3;this.lag3_vec4 = v4;return true;}
+ if (this.lag4_time == 0) {this.lag4_time = t;this.lag4_float1 = f1;this.lag4_float2 = f2;this.lag4_entity1 = e1;this.lag4_vec1 = v1;this.lag4_vec2 = v2;this.lag4_vec3 = v3;this.lag4_vec4 = v4;return true;}
+ if (this.lag5_time == 0) {this.lag5_time = t;this.lag5_float1 = f1;this.lag5_float2 = f2;this.lag5_entity1 = e1;this.lag5_vec1 = v1;this.lag5_vec2 = v2;this.lag5_vec3 = v3;this.lag5_vec4 = v4;return true;}
+ // no room for it (what is the best thing to do here??)
+ return false;
+}
+
+bool bot_shouldattack(entity this, entity targ)
+{
+ if (targ.team == this.team)
+ {
+ if (targ == this)
+ return false;
+ if (teamplay)
+ if (targ.team != 0)
+ return false;
+ }
+
+ if(STAT(FROZEN, targ))
+ return false;
+
+ if(teamplay)
+ {
+ if(targ.team==0)
+ return false;
+ }
+ else if(bot_ignore_bots)
+ if(IS_BOT_CLIENT(targ))
+ return false;
+
+ if (!targ.takedamage)
+ return false;
+ if (IS_DEAD(targ))
+ return false;
+ if (PHYS_INPUT_BUTTON_CHAT(targ))
+ return false;
+ if(targ.flags & FL_NOTARGET)
+ return false;
+
+ if(MUTATOR_CALLHOOK(BotShouldAttack, this, targ))
+ return false;
+
+ return true;
+}
+
+void bot_lagfunc(entity this, float t, float f1, float f2, entity e1, vector v1, vector v2, vector v3, vector v4)
+{
+ if(this.flags & FL_INWATER)
+ {
+ this.bot_aimtarg = NULL;
+ return;
+ }
+ this.bot_aimtarg = e1;
+ this.bot_aimlatency = this.ping; // FIXME? Shouldn't this be in the lag item?
+ //this.bot_aimorigin = v1;
+ //this.bot_aimvelocity = v2;
+ this.bot_aimtargorigin = v3;
+ this.bot_aimtargvelocity = v4;
+ if(skill <= 0)
+ this.bot_canfire = (random() < 0.8);
+ else if(skill <= 1)
+ this.bot_canfire = (random() < 0.9);
+ else if(skill <= 2)
+ this.bot_canfire = (random() < 0.95);
+ else
+ this.bot_canfire = 1;
+}
+
+float bot_aimdir(entity this, vector v, float maxfiredeviation)
+{
+ float dist, delta_t, blend;
+ vector desiredang, diffang;
+
+ //dprint("aim ", this.netname, ": old:", vtos(this.v_angle));
+ // make sure v_angle is sane first
+ this.v_angle_y = this.v_angle.y - floor(this.v_angle.y / 360) * 360;
+ this.v_angle_z = 0;
+
+ // get the desired angles to aim at
+ //dprint(" at:", vtos(v));
+ v = normalize(v);
+ //te_lightning2(NULL, this.origin + this.view_ofs, this.origin + this.view_ofs + v * 200);
+ if (time >= this.bot_badaimtime)
+ {
+ this.bot_badaimtime = max(this.bot_badaimtime + 0.3, time);
+ this.bot_badaimoffset = randomvec() * bound(0, 5 - 0.5 * (skill+this.bot_offsetskill), 5) * autocvar_bot_ai_aimskill_offset;
+ }
+ desiredang = vectoangles(v) + this.bot_badaimoffset;
+ //dprint(" desired:", vtos(desiredang));
+ if (desiredang.x >= 180)
+ desiredang.x = desiredang.x - 360;
+ desiredang.x = bound(-90, 0 - desiredang.x, 90);
+ desiredang.z = this.v_angle.z;
+ //dprint(" / ", vtos(desiredang));
+
+ //// pain throws off aim
+ //if (this.bot_painintensity)
+ //{
+ // // shake from pain
+ // desiredang = desiredang + randomvec() * this.bot_painintensity * 0.2;
+ //}
+
+ // calculate turn angles
+ diffang = (desiredang - this.bot_olddesiredang);
+ // wrap yaw turn
+ diffang.y = diffang.y - floor(diffang.y / 360) * 360;
+ if (diffang.y >= 180)
+ diffang.y = diffang.y - 360;
+ this.bot_olddesiredang = desiredang;
+ //dprint(" diff:", vtos(diffang));
+
+ delta_t = time-this.bot_prevaimtime;
+ this.bot_prevaimtime = time;
+ // Here we will try to anticipate the comming aiming direction
+ this.bot_1st_order_aimfilter= this.bot_1st_order_aimfilter
+ + (diffang * (1 / delta_t) - this.bot_1st_order_aimfilter) * bound(0, autocvar_bot_ai_aimskill_order_filter_1st,1);
+ this.bot_2nd_order_aimfilter= this.bot_2nd_order_aimfilter
+ + (this.bot_1st_order_aimfilter - this.bot_2nd_order_aimfilter) * bound(0, autocvar_bot_ai_aimskill_order_filter_2nd,1);
+ this.bot_3th_order_aimfilter= this.bot_3th_order_aimfilter
+ + (this.bot_2nd_order_aimfilter - this.bot_3th_order_aimfilter) * bound(0, autocvar_bot_ai_aimskill_order_filter_3th,1);
+ this.bot_4th_order_aimfilter= this.bot_4th_order_aimfilter
+ + (this.bot_3th_order_aimfilter - this.bot_4th_order_aimfilter) * bound(0, autocvar_bot_ai_aimskill_order_filter_4th,1);
+ this.bot_5th_order_aimfilter= this.bot_5th_order_aimfilter
+ + (this.bot_4th_order_aimfilter - this.bot_5th_order_aimfilter) * bound(0, autocvar_bot_ai_aimskill_order_filter_5th,1);
+
+ //blend = (bound(0,skill,10)*0.1)*pow(1-bound(0,skill,10)*0.05,2.5)*5.656854249; //Plot formule before changing !
+ blend = bound(0,skill+this.bot_aimskill,10)*0.1;
+ desiredang = desiredang + blend *
+ (
+ this.bot_1st_order_aimfilter * autocvar_bot_ai_aimskill_order_mix_1st
+ + this.bot_2nd_order_aimfilter * autocvar_bot_ai_aimskill_order_mix_2nd
+ + this.bot_3th_order_aimfilter * autocvar_bot_ai_aimskill_order_mix_3th
+ + this.bot_4th_order_aimfilter * autocvar_bot_ai_aimskill_order_mix_4th
+ + this.bot_5th_order_aimfilter * autocvar_bot_ai_aimskill_order_mix_5th
+ );
+
+ // calculate turn angles
+ diffang = desiredang - this.bot_mouseaim;
+ // wrap yaw turn
+ diffang.y = diffang.y - floor(diffang.y / 360) * 360;
+ if (diffang.y >= 180)
+ diffang.y = diffang.y - 360;
+ //dprint(" diff:", vtos(diffang));
+
+ if (time >= this.bot_aimthinktime)
+ {
+ this.bot_aimthinktime = max(this.bot_aimthinktime + 0.5 - 0.05*(skill+this.bot_thinkskill), time);
+ this.bot_mouseaim = this.bot_mouseaim + diffang * (1-random()*0.1*bound(1,10-(skill+this.bot_thinkskill),10));
+ }
+
+ //this.v_angle = this.v_angle + diffang * bound(0, r * frametime * (skill * 0.5 + 2), 1);
+
+ diffang = this.bot_mouseaim - desiredang;
+ // wrap yaw turn
+ diffang.y = diffang.y - floor(diffang.y / 360) * 360;
+ if (diffang.y >= 180)
+ diffang.y = diffang.y - 360;
+ desiredang = desiredang + diffang * bound(0,autocvar_bot_ai_aimskill_think,1);
+
+ // calculate turn angles
+ diffang = desiredang - this.v_angle;
+ // wrap yaw turn
+ diffang.y = diffang.y - floor(diffang.y / 360) * 360;
+ if (diffang.y >= 180)
+ diffang.y = diffang.y - 360;
+ //dprint(" diff:", vtos(diffang));
+
+ // jitter tracking
+ dist = vlen(diffang);
+ //diffang = diffang + randomvec() * (dist * 0.05 * (3.5 - bound(0, skill, 3)));
+
+ // turn
+ float r, fixedrate, blendrate;
+ fixedrate = autocvar_bot_ai_aimskill_fixedrate / bound(1,dist,1000);
+ blendrate = autocvar_bot_ai_aimskill_blendrate;
+ r = max(fixedrate, blendrate);
+ //this.v_angle = this.v_angle + diffang * bound(frametime, r * frametime * (2+skill*skill*0.05-random()*0.05*(10-skill)), 1);
+ this.v_angle = this.v_angle + diffang * bound(delta_t, r * delta_t * (2+pow(skill+this.bot_mouseskill,3)*0.005-random()), 1);
+ this.v_angle = this.v_angle * bound(0,autocvar_bot_ai_aimskill_mouse,1) + desiredang * bound(0,(1-autocvar_bot_ai_aimskill_mouse),1);
+ //this.v_angle = this.v_angle + diffang * bound(0, r * frametime * (skill * 0.5 + 2), 1);
+ //this.v_angle = this.v_angle + diffang * (1/ blendrate);
+ this.v_angle_z = 0;
+ this.v_angle_y = this.v_angle.y - floor(this.v_angle.y / 360) * 360;
+ //dprint(" turn:", vtos(this.v_angle));
+
+ makevectors(this.v_angle);
+ shotorg = this.origin + this.view_ofs;
+ shotdir = v_forward;
+
+ //dprint(" dir:", vtos(v_forward));
+ //te_lightning2(NULL, shotorg, shotorg + shotdir * 100);
+
+ // calculate turn angles again
+ //diffang = desiredang - this.v_angle;
+ //diffang_y = diffang_y - floor(diffang_y / 360) * 360;
+ //if (diffang_y >= 180)
+ // diffang_y = diffang_y - 360;
+
+ //dprint("e ", vtos(diffang), " < ", ftos(maxfiredeviation), "\n");
+
+ // decide whether to fire this time
+ // note the maxfiredeviation is in degrees so this has to convert to radians first
+ //if ((normalize(v) * shotdir) >= cos(maxfiredeviation * (3.14159265358979323846 / 180)))
+ if ((normalize(v) * shotdir) >= cos(maxfiredeviation * (3.14159265358979323846 / 180)))
+ if(vdist(trace_endpos-shotorg, <, 500 + 500 * bound(0, skill + this.bot_aggresskill, 10)) || random()*random()>bound(0,(skill+this.bot_aggresskill)*0.05,1))
+ this.bot_firetimer = time + bound(0.1, 0.5-(skill+this.bot_aggresskill)*0.05, 0.5);
+ //traceline(shotorg,shotorg+shotdir*1000,false,NULL);
+ //dprint(ftos(maxfiredeviation),"\n");
+ //dprint(" diff:", vtos(diffang), "\n");
+
+ return this.bot_canfire && (time < this.bot_firetimer);
+}
+
+vector bot_shotlead(vector targorigin, vector targvelocity, float shotspeed, float shotdelay)
+{
+ // Try to add code here that predicts gravity effect here, no clue HOW to though ... well not yet atleast...
+ return targorigin + targvelocity * (shotdelay + vlen(targorigin - shotorg) / shotspeed);
+}
+
+bool bot_aim(entity this, float shotspeed, float shotspeedupward, float maxshottime, bool applygravity)
+{
+ float f, r, hf, distanceratio;
+ vector v;
+ /*
+ eprint(this);
+ dprint("bot_aim(", ftos(shotspeed));
+ dprint(", ", ftos(shotspeedupward));
+ dprint(", ", ftos(maxshottime));
+ dprint(", ", ftos(applygravity));
+ dprint(");\n");
+ */
+
+ hf = this.dphitcontentsmask;
+ this.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
+
+ shotspeed *= W_WeaponSpeedFactor(this);
+ shotspeedupward *= W_WeaponSpeedFactor(this);
+ if (!shotspeed)
+ {
+ LOG_TRACE("bot_aim: WARNING: weapon ", PS(this).m_weapon.m_name, " shotspeed is zero!");
+ shotspeed = 1000000;
+ }
+ if (!maxshottime)
+ {
+ LOG_TRACE("bot_aim: WARNING: weapon ", PS(this).m_weapon.m_name, " maxshottime is zero!");
+ maxshottime = 1;
+ }
+ makevectors(this.v_angle);
+ shotorg = this.origin + this.view_ofs;
+ shotdir = v_forward;
+ v = bot_shotlead(this.bot_aimtargorigin, this.bot_aimtargvelocity, shotspeed, this.bot_aimlatency);
+ distanceratio = sqrt(bound(0,skill,10000))*0.3*(vlen(v-shotorg)-100)/autocvar_bot_ai_aimskill_firetolerance_distdegrees;
+ distanceratio = bound(0,distanceratio,1);
+ r = (autocvar_bot_ai_aimskill_firetolerance_maxdegrees-autocvar_bot_ai_aimskill_firetolerance_mindegrees)
+ * (1-distanceratio) + autocvar_bot_ai_aimskill_firetolerance_mindegrees;
+ if (applygravity && this.bot_aimtarg)
+ {
+ if (!findtrajectorywithleading(shotorg, '0 0 0', '0 0 0', this.bot_aimtarg, shotspeed, shotspeedupward, maxshottime, 0, this))
+ {
+ this.dphitcontentsmask = hf;
+ return false;
+ }
+
+ f = bot_aimdir(this, findtrajectory_velocity - shotspeedupward * '0 0 1', r);
+ }
+ else
+ {
+ f = bot_aimdir(this, v - shotorg, r);
+ //dprint("AIM: ");dprint(vtos(this.bot_aimtargorigin));dprint(" + ");dprint(vtos(this.bot_aimtargvelocity));dprint(" * ");dprint(ftos(this.bot_aimlatency + vlen(this.bot_aimtargorigin - shotorg) / shotspeed));dprint(" = ");dprint(vtos(v));dprint(" : aimdir = ");dprint(vtos(normalize(v - shotorg)));dprint(" : ");dprint(vtos(shotdir));dprint("\n");
+ //traceline(shotorg, shotorg + shotdir * 10000, false, this);
+ //if (trace_ent.takedamage)
+ //if (trace_fraction < 1)
+ //if (!bot_shouldattack(this, trace_ent))
+ // return false;
+ traceline(shotorg, this.bot_aimtargorigin, false, this);
+ if (trace_fraction < 1)
+ if (trace_ent != this.enemy)
+ if (!bot_shouldattack(this, trace_ent))
+ {
+ this.dphitcontentsmask = hf;
+ return false;
+ }
+ }
+
+ //if (r > maxshottime * shotspeed)
+ // return false;
+ this.dphitcontentsmask = hf;
+ return true;
+}
--- /dev/null
+#pragma once
+/*
+ * Globals and Fields
+ */
+
+entity tracetossent;
+entity tracetossfaketarget;
+vector findtrajectory_velocity;
+
+
+
+vector shotorg;
+vector shotdir;
+
+// lag simulation
+// upto 5 queued messages
+.float lag1_time;
+.float lag1_float1;
+.float lag1_float2;
+.entity lag1_entity1;
+.vector lag1_vec1;
+.vector lag1_vec2;
+.vector lag1_vec3;
+.vector lag1_vec4;
+
+.float lag2_time;
+.float lag2_float1;
+.float lag2_float2;
+.entity lag2_entity1;
+.vector lag2_vec1;
+.vector lag2_vec2;
+.vector lag2_vec3;
+.vector lag2_vec4;
+
+.float lag3_time;
+.float lag3_float1;
+.float lag3_float2;
+.entity lag3_entity1;
+.vector lag3_vec1;
+.vector lag3_vec2;
+.vector lag3_vec3;
+.vector lag3_vec4;
+
+.float lag4_time;
+.float lag4_float1;
+.float lag4_float2;
+.entity lag4_entity1;
+.vector lag4_vec1;
+.vector lag4_vec2;
+.vector lag4_vec3;
+.vector lag4_vec4;
+
+.float lag5_time;
+.float lag5_float1;
+.float lag5_float2;
+.entity lag5_entity1;
+.vector lag5_vec1;
+.vector lag5_vec2;
+.vector lag5_vec3;
+.vector lag5_vec4;
+
+.float bot_badaimtime;
+.float bot_aimthinktime;
+.float bot_prevaimtime;
+.float bot_firetimer;
+.float bot_aimlatency;
+
+.vector bot_mouseaim;
+.vector bot_badaimoffset;
+.vector bot_1st_order_aimfilter;
+.vector bot_2nd_order_aimfilter;
+.vector bot_3th_order_aimfilter;
+.vector bot_4th_order_aimfilter;
+.vector bot_5th_order_aimfilter;
+.vector bot_olddesiredang;
+
+//.vector bot_aimorigin;
+//.vector bot_aimvelocity;
+.vector bot_aimtargorigin;
+.vector bot_aimtargvelocity;
+
+.entity bot_aimtarg;
+
+/*
+ * Functions
+ */
+
+float lag_additem(entity this, float t, float f1, float f2, entity e1, vector v1, vector v2, vector v3, vector v4);
+void lag_update(entity this);
+void bot_lagfunc(entity this, float t, float f1, float f2, entity e1, vector v1, vector v2, vector v3, vector v4);
+
+float bot_shouldattack(entity this, entity targ);
+float bot_aimdir(entity this, vector v, float maxfiredeviation);
+bool bot_aim(entity this, float shotspeed, float shotspeedupward, float maxshottime, bool applygravity);
+float findtrajectorywithleading(vector org, vector m1, vector m2, entity targ, float shotspeed, float shotspeedupward, float maxtime, float shotdelay, entity ignore);
+
+vector bot_shotlead(vector targorigin, vector targvelocity, float shotspeed, float shotdelay);
+
+.void(entity this, float t, float f1, float f2, entity e1, vector v1, vector v2, vector v3, vector v4) lag_func;
--- /dev/null
+#include "bot.qh"
+
+#include "cvars.qh"
+
+#include "aim.qh"
+#include "navigation.qh"
+#include "scripting.qh"
+#include "waypoints.qh"
+
+#include "havocbot/havocbot.qh"
+#include "havocbot/scripting.qh"
+
+#include "../../teamplay.qh"
+
+#include "../../antilag.qh"
+#include "../../autocvars.qh"
+#include "../../campaign.qh"
+#include "../../cl_client.qh"
+#include "../../constants.qh"
+#include "../../defs.qh"
+#include "../../race.qh"
+#include <common/t_items.qh>
+
+#include "../../mutators/all.qh"
+
+#include "../../weapons/accuracy.qh"
+
+#include <common/physics/player.qh>
+#include <common/constants.qh>
+#include <common/mapinfo.qh>
+#include <common/teams.qh>
+#include <common/util.qh>
+
+#include <common/weapons/all.qh>
+
+#include <lib/csqcmodel/sv_model.qh>
+
+#include <lib/warpzone/common.qh>
+#include <lib/warpzone/util_server.qh>
+
+entity bot_spawn()
+{
+ entity bot = spawnclient();
+ if (bot)
+ {
+ currentbots = currentbots + 1;
+ bot_setnameandstuff(bot);
+ ClientConnect(bot);
+ PutClientInServer(bot);
+ }
+ return bot;
+}
+
+void bot_think(entity this)
+{
+ if (this.bot_nextthink > time)
+ return;
+
+ this.flags &= ~FL_GODMODE;
+ if(autocvar_bot_god)
+ this.flags |= FL_GODMODE;
+
+ this.bot_nextthink = this.bot_nextthink + autocvar_bot_ai_thinkinterval * pow(0.5, this.bot_aiskill);
+ //if (this.bot_painintensity > 0)
+ // this.bot_painintensity = this.bot_painintensity - (skill + 1) * 40 * frametime;
+
+ //this.bot_painintensity = this.bot_painintensity + this.bot_oldhealth - this.health;
+ //this.bot_painintensity = bound(0, this.bot_painintensity, 100);
+
+ if (!IS_PLAYER(this) || (autocvar_g_campaign && !campaign_bots_may_start))
+ {
+ this.bot_nextthink = time + 0.5;
+ return;
+ }
+
+ if (this.fixangle)
+ {
+ this.v_angle = this.angles;
+ this.v_angle_z = 0;
+ this.fixangle = false;
+ }
+
+ this.dmg_take = 0;
+ this.dmg_save = 0;
+ this.dmg_inflictor = NULL;
+
+ // calculate an aiming latency based on the skill setting
+ // (simulated network latency + naturally delayed reflexes)
+ //this.ping = 0.7 - bound(0, 0.05 * skill, 0.5); // moved the reflexes to bot_aimdir (under the name 'think')
+ // minimum ping 20+10 random
+ this.ping = bound(0,0.07 - bound(0, (skill + this.bot_pingskill) * 0.005,0.05)+random()*0.01,0.65); // Now holds real lag to server, and higer skill players take a less laggy server
+ // skill 10 = ping 0.2 (adrenaline)
+ // skill 0 = ping 0.7 (slightly drunk)
+
+ // clear buttons
+ PHYS_INPUT_BUTTON_ATCK(this) = false;
+ PHYS_INPUT_BUTTON_JUMP(this) = false;
+ PHYS_INPUT_BUTTON_ATCK2(this) = false;
+ PHYS_INPUT_BUTTON_ZOOM(this) = false;
+ PHYS_INPUT_BUTTON_CROUCH(this) = false;
+ PHYS_INPUT_BUTTON_HOOK(this) = false;
+ PHYS_INPUT_BUTTON_INFO(this) = false;
+ PHYS_INPUT_BUTTON_DRAG(this) = false;
+ PHYS_INPUT_BUTTON_CHAT(this) = false;
+ PHYS_INPUT_BUTTON_USE(this) = false;
+
+ if (time < game_starttime)
+ {
+ // block the bot during the countdown to game start
+ this.movement = '0 0 0';
+ this.bot_nextthink = game_starttime;
+ return;
+ }
+
+ // if dead, just wait until we can respawn
+ if (IS_DEAD(this))
+ {
+ if (this.deadflag == DEAD_DEAD)
+ {
+ PHYS_INPUT_BUTTON_JUMP(this) = true; // press jump to respawn
+ this.bot_strategytime = 0;
+ }
+ }
+ else if(this.aistatus & AI_STATUS_STUCK)
+ navigation_unstuck(this);
+
+ // now call the current bot AI (havocbot for example)
+ this.bot_ai(this);
+}
+
+void bot_setnameandstuff(entity this)
+{
+ string readfile, s;
+ float file, tokens, prio;
+
+ string bot_name, bot_model, bot_skin, bot_shirt, bot_pants;
+ string name, prefix, suffix;
+
+ if(autocvar_g_campaign)
+ {
+ prefix = "";
+ suffix = "";
+ }
+ else
+ {
+ prefix = autocvar_bot_prefix;
+ suffix = autocvar_bot_suffix;
+ }
+
+ file = fopen(autocvar_bot_config_file, FILE_READ);
+
+ if(file < 0)
+ {
+ LOG_INFO(strcat("Error: Can not open the bot configuration file '",autocvar_bot_config_file,"'\n"));
+ readfile = "";
+ }
+ else
+ {
+ RandomSelection_Init();
+ while((readfile = fgets(file)))
+ {
+ if(substring(readfile, 0, 2) == "//")
+ continue;
+ if(substring(readfile, 0, 1) == "#")
+ continue;
+ tokens = tokenizebyseparator(readfile, "\t");
+ if(tokens == 0)
+ continue;
+ s = argv(0);
+ prio = 1;
+ FOREACH_CLIENT(IS_BOT_CLIENT(it), LAMBDA(
+ if(s == it.cleanname)
+ {
+ prio = 0;
+ break;
+ }
+ ));
+ RandomSelection_Add(NULL, 0, readfile, 1, prio);
+ }
+ readfile = RandomSelection_chosen_string;
+ fclose(file);
+ }
+
+ tokens = tokenizebyseparator(readfile, "\t");
+ if(argv(0) != "") bot_name = argv(0);
+ else bot_name = "Bot";
+
+ if(argv(1) != "") bot_model = argv(1);
+ else bot_model = "";
+
+ if(argv(2) != "") bot_skin = argv(2);
+ else bot_skin = "0";
+
+ if(argv(3) != "" && stof(argv(3)) >= 0) bot_shirt = argv(3);
+ else bot_shirt = ftos(floor(random() * 15));
+
+ if(argv(4) != "" && stof(argv(4)) >= 0) bot_pants = argv(4);
+ else bot_pants = ftos(floor(random() * 15));
+
+ this.bot_forced_team = stof(argv(5));
+
+ prio = 6;
+
+ #define READSKILL(f,w,r) if(argv(prio) != "") this.f = stof(argv(prio)) * (w); else this.f = (!autocvar_g_campaign) * (2 * random() - 1) * (r) * (w); ++prio
+ //print(bot_name, ": ping=", argv(9), "\n");
+
+ READSKILL(havocbot_keyboardskill, 0.5, 0.5); // keyboard skill
+ READSKILL(bot_moveskill, 2, 0); // move skill
+ READSKILL(bot_dodgeskill, 2, 0); // dodge skill
+
+ READSKILL(bot_pingskill, 0.5, 0); // ping skill
+
+ READSKILL(bot_weaponskill, 2, 0); // weapon skill
+ READSKILL(bot_aggresskill, 1, 0); // aggre skill
+ READSKILL(bot_rangepreference, 1, 0); // read skill
+
+ READSKILL(bot_aimskill, 2, 0); // aim skill
+ READSKILL(bot_offsetskill, 2, 0.5); // offset skill
+ READSKILL(bot_mouseskill, 1, 0.5); // mouse skill
+
+ READSKILL(bot_thinkskill, 1, 0.5); // think skill
+ READSKILL(bot_aiskill, 2, 0); // "ai" skill
+
+ this.bot_config_loaded = true;
+
+ // this is really only a default, JoinBestTeam is called later
+ setcolor(this, stof(bot_shirt) * 16 + stof(bot_pants));
+ this.bot_preferredcolors = this.clientcolors;
+
+ // pick the name
+ if (autocvar_bot_usemodelnames)
+ name = bot_model;
+ else
+ name = bot_name;
+
+ // number bots with identical names
+ int j = 0;
+ FOREACH_CLIENT(IS_BOT_CLIENT(it), LAMBDA(
+ if(it.cleanname == name)
+ ++j;
+ ));
+ if (j)
+ this.netname = this.netname_freeme = strzone(strcat(prefix, name, "(", ftos(j), ")", suffix));
+ else
+ this.netname = this.netname_freeme = strzone(strcat(prefix, name, suffix));
+
+ this.cleanname = strzone(name);
+
+ // pick the model and skin
+ if(substring(bot_model, -4, 1) != ".")
+ bot_model = strcat(bot_model, ".iqm");
+ this.playermodel = this.playermodel_freeme = strzone(strcat("models/player/", bot_model));
+ this.playerskin = this.playerskin_freeme = strzone(bot_skin);
+
+ this.cvar_cl_accuracy_data_share = 1; // share the bots weapon accuracy data with the NULL
+ this.cvar_cl_accuracy_data_receive = 0; // don't receive any weapon accuracy data
+}
+
+void bot_custom_weapon_priority_setup()
+{
+ float tokens, i, w;
+
+ bot_custom_weapon = false;
+
+ if( autocvar_bot_ai_custom_weapon_priority_far == "" ||
+ autocvar_bot_ai_custom_weapon_priority_mid == "" ||
+ autocvar_bot_ai_custom_weapon_priority_close == "" ||
+ autocvar_bot_ai_custom_weapon_priority_distances == ""
+ )
+ return;
+
+ // Parse distances
+ tokens = tokenizebyseparator(autocvar_bot_ai_custom_weapon_priority_distances," ");
+
+ if (tokens!=2)
+ return;
+
+ bot_distance_far = stof(argv(0));
+ bot_distance_close = stof(argv(1));
+
+ if(bot_distance_far < bot_distance_close){
+ bot_distance_far = stof(argv(1));
+ bot_distance_close = stof(argv(0));
+ }
+
+ // Initialize list of weapons
+ bot_weapons_far[0] = -1;
+ bot_weapons_mid[0] = -1;
+ bot_weapons_close[0] = -1;
+
+ // Parse far distance weapon priorities
+ tokens = tokenizebyseparator(W_NumberWeaponOrder(autocvar_bot_ai_custom_weapon_priority_far)," ");
+
+ int c = 0;
+ for(i=0; i < tokens && c < Weapons_COUNT; ++i){
+ w = stof(argv(i));
+ if ( w >= WEP_FIRST && w <= WEP_LAST) {
+ bot_weapons_far[c] = w;
+ ++c;
+ }
+ }
+ if(c < Weapons_COUNT)
+ bot_weapons_far[c] = -1;
+
+ // Parse mid distance weapon priorities
+ tokens = tokenizebyseparator(W_NumberWeaponOrder(autocvar_bot_ai_custom_weapon_priority_mid)," ");
+
+ c = 0;
+ for(i=0; i < tokens && c < Weapons_COUNT; ++i){
+ w = stof(argv(i));
+ if ( w >= WEP_FIRST && w <= WEP_LAST) {
+ bot_weapons_mid[c] = w;
+ ++c;
+ }
+ }
+ if(c < Weapons_COUNT)
+ bot_weapons_mid[c] = -1;
+
+ // Parse close distance weapon priorities
+ tokens = tokenizebyseparator(W_NumberWeaponOrder(autocvar_bot_ai_custom_weapon_priority_close)," ");
+
+ c = 0;
+ for(i=0; i < tokens && i < Weapons_COUNT; ++i){
+ w = stof(argv(i));
+ if ( w >= WEP_FIRST && w <= WEP_LAST) {
+ bot_weapons_close[c] = w;
+ ++c;
+ }
+ }
+ if(c < Weapons_COUNT)
+ bot_weapons_close[c] = -1;
+
+ bot_custom_weapon = true;
+}
+
+void bot_endgame()
+{
+ entity e;
+ //dprint("bot_endgame\n");
+ e = bot_list;
+ while (e)
+ {
+ setcolor(e, e.bot_preferredcolors);
+ e = e.nextbot;
+ }
+ // if dynamic waypoints are ever implemented, save them here
+}
+
+void bot_relinkplayerlist()
+{
+ player_count = 0;
+ currentbots = 0;
+ bot_list = NULL;
+
+ entity prevbot = NULL;
+ FOREACH_CLIENT(true,
+ {
+ ++player_count;
+
+ if(IS_BOT_CLIENT(it))
+ {
+ if(prevbot)
+ prevbot.nextbot = it;
+ else
+ {
+ bot_list = it;
+ bot_list.nextbot = NULL;
+ }
+ prevbot = it;
+ ++currentbots;
+ }
+ });
+ LOG_TRACE("relink: ", ftos(currentbots), " bots seen.");
+ bot_strategytoken = bot_list;
+ bot_strategytoken_taken = true;
+}
+
+void bot_clientdisconnect(entity this)
+{
+ if (!IS_BOT_CLIENT(this))
+ return;
+ bot_clearqueue(this);
+ if(this.cleanname)
+ strunzone(this.cleanname);
+ if(this.netname_freeme)
+ strunzone(this.netname_freeme);
+ if(this.playermodel_freeme)
+ strunzone(this.playermodel_freeme);
+ if(this.playerskin_freeme)
+ strunzone(this.playerskin_freeme);
+ this.cleanname = string_null;
+ this.netname_freeme = string_null;
+ this.playermodel_freeme = string_null;
+ this.playerskin_freeme = string_null;
+ if(this.bot_cmd_current)
+ delete(this.bot_cmd_current);
+ if(bot_waypoint_queue_owner==this)
+ bot_waypoint_queue_owner = NULL;
+}
+
+void bot_clientconnect(entity this)
+{
+ if (!IS_BOT_CLIENT(this)) return;
+ this.bot_preferredcolors = this.clientcolors;
+ this.bot_nextthink = time - random();
+ this.lag_func = bot_lagfunc;
+ this.isbot = true;
+ this.createdtime = this.bot_nextthink;
+
+ if(!this.bot_config_loaded) // This is needed so team overrider doesn't break between matches
+ bot_setnameandstuff(this);
+
+ if(this.bot_forced_team==1)
+ this.team = NUM_TEAM_1;
+ else if(this.bot_forced_team==2)
+ this.team = NUM_TEAM_2;
+ else if(this.bot_forced_team==3)
+ this.team = NUM_TEAM_3;
+ else if(this.bot_forced_team==4)
+ this.team = NUM_TEAM_4;
+ else
+ JoinBestTeam(this, false, true);
+
+ havocbot_setupbot(this);
+}
+
+void bot_removefromlargestteam()
+{
+ CheckAllowedTeams(NULL);
+ GetTeamCounts(NULL);
+
+ entity best = NULL;
+ float besttime = 0;
+ int bestcount = 0;
+
+ int bcount = 0;
+ FOREACH_ENTITY_FLOAT(isbot, true,
+ {
+ ++bcount;
+
+ if(!best)
+ {
+ best = it;
+ besttime = it.createdtime;
+ }
+
+ int thiscount = 0;
+
+ switch(it.team)
+ {
+ case NUM_TEAM_1: thiscount = c1; break;
+ case NUM_TEAM_2: thiscount = c2; break;
+ case NUM_TEAM_3: thiscount = c3; break;
+ case NUM_TEAM_4: thiscount = c4; break;
+ }
+
+ if(thiscount > bestcount)
+ {
+ bestcount = thiscount;
+ besttime = it.createdtime;
+ best = it;
+ }
+ else if(thiscount == bestcount && besttime < it.createdtime)
+ {
+ besttime = it.createdtime;
+ best = it;
+ }
+ });
+ if(!bcount)
+ return; // no bots to remove
+ currentbots = currentbots - 1;
+ dropclient(best);
+}
+
+void bot_removenewest()
+{
+ if(teamplay)
+ {
+ bot_removefromlargestteam();
+ return;
+ }
+
+ float besttime = 0;
+ entity best = NULL;
+ int bcount = 0;
+
+ FOREACH_ENTITY_FLOAT(isbot, true,
+ {
+ ++bcount;
+
+ if(!best)
+ {
+ best = it;
+ besttime = it.createdtime;
+ }
+
+ if(besttime < it.createdtime)
+ {
+ besttime = it.createdtime;
+ best = it;
+ }
+ });
+
+ if(!bcount)
+ return; // no bots to remove
+
+ currentbots = currentbots - 1;
+ dropclient(best);
+}
+
+void autoskill(float factor)
+{
+ float bestbot;
+ float bestplayer;
+
+ bestbot = -1;
+ bestplayer = -1;
+ FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
+ if(IS_REAL_CLIENT(it))
+ bestplayer = max(bestplayer, it.totalfrags - it.totalfrags_lastcheck);
+ else
+ bestbot = max(bestbot, it.totalfrags - it.totalfrags_lastcheck);
+ ));
+
+ LOG_TRACE("autoskill: best player got ", ftos(bestplayer), ", ");
+ LOG_TRACE("best bot got ", ftos(bestbot), "; ");
+ if(bestbot < 0 || bestplayer < 0)
+ {
+ LOG_TRACE("not doing anything");
+ // don't return, let it reset all counters below
+ }
+ else if(bestbot <= bestplayer * factor - 2)
+ {
+ if(autocvar_skill < 17)
+ {
+ LOG_TRACE("2 frags difference, increasing skill");
+ cvar_set("skill", ftos(autocvar_skill + 1));
+ bprint("^2SKILL UP!^7 Now at level ", ftos(autocvar_skill), "\n");
+ }
+ }
+ else if(bestbot >= bestplayer * factor + 2)
+ {
+ if(autocvar_skill > 0)
+ {
+ LOG_TRACE("2 frags difference, decreasing skill");
+ cvar_set("skill", ftos(autocvar_skill - 1));
+ bprint("^1SKILL DOWN!^7 Now at level ", ftos(autocvar_skill), "\n");
+ }
+ }
+ else
+ {
+ LOG_TRACE("not doing anything");
+ return;
+ // don't reset counters, wait for them to accumulate
+ }
+
+ FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(it.totalfrags_lastcheck = it.totalfrags));
+}
+
+void bot_calculate_stepheightvec()
+{
+ stepheightvec = autocvar_sv_stepheight * '0 0 1';
+ jumpstepheightvec = stepheightvec +
+ ((autocvar_sv_jumpvelocity * autocvar_sv_jumpvelocity) / (2 * autocvar_sv_gravity)) * '0 0 0.85';
+ // 0.75 factor is for safety to make the jumps easy
+}
+
+float bot_fixcount()
+{
+ int activerealplayers = 0;
+ int realplayers = 0;
+ if (MUTATOR_CALLHOOK(Bot_FixCount, activerealplayers, realplayers)) {
+ activerealplayers = M_ARGV(0, int);
+ realplayers = M_ARGV(1, int);
+ } else {
+ FOREACH_CLIENT(IS_REAL_CLIENT(it), LAMBDA(
+ if(IS_PLAYER(it))
+ ++activerealplayers;
+ ++realplayers;
+ ));
+ }
+
+ int bots;
+ // add/remove bots if needed to make sure there are at least
+ // minplayers+bot_number, or remove all bots if no one is playing
+ // But don't remove bots immediately on level change, as the real players
+ // usually haven't rejoined yet
+ bots_would_leave = false;
+ if (teamplay && autocvar_bot_vs_human && AvailableTeams() == 2)
+ bots = min(ceil(fabs(autocvar_bot_vs_human) * activerealplayers), maxclients - realplayers);
+ else if ((realplayers || autocvar_bot_join_empty || (currentbots > 0 && time < 5)))
+ {
+ float realminplayers, minplayers;
+ realminplayers = autocvar_minplayers;
+ minplayers = max(0, floor(realminplayers));
+
+ float realminbots, minbots;
+ realminbots = autocvar_bot_number;
+ minbots = max(0, floor(realminbots));
+
+ bots = min(max(minbots, minplayers - activerealplayers), maxclients - realplayers);
+ if(bots > minbots)
+ bots_would_leave = true;
+ }
+ else
+ {
+ // if there are no players, remove bots
+ bots = 0;
+ }
+
+ // only add one bot per frame to avoid utter chaos
+ if(time > botframe_nextthink)
+ {
+ //dprint(ftos(bots), " ? ", ftos(currentbots), "\n");
+ while (currentbots < bots)
+ {
+ if (bot_spawn() == NULL)
+ {
+ bprint("Can not add bot, server full.\n");
+ return false;
+ }
+ }
+ while (currentbots > bots)
+ bot_removenewest();
+ }
+
+ return true;
+}
+
+void bot_serverframe()
+{
+ if (intermission_running)
+ return;
+
+ if (time < 2)
+ return;
+
+ bot_calculate_stepheightvec();
+ bot_navigation_movemode = ((autocvar_bot_navigation_ignoreplayers) ? MOVE_NOMONSTERS : MOVE_NORMAL);
+
+ if(time > autoskill_nextthink)
+ {
+ float a;
+ a = autocvar_skill_auto;
+ if(a)
+ autoskill(a);
+ autoskill_nextthink = time + 5;
+ }
+
+ if(time > botframe_nextthink)
+ {
+ if(!bot_fixcount())
+ botframe_nextthink = time + 10;
+ }
+
+ bot_ignore_bots = autocvar_bot_ignore_bots;
+
+ if(botframe_spawnedwaypoints)
+ {
+ if(autocvar_waypoint_benchmark)
+ localcmd("quit\n");
+ }
+
+ if (currentbots > 0 || autocvar_g_waypointeditor || autocvar_g_waypointeditor_auto)
+ if (botframe_spawnedwaypoints)
+ {
+ if(botframe_cachedwaypointlinks)
+ {
+ if(!botframe_loadedforcedlinks)
+ waypoint_load_links_hardwired();
+ }
+ else
+ {
+ // TODO: Make this check cleaner
+ IL_EACH(g_waypoints, time - it.nextthink > 10,
+ {
+ waypoint_save_links();
+ break;
+ });
+ }
+ }
+ else
+ {
+ botframe_spawnedwaypoints = true;
+ waypoint_loadall();
+ if(!waypoint_load_links())
+ waypoint_schedulerelinkall();
+ }
+
+ if (bot_list)
+ {
+ // cycle the goal token from one bot to the next each frame
+ // (this prevents them from all doing spawnfunc_waypoint searches on the same
+ // frame, which causes choppy framerates)
+ if (bot_strategytoken_taken)
+ {
+ bot_strategytoken_taken = false;
+ if (bot_strategytoken)
+ bot_strategytoken = bot_strategytoken.nextbot;
+ if (!bot_strategytoken)
+ bot_strategytoken = bot_list;
+ }
+
+ if (botframe_nextdangertime < time)
+ {
+ float interval;
+ interval = autocvar_bot_ai_dangerdetectioninterval;
+ if (botframe_nextdangertime < time - interval * 1.5)
+ botframe_nextdangertime = time;
+ botframe_nextdangertime = botframe_nextdangertime + interval;
+ botframe_updatedangerousobjects(autocvar_bot_ai_dangerdetectionupdates);
+ }
+ }
+
+ if (autocvar_g_waypointeditor)
+ botframe_showwaypointlinks();
+
+ if (autocvar_g_waypointeditor_auto)
+ botframe_autowaypoints();
+
+ if(time > bot_cvar_nextthink)
+ {
+ if(currentbots>0)
+ bot_custom_weapon_priority_setup();
+ bot_cvar_nextthink = time + 5;
+ }
+}
--- /dev/null
+#pragma once
+/*
+ * Globals and Fields
+ */
+
+const int AI_STATUS_ROAMING = BIT(0); // Bot is just crawling the map. No enemies at sight
+const int AI_STATUS_ATTACKING = BIT(1); // There are enemies at sight
+const int AI_STATUS_RUNNING = BIT(2); // Bot is bunny hopping
+const int AI_STATUS_DANGER_AHEAD = BIT(3); // There is lava/slime/trigger_hurt ahead
+const int AI_STATUS_OUT_JUMPPAD = BIT(4); // Trying to get out of a "vertical" jump pad
+const int AI_STATUS_OUT_WATER = BIT(5); // Trying to get out of water
+const int AI_STATUS_WAYPOINT_PERSONAL_LINKING = BIT(6); // Waiting for the personal waypoint to be linked
+const int AI_STATUS_WAYPOINT_PERSONAL_GOING = BIT(7); // Going to a personal waypoint
+const int AI_STATUS_WAYPOINT_PERSONAL_REACHED = BIT(8); // Personal waypoint reached
+const int AI_STATUS_JETPACK_FLYING = BIT(9);
+const int AI_STATUS_JETPACK_LANDING = BIT(10);
+const int AI_STATUS_STUCK = BIT(11); // Cannot reach any goal
+
+.float isbot; // true if this client is actually a bot
+.int aistatus;
+
+// Skill system
+float autoskill_nextthink;
+
+// havocbot_keyboardskill // keyboard movement
+.float bot_moveskill; // moving technique
+.float bot_dodgeskill; // dodging
+
+.float bot_pingskill; // ping offset
+
+.float bot_weaponskill; // weapon usage skill (combos, e.g.)
+.float bot_aggresskill; // aggressivity, controls "think before fire" behaviour
+.float bot_rangepreference; // weapon choice offset for range (>0 = prefer long range earlier "sniper", <0 = prefer short range "spammer")
+
+.float bot_aimskill; // aim accuracy
+.float bot_offsetskill; // aim breakage
+.float bot_mouseskill; // mouse "speed"
+
+.float bot_thinkskill; // target choice
+.float bot_aiskill; // strategy choice
+
+.float totalfrags_lastcheck;
+
+// Custom weapon priorities
+float bot_distance_far;
+float bot_distance_close;
+
+entity bot_list;
+.entity nextbot;
+.string cleanname;
+.string netname_freeme;
+.string playermodel_freeme;
+.string playerskin_freeme;
+
+.float bot_nextthink;
+
+.float createdtime;
+.float bot_preferredcolors;
+.float bot_attack;
+.float bot_dodge;
+.float bot_dodgerating;
+
+.float bot_pickup;
+.float bot_pickupbasevalue;
+.float bot_canfire;
+.float bot_strategytime;
+
+.float bot_forced_team;
+.float bot_config_loaded;
+
+float bot_strategytoken_taken;
+entity bot_strategytoken;
+
+float botframe_spawnedwaypoints;
+float botframe_nextthink;
+float botframe_nextdangertime;
+float bot_cvar_nextthink;
+float bot_ignore_bots; // let bots not attack other bots (only works in non-teamplay)
+
+/*
+ * Functions
+ */
+
+entity bot_spawn();
+float bot_fixcount();
+
+void bot_think(entity this);
+void bot_setnameandstuff(entity this);
+void bot_custom_weapon_priority_setup();
+void bot_endgame();
+void bot_relinkplayerlist();
+void bot_clientdisconnect(entity this);
+void bot_clientconnect(entity this);
+void bot_removefromlargestteam();
+void bot_removenewest();
+void autoskill(float factor);
+void bot_serverframe();
+
+.void(entity this) bot_ai;
+.float(entity player, entity item) bot_pickupevalfunc;
+
+/*
+ * Imports
+ */
+
+void(entity this) havocbot_setupbot;
+
+void bot_calculate_stepheightvec();
--- /dev/null
+#include "cvars.qh"
--- /dev/null
+#pragma once
+
+float autocvar_bot_ai_aimskill_blendrate;
+float autocvar_bot_ai_aimskill_firetolerance_distdegrees;
+float autocvar_bot_ai_aimskill_firetolerance_maxdegrees;
+float autocvar_bot_ai_aimskill_firetolerance_mindegrees;
+float autocvar_bot_ai_aimskill_fixedrate;
+float autocvar_bot_ai_aimskill_mouse;
+float autocvar_bot_ai_aimskill_offset;
+float autocvar_bot_ai_aimskill_order_filter_1st;
+float autocvar_bot_ai_aimskill_order_filter_2nd;
+float autocvar_bot_ai_aimskill_order_filter_3th;
+float autocvar_bot_ai_aimskill_order_filter_4th;
+float autocvar_bot_ai_aimskill_order_filter_5th;
+float autocvar_bot_ai_aimskill_order_mix_1st;
+float autocvar_bot_ai_aimskill_order_mix_2nd;
+float autocvar_bot_ai_aimskill_order_mix_3th;
+float autocvar_bot_ai_aimskill_order_mix_4th;
+float autocvar_bot_ai_aimskill_order_mix_5th;
+float autocvar_bot_ai_aimskill_think;
+float autocvar_bot_ai_bunnyhop_firstjumpdelay;
+float autocvar_bot_ai_bunnyhop_skilloffset;
+float autocvar_bot_ai_bunnyhop_startdistance;
+float autocvar_bot_ai_bunnyhop_stopdistance;
+float autocvar_bot_ai_chooseweaponinterval;
+string autocvar_bot_ai_custom_weapon_priority_close;
+string autocvar_bot_ai_custom_weapon_priority_distances;
+string autocvar_bot_ai_custom_weapon_priority_far;
+string autocvar_bot_ai_custom_weapon_priority_mid;
+float autocvar_bot_ai_dangerdetectioninterval;
+float autocvar_bot_ai_dangerdetectionupdates;
+float autocvar_bot_ai_enemydetectioninterval;
+float autocvar_bot_ai_enemydetectionradius;
+float autocvar_bot_ai_friends_aware_pickup_radius;
+float autocvar_bot_ai_ignoregoal_timeout;
+float autocvar_bot_ai_keyboard_distance;
+float autocvar_bot_ai_keyboard_threshold;
+float autocvar_bot_ai_navigation_jetpack;
+float autocvar_bot_ai_navigation_jetpack_mindistance;
+float autocvar_bot_ai_thinkinterval;
+bool autocvar_bot_ai_weapon_combo;
+float autocvar_bot_ai_weapon_combo_threshold;
+string autocvar_bot_config_file;
+bool autocvar_bot_god;
+bool autocvar_bot_ignore_bots;
+bool autocvar_bot_join_empty;
+bool autocvar_bot_navigation_ignoreplayers;
+bool autocvar_bot_nofire;
+#define autocvar_bot_prefix cvar_string("bot_prefix")
+#define autocvar_bot_suffix cvar_string("bot_suffix")
+bool autocvar_bot_usemodelnames;
+bool autocvar_bot_debug_tracewalk;
+bool autocvar_bot_debug_goalstack;
+bool autocvar_bot_wander_enable;
+bool autocvar_g_debug_bot_commands;
+int autocvar_g_waypointeditor_auto;
+float autocvar_skill_auto;
+bool autocvar_waypoint_benchmark;
--- /dev/null
+// generated file; do not modify
+#include <server/bot/default/havocbot/havocbot.qc>
+#include <server/bot/default/havocbot/roles.qc>
--- /dev/null
+// generated file; do not modify
+#include <server/bot/default/havocbot/havocbot.qh>
+#include <server/bot/default/havocbot/roles.qh>
--- /dev/null
+#include "havocbot.qh"
+
+#include "../cvars.qh"
+
+#include "../aim.qh"
+#include "../bot.qh"
+#include "../navigation.qh"
+#include "../scripting.qh"
+#include "../waypoints.qh"
+
+#include <common/constants.qh>
+#include <common/physics/player.qh>
+#include <common/state.qh>
+#include <common/items/all.qh>
+
+#include <common/triggers/trigger/jumppads.qh>
+
+#include <lib/warpzone/common.qh>
+
+.float speed;
+
+void havocbot_ai(entity this)
+{
+ if(this.draggedby)
+ return;
+
+ if(bot_execute_commands(this))
+ return;
+
+ if (bot_strategytoken == this)
+ if (!bot_strategytoken_taken)
+ {
+ if(this.havocbot_blockhead)
+ {
+ this.havocbot_blockhead = false;
+ }
+ else
+ {
+ if (!this.jumppadcount)
+ this.havocbot_role(this); // little too far down the rabbit hole
+ }
+
+ // TODO: tracewalk() should take care of this job (better path finding under water)
+ // if we don't have a goal and we're under water look for a waypoint near the "shore" and push it
+ if(IS_DEAD(this))
+ if(!this.goalcurrent)
+ if(this.waterlevel == WATERLEVEL_SWIMMING || (this.aistatus & AI_STATUS_OUT_WATER))
+ {
+ // Look for the closest waypoint out of water
+ entity newgoal = NULL;
+ IL_EACH(g_waypoints, vdist(it.origin - this.origin, <=, 10000),
+ {
+ if(it.origin.z < this.origin.z)
+ continue;
+
+ if(it.origin.z - this.origin.z - this.view_ofs.z > 100)
+ continue;
+
+ if (pointcontents(it.origin + it.maxs + '0 0 1') != CONTENT_EMPTY)
+ continue;
+
+ traceline(this.origin + this.view_ofs, ((it.absmin + it.absmax) * 0.5), true, this);
+
+ if(trace_fraction < 1)
+ continue;
+
+ if(!newgoal || vlen2(it.origin - this.origin) < vlen2(newgoal.origin - this.origin))
+ newgoal = it;
+ });
+
+ if(newgoal)
+ {
+ // te_wizspike(newgoal.origin);
+ navigation_pushroute(this, newgoal);
+ }
+ }
+
+ // token has been used this frame
+ bot_strategytoken_taken = true;
+ }
+
+ if(IS_DEAD(this))
+ return;
+
+ havocbot_chooseenemy(this);
+ if (this.bot_chooseweapontime < time )
+ {
+ this.bot_chooseweapontime = time + autocvar_bot_ai_chooseweaponinterval;
+ havocbot_chooseweapon(this);
+ }
+ havocbot_aim(this);
+ lag_update(this);
+ if (this.bot_aimtarg)
+ {
+ this.aistatus |= AI_STATUS_ATTACKING;
+ this.aistatus &= ~AI_STATUS_ROAMING;
+
+ if(this.weapons)
+ {
+ Weapon w = PS(this).m_weapon;
+ w.wr_aim(w, this);
+ if (autocvar_bot_nofire || IS_INDEPENDENT_PLAYER(this))
+ {
+ PHYS_INPUT_BUTTON_ATCK(this) = false;
+ PHYS_INPUT_BUTTON_ATCK2(this) = false;
+ }
+ else
+ {
+ if(PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_ATCK2(this))
+ this.lastfiredweapon = PS(this).m_weapon.m_id;
+ }
+ }
+ else
+ {
+ if(IS_PLAYER(this.bot_aimtarg))
+ bot_aimdir(this, this.bot_aimtarg.origin + this.bot_aimtarg.view_ofs - this.origin - this.view_ofs , -1);
+ }
+ }
+ else if (this.goalcurrent)
+ {
+ this.aistatus |= AI_STATUS_ROAMING;
+ this.aistatus &= ~AI_STATUS_ATTACKING;
+
+ vector now,v,next;//,heading;
+ float aimdistance,skillblend,distanceblend,blend;
+ next = now = ( (this.goalcurrent.absmin + this.goalcurrent.absmax) * 0.5) - (this.origin + this.view_ofs);
+ aimdistance = vlen(now);
+ //heading = this.velocity;
+ //dprint(this.goalstack01.classname,etos(this.goalstack01),"\n");
+ if(
+ this.goalstack01 != this && this.goalstack01 != NULL && ((this.aistatus & AI_STATUS_RUNNING) == 0) &&
+ !(this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT)
+ )
+ next = ((this.goalstack01.absmin + this.goalstack01.absmax) * 0.5) - (this.origin + this.view_ofs);
+
+ skillblend=bound(0,(skill+this.bot_moveskill-2.5)*0.5,1); //lower skill player can't preturn
+ distanceblend=bound(0,aimdistance/autocvar_bot_ai_keyboard_distance,1);
+ blend = skillblend * (1-distanceblend);
+ //v = (now * (distanceblend) + next * (1-distanceblend)) * (skillblend) + now * (1-skillblend);
+ //v = now * (distanceblend) * (skillblend) + next * (1-distanceblend) * (skillblend) + now * (1-skillblend);
+ //v = now * ((1-skillblend) + (distanceblend) * (skillblend)) + next * (1-distanceblend) * (skillblend);
+ v = now + blend * (next - now);
+ //dprint(etos(this), " ");
+ //dprint(vtos(now), ":", vtos(next), "=", vtos(v), " (blend ", ftos(blend), ")\n");
+ //v = now * (distanceblend) + next * (1-distanceblend);
+ if (this.waterlevel < WATERLEVEL_SWIMMING)
+ v.z = 0;
+ //dprint("walk at:", vtos(v), "\n");
+ //te_lightning2(NULL, this.origin, this.goalcurrent.origin);
+ bot_aimdir(this, v, -1);
+ }
+ havocbot_movetogoal(this);
+
+ // if the bot is not attacking, consider reloading weapons
+ if (!(this.aistatus & AI_STATUS_ATTACKING))
+ {
+ // we are currently holding a weapon that's not fully loaded, reload it
+ if(skill >= 2) // bots can only reload the held weapon on purpose past this skill
+ if(this.clip_load < this.clip_size)
+ this.impulse = 20; // "press" the reload button, not sure if this is done right
+
+ // if we're not reloading a weapon, switch to any weapon in our invnetory that's not fully loaded to reload it next
+ // the code above executes next frame, starting the reloading then
+ if(skill >= 5) // bots can only look for unloaded weapons past this skill
+ if(this.clip_load >= 0) // only if we're not reloading a weapon already
+ {
+ FOREACH(Weapons, it != WEP_Null, LAMBDA(
+ if((this.weapons & (it.m_wepset)) && (it.spawnflags & WEP_FLAG_RELOADABLE) && (this.weapon_load[it.m_id] < it.reloading_ammo))
+ PS(this).m_switchweapon = it;
+ ));
+ }
+ }
+}
+
+void havocbot_keyboard_movement(entity this, vector destorg)
+{
+ vector keyboard;
+ float blend, maxspeed;
+ float sk;
+
+ sk = skill + this.bot_moveskill;
+
+ maxspeed = autocvar_sv_maxspeed;
+
+ if (time < this.havocbot_keyboardtime)
+ return;
+
+ this.havocbot_keyboardtime =
+ max(
+ this.havocbot_keyboardtime
+ + 0.05/max(1, sk+this.havocbot_keyboardskill)
+ + random()*0.025/max(0.00025, skill+this.havocbot_keyboardskill)
+ , time);
+ keyboard = this.movement * (1.0 / maxspeed);
+
+ float trigger, trigger1;
+ blend = bound(0,sk*0.1,1);
+ trigger = autocvar_bot_ai_keyboard_threshold;
+ trigger1 = 0 - trigger;
+
+ // categorize forward movement
+ // at skill < 1.5 only forward
+ // at skill < 2.5 only individual directions
+ // at skill < 4.5 only individual directions, and forward diagonals
+ // at skill >= 4.5, all cases allowed
+ if (keyboard.x > trigger)
+ {
+ keyboard.x = 1;
+ if (sk < 2.5)
+ keyboard.y = 0;
+ }
+ else if (keyboard.x < trigger1 && sk > 1.5)
+ {
+ keyboard.x = -1;
+ if (sk < 4.5)
+ keyboard.y = 0;
+ }
+ else
+ {
+ keyboard.x = 0;
+ if (sk < 1.5)
+ keyboard.y = 0;
+ }
+ if (sk < 4.5)
+ keyboard.z = 0;
+
+ if (keyboard.y > trigger)
+ keyboard.y = 1;
+ else if (keyboard.y < trigger1)
+ keyboard.y = -1;
+ else
+ keyboard.y = 0;
+
+ if (keyboard.z > trigger)
+ keyboard.z = 1;
+ else if (keyboard.z < trigger1)
+ keyboard.z = -1;
+ else
+ keyboard.z = 0;
+
+ this.havocbot_keyboard = keyboard * maxspeed;
+ if (this.havocbot_ducktime>time) PHYS_INPUT_BUTTON_CROUCH(this) = true;
+
+ keyboard = this.havocbot_keyboard;
+ blend = bound(0,vlen(destorg-this.origin)/autocvar_bot_ai_keyboard_distance,1); // When getting close move with 360 degree
+ //dprint("movement ", vtos(this.movement), " keyboard ", vtos(keyboard), " blend ", ftos(blend), "\n");
+ this.movement = this.movement + (keyboard - this.movement) * blend;
+}
+
+void havocbot_bunnyhop(entity this, vector dir)
+{
+ float bunnyhopdistance;
+ vector deviation;
+ float maxspeed;
+ vector gco, gno;
+
+ // Don't jump when attacking
+ if(this.aistatus & AI_STATUS_ATTACKING)
+ return;
+
+ if(IS_PLAYER(this.goalcurrent))
+ return;
+
+ maxspeed = autocvar_sv_maxspeed;
+
+ if(this.aistatus & AI_STATUS_DANGER_AHEAD)
+ {
+ this.aistatus &= ~AI_STATUS_RUNNING;
+ PHYS_INPUT_BUTTON_JUMP(this) = false;
+ this.bot_canruntogoal = 0;
+ this.bot_timelastseengoal = 0;
+ return;
+ }
+
+ if(this.waterlevel > WATERLEVEL_WETFEET)
+ {
+ this.aistatus &= ~AI_STATUS_RUNNING;
+ return;
+ }
+
+ if(this.bot_lastseengoal != this.goalcurrent && !(this.aistatus & AI_STATUS_RUNNING))
+ {
+ this.bot_canruntogoal = 0;
+ this.bot_timelastseengoal = 0;
+ }
+
+ gco = (this.goalcurrent.absmin + this.goalcurrent.absmax) * 0.5;
+ bunnyhopdistance = vlen(this.origin - gco);
+
+ // Run only to visible goals
+ if(IS_ONGROUND(this))
+ if(this.speed==maxspeed)
+ if(checkpvs(this.origin + this.view_ofs, this.goalcurrent))
+ {
+ this.bot_lastseengoal = this.goalcurrent;
+
+ // seen it before
+ if(this.bot_timelastseengoal)
+ {
+ // for a period of time
+ if(time - this.bot_timelastseengoal > autocvar_bot_ai_bunnyhop_firstjumpdelay)
+ {
+ float checkdistance;
+ checkdistance = true;
+
+ // don't run if it is too close
+ if(this.bot_canruntogoal==0)
+ {
+ if(bunnyhopdistance > autocvar_bot_ai_bunnyhop_startdistance)
+ this.bot_canruntogoal = 1;
+ else
+ this.bot_canruntogoal = -1;
+ }
+
+ if(this.bot_canruntogoal != 1)
+ return;
+
+ if(this.aistatus & AI_STATUS_ROAMING)
+ if(this.goalcurrent.classname=="waypoint")
+ if (!(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL))
+ if(fabs(gco.z - this.origin.z) < this.maxs.z - this.mins.z)
+ if(this.goalstack01!=NULL)
+ {
+ gno = (this.goalstack01.absmin + this.goalstack01.absmax) * 0.5;
+ deviation = vectoangles(gno - this.origin) - vectoangles(gco - this.origin);
+ while (deviation.y < -180) deviation.y = deviation.y + 360;
+ while (deviation.y > 180) deviation.y = deviation.y - 360;
+
+ if(fabs(deviation.y) < 20)
+ if(bunnyhopdistance < vlen(this.origin - gno))
+ if(fabs(gno.z - gco.z) < this.maxs.z - this.mins.z)
+ {
+ if(vdist(gco - gno, >, autocvar_bot_ai_bunnyhop_startdistance))
+ if(checkpvs(this.origin + this.view_ofs, this.goalstack01))
+ {
+ checkdistance = false;
+ }
+ }
+ }
+
+ if(checkdistance)
+ {
+ this.aistatus &= ~AI_STATUS_RUNNING;
+ if(bunnyhopdistance > autocvar_bot_ai_bunnyhop_stopdistance)
+ PHYS_INPUT_BUTTON_JUMP(this) = true;
+ }
+ else
+ {
+ this.aistatus |= AI_STATUS_RUNNING;
+ PHYS_INPUT_BUTTON_JUMP(this) = true;
+ }
+ }
+ }
+ else
+ {
+ this.bot_timelastseengoal = time;
+ }
+ }
+ else
+ {
+ this.bot_timelastseengoal = 0;
+ }
+
+#if 0
+ // Release jump button
+ if(!cvar("sv_pogostick"))
+ if((IS_ONGROUND(this)) == 0)
+ {
+ if(this.velocity.z < 0 || vlen(this.velocity)<maxspeed)
+ PHYS_INPUT_BUTTON_JUMP(this) = false;
+
+ // Strafe
+ if(this.aistatus & AI_STATUS_RUNNING)
+ if(vlen(this.velocity)>maxspeed)
+ {
+ deviation = vectoangles(dir) - vectoangles(this.velocity);
+ while (deviation.y < -180) deviation.y = deviation.y + 360;
+ while (deviation.y > 180) deviation.y = deviation.y - 360;
+
+ if(fabs(deviation.y)>10)
+ this.movement_x = 0;
+
+ if(deviation.y>10)
+ this.movement_y = maxspeed * -1;
+ else if(deviation.y<10)
+ this.movement_y = maxspeed;
+
+ }
+ }
+#endif
+}
+
+void havocbot_movetogoal(entity this)
+{
+ vector destorg;
+ vector diff;
+ vector dir;
+ vector flatdir;
+ vector m1;
+ vector m2;
+ vector evadeobstacle;
+ vector evadelava;
+ float s;
+ float maxspeed;
+ vector gco;
+ //float dist;
+ vector dodge;
+ //if (this.goalentity)
+ // te_lightning2(this, this.origin, (this.goalentity.absmin + this.goalentity.absmax) * 0.5);
+ this.movement = '0 0 0';
+ maxspeed = autocvar_sv_maxspeed;
+
+ // Jetpack navigation
+ if(this.goalcurrent)
+ if(this.navigation_jetpack_goal)
+ if(this.goalcurrent==this.navigation_jetpack_goal)
+ if(this.ammo_fuel)
+ {
+ if(autocvar_bot_debug_goalstack)
+ {
+ debuggoalstack(this);
+ te_wizspike(this.navigation_jetpack_point);
+ }
+
+ // Take off
+ if (!(this.aistatus & AI_STATUS_JETPACK_FLYING))
+ {
+ // Brake almost completely so it can get a good direction
+ if(vdist(this.velocity, >, 10))
+ return;
+ this.aistatus |= AI_STATUS_JETPACK_FLYING;
+ }
+
+ makevectors(this.v_angle.y * '0 1 0');
+ dir = normalize(this.navigation_jetpack_point - this.origin);
+
+ // Landing
+ if(this.aistatus & AI_STATUS_JETPACK_LANDING)
+ {
+ // Calculate brake distance in xy
+ float db, v, d;
+ vector dxy;
+
+ dxy = this.origin - ( ( this.goalcurrent.absmin + this.goalcurrent.absmax ) * 0.5 ); dxy.z = 0;
+ d = vlen(dxy);
+ v = vlen(this.velocity - this.velocity.z * '0 0 1');
+ db = (pow(v,2) / (autocvar_g_jetpack_acceleration_side * 2)) + 100;
+ // dprint("distance ", ftos(ceil(d)), " velocity ", ftos(ceil(v)), " brake at ", ftos(ceil(db)), "\n");
+ if(d < db || d < 500)
+ {
+ // Brake
+ if(fabs(this.velocity.x)>maxspeed*0.3)
+ {
+ this.movement_x = dir * v_forward * -maxspeed;
+ return;
+ }
+ // Switch to normal mode
+ this.navigation_jetpack_goal = NULL;
+ this.aistatus &= ~AI_STATUS_JETPACK_LANDING;
+ this.aistatus &= ~AI_STATUS_JETPACK_FLYING;
+ return;
+ }
+ }
+ else if(checkpvs(this.origin,this.goalcurrent))
+ {
+ // If I can see the goal switch to landing code
+ this.aistatus &= ~AI_STATUS_JETPACK_FLYING;
+ this.aistatus |= AI_STATUS_JETPACK_LANDING;
+ return;
+ }
+
+ // Flying
+ PHYS_INPUT_BUTTON_HOOK(this) = true;
+ if(this.navigation_jetpack_point.z - STAT(PL_MAX, NULL).z + STAT(PL_MIN, NULL).z < this.origin.z)
+ {
+ this.movement_x = dir * v_forward * maxspeed;
+ this.movement_y = dir * v_right * maxspeed;
+ }
+ return;
+ }
+
+ // Handling of jump pads
+ if(this.jumppadcount)
+ {
+ // If got stuck on the jump pad try to reach the farthest visible waypoint
+ if(this.aistatus & AI_STATUS_OUT_JUMPPAD)
+ {
+ if(fabs(this.velocity.z)<50)
+ {
+ entity newgoal = NULL;
+ IL_EACH(g_waypoints, vdist(it.origin - this.origin, <=, 1000),
+ {
+ traceline(this.origin + this.view_ofs, ((it.absmin + it.absmax) * 0.5), true, this);
+
+ if(trace_fraction < 1)
+ continue;
+
+ if(!newgoal || vlen2(it.origin - this.origin) > vlen2(newgoal.origin - this.origin))
+ newgoal = it;
+ });
+
+ if(newgoal)
+ {
+ this.ignoregoal = this.goalcurrent;
+ this.ignoregoaltime = time + autocvar_bot_ai_ignoregoal_timeout;
+ navigation_clearroute(this);
+ navigation_routetogoal(this, newgoal, this.origin);
+ this.aistatus &= ~AI_STATUS_OUT_JUMPPAD;
+ }
+ }
+ else
+ return;
+ }
+ else
+ {
+ if(this.velocity.z>0)
+ {
+ float threshold;
+ vector velxy = this.velocity; velxy_z = 0;
+ threshold = maxspeed * 0.2;
+ if(vdist(velxy, <, threshold))
+ {
+ LOG_TRACE("Warning: ", this.netname, " got stuck on a jumppad (velocity in xy is ", vtos(velxy), "), trying to get out of it now");
+ this.aistatus |= AI_STATUS_OUT_JUMPPAD;
+ }
+ return;
+ }
+
+ // Don't chase players while using a jump pad
+ if(IS_PLAYER(this.goalcurrent) || IS_PLAYER(this.goalstack01))
+ return;
+ }
+ }
+ else if(this.aistatus & AI_STATUS_OUT_JUMPPAD)
+ this.aistatus &= ~AI_STATUS_OUT_JUMPPAD;
+
+ // If there is a trigger_hurt right below try to use the jetpack or make a rocketjump
+ if(skill>6)
+ if (!(IS_ONGROUND(this)))
+ {
+ tracebox(this.origin, this.mins, this.maxs, this.origin + '0 0 -65536', MOVE_NOMONSTERS, this);
+ if(tracebox_hits_trigger_hurt(this.origin, this.mins, this.maxs, trace_endpos ))
+ if(this.items & IT_JETPACK)
+ {
+ tracebox(this.origin, this.mins, this.maxs, this.origin + '0 0 65536', MOVE_NOMONSTERS, this);
+ if(tracebox_hits_trigger_hurt(this.origin, this.mins, this.maxs, trace_endpos + '0 0 1' ))
+ {
+ if(this.velocity.z<0)
+ {
+ PHYS_INPUT_BUTTON_HOOK(this) = true;
+ }
+ }
+ else
+ PHYS_INPUT_BUTTON_HOOK(this) = true;
+
+ // If there is no goal try to move forward
+
+ if(this.goalcurrent==NULL)
+ dir = v_forward;
+ else
+ dir = normalize(( ( this.goalcurrent.absmin + this.goalcurrent.absmax ) * 0.5 ) - this.origin);
+
+ vector xyvelocity = this.velocity; xyvelocity_z = 0;
+ float xyspeed = xyvelocity * dir;
+
+ if(xyspeed < (maxspeed / 2))
+ {
+ makevectors(this.v_angle.y * '0 1 0');
+ tracebox(this.origin, this.mins, this.maxs, this.origin + (dir * maxspeed * 3), MOVE_NOMONSTERS, this);
+ if(trace_fraction==1)
+ {
+ this.movement_x = dir * v_forward * maxspeed;
+ this.movement_y = dir * v_right * maxspeed;
+ if (skill < 10)
+ havocbot_keyboard_movement(this, this.origin + dir * 100);
+ }
+ }
+
+ this.havocbot_blockhead = true;
+
+ return;
+ }
+ else if(this.health>WEP_CVAR(devastator, damage)*0.5)
+ {
+ if(this.velocity.z < 0)
+ if(client_hasweapon(this, WEP_DEVASTATOR, true, false))
+ {
+ this.movement_x = maxspeed;
+
+ if(this.rocketjumptime)
+ {
+ if(time > this.rocketjumptime)
+ {
+ PHYS_INPUT_BUTTON_ATCK2(this) = true;
+ this.rocketjumptime = 0;
+ }
+ return;
+ }
+
+ PS(this).m_switchweapon = WEP_DEVASTATOR;
+ this.v_angle_x = 90;
+ PHYS_INPUT_BUTTON_ATCK(this) = true;
+ this.rocketjumptime = time + WEP_CVAR(devastator, detonatedelay);
+ return;
+ }
+ }
+ else
+ {
+ // If there is no goal try to move forward
+ if(this.goalcurrent==NULL)
+ this.movement_x = maxspeed;
+ }
+ }
+
+ // If we are under water with no goals, swim up
+ if(this.waterlevel)
+ if(this.goalcurrent==NULL)
+ {
+ dir = '0 0 0';
+ if(this.waterlevel>WATERLEVEL_SWIMMING)
+ dir.z = 1;
+ else if(this.velocity.z >= 0 && !(this.waterlevel == WATERLEVEL_WETFEET && this.watertype == CONTENT_WATER))
+ PHYS_INPUT_BUTTON_JUMP(this) = true;
+ else
+ PHYS_INPUT_BUTTON_JUMP(this) = false;
+ makevectors(this.v_angle.y * '0 1 0');
+ this.movement_x = dir * v_forward * maxspeed;
+ this.movement_y = dir * v_right * maxspeed;
+ this.movement_z = dir * v_up * maxspeed;
+ }
+
+ // if there is nowhere to go, exit
+ if (this.goalcurrent == NULL)
+ return;
+
+ if (this.goalcurrent)
+ navigation_poptouchedgoals(this);
+
+ // if ran out of goals try to use an alternative goal or get a new strategy asap
+ if(this.goalcurrent == NULL)
+ {
+ this.bot_strategytime = 0;
+ return;
+ }
+
+
+ if(autocvar_bot_debug_goalstack)
+ debuggoalstack(this);
+
+ m1 = this.goalcurrent.origin + this.goalcurrent.mins;
+ m2 = this.goalcurrent.origin + this.goalcurrent.maxs;
+ destorg = this.origin;
+ destorg.x = bound(m1_x, destorg.x, m2_x);
+ destorg.y = bound(m1_y, destorg.y, m2_y);
+ destorg.z = bound(m1_z, destorg.z, m2_z);
+ diff = destorg - this.origin;
+ //dist = vlen(diff);
+ dir = normalize(diff);
+ flatdir = diff;flatdir.z = 0;
+ flatdir = normalize(flatdir);
+ gco = (this.goalcurrent.absmin + this.goalcurrent.absmax) * 0.5;
+
+ //if (this.bot_dodgevector_time < time)
+ {
+ // this.bot_dodgevector_time = time + cvar("bot_ai_dodgeupdateinterval");
+ // this.bot_dodgevector_jumpbutton = 1;
+ evadeobstacle = '0 0 0';
+ evadelava = '0 0 0';
+
+ if (this.waterlevel)
+ {
+ if(this.waterlevel>WATERLEVEL_SWIMMING)
+ {
+ // flatdir_z = 1;
+ this.aistatus |= AI_STATUS_OUT_WATER;
+ }
+ else
+ {
+ if(this.velocity.z >= 0 && !(this.watertype == CONTENT_WATER && gco.z < this.origin.z) &&
+ ( !(this.waterlevel == WATERLEVEL_WETFEET && this.watertype == CONTENT_WATER) || this.aistatus & AI_STATUS_OUT_WATER))
+ PHYS_INPUT_BUTTON_JUMP(this) = true;
+ else
+ PHYS_INPUT_BUTTON_JUMP(this) = false;
+ }
+ dir = normalize(flatdir);
+ makevectors(this.v_angle.y * '0 1 0');
+ }
+ else
+ {
+ if(this.aistatus & AI_STATUS_OUT_WATER)
+ this.aistatus &= ~AI_STATUS_OUT_WATER;
+
+ // jump if going toward an obstacle that doesn't look like stairs we
+ // can walk up directly
+ tracebox(this.origin, this.mins, this.maxs, this.origin + this.velocity * 0.2, false, this);
+ if (trace_fraction < 1)
+ if (trace_plane_normal.z < 0.7)
+ {
+ s = trace_fraction;
+ tracebox(this.origin + stepheightvec, this.mins, this.maxs, this.origin + this.velocity * 0.2 + stepheightvec, false, this);
+ if (trace_fraction < s + 0.01)
+ if (trace_plane_normal.z < 0.7)
+ {
+ s = trace_fraction;
+ tracebox(this.origin + jumpstepheightvec, this.mins, this.maxs, this.origin + this.velocity * 0.2 + jumpstepheightvec, false, this);
+ if (trace_fraction > s)
+ PHYS_INPUT_BUTTON_JUMP(this) = true;
+ }
+ }
+
+ // avoiding dangers and obstacles
+ vector dst_ahead, dst_down;
+ makevectors(this.v_angle.y * '0 1 0');
+ dst_ahead = this.origin + this.view_ofs + (this.velocity * 0.4) + (v_forward * 32 * 3);
+ dst_down = dst_ahead - '0 0 1500';
+
+ // Look ahead
+ traceline(this.origin + this.view_ofs, dst_ahead, true, NULL);
+
+ // Check head-banging against walls
+ if(vdist(this.origin + this.view_ofs - trace_endpos, <, 25) && !(this.aistatus & AI_STATUS_OUT_WATER))
+ {
+ PHYS_INPUT_BUTTON_JUMP(this) = true;
+ if(this.facingwalltime && time > this.facingwalltime)
+ {
+ this.ignoregoal = this.goalcurrent;
+ this.ignoregoaltime = time + autocvar_bot_ai_ignoregoal_timeout;
+ this.bot_strategytime = 0;
+ return;
+ }
+ else
+ {
+ this.facingwalltime = time + 0.05;
+ }
+ }
+ else
+ {
+ this.facingwalltime = 0;
+
+ if(this.ignoregoal != NULL && time > this.ignoregoaltime)
+ {
+ this.ignoregoal = NULL;
+ this.ignoregoaltime = 0;
+ }
+ }
+
+ // Check for water/slime/lava and dangerous edges
+ // (only when the bot is on the ground or jumping intentionally)
+ this.aistatus &= ~AI_STATUS_DANGER_AHEAD;
+
+ if(trace_fraction == 1 && this.jumppadcount == 0 && !this.goalcurrent.wphardwired )
+ if((IS_ONGROUND(this)) || (this.aistatus & AI_STATUS_RUNNING) || PHYS_INPUT_BUTTON_JUMP(this))
+ {
+ // Look downwards
+ traceline(dst_ahead , dst_down, true, NULL);
+ // te_lightning2(NULL, this.origin, dst_ahead); // Draw "ahead" look
+ // te_lightning2(NULL, dst_ahead, dst_down); // Draw "downwards" look
+ if(trace_endpos.z < this.origin.z + this.mins.z)
+ {
+ s = pointcontents(trace_endpos + '0 0 1');
+ if (s != CONTENT_SOLID)
+ if (s == CONTENT_LAVA || s == CONTENT_SLIME)
+ evadelava = normalize(this.velocity) * -1;
+ else if (s == CONTENT_SKY)
+ evadeobstacle = normalize(this.velocity) * -1;
+ else if (!boxesoverlap(dst_ahead - this.view_ofs + this.mins, dst_ahead - this.view_ofs + this.maxs,
+ this.goalcurrent.absmin, this.goalcurrent.absmax))
+ {
+ // if ain't a safe goal with "holes" (like the jumpad on soylent)
+ // and there is a trigger_hurt below
+ if(tracebox_hits_trigger_hurt(dst_ahead, this.mins, this.maxs, trace_endpos))
+ {
+ // Remove dangerous dynamic goals from stack
+ LOG_TRACE("bot ", this.netname, " avoided the goal ", this.goalcurrent.classname, " ", etos(this.goalcurrent), " because it led to a dangerous path; goal stack cleared");
+ navigation_clearroute(this);
+ return;
+ }
+ }
+ }
+ }
+
+ dir = flatdir;
+ evadeobstacle.z = 0;
+ evadelava.z = 0;
+ makevectors(this.v_angle.y * '0 1 0');
+
+ if(evadeobstacle!='0 0 0'||evadelava!='0 0 0')
+ this.aistatus |= AI_STATUS_DANGER_AHEAD;
+ }
+
+ dodge = havocbot_dodge(this);
+ dodge = dodge * bound(0,0.5+(skill+this.bot_dodgeskill)*0.1,1);
+ evadelava = evadelava * bound(1,3-(skill+this.bot_dodgeskill),3); //Noobs fear lava a lot and take more distance from it
+ traceline(this.origin, ( ( this.enemy.absmin + this.enemy.absmax ) * 0.5 ), true, NULL);
+ if(IS_PLAYER(trace_ent))
+ dir = dir * bound(0,(skill+this.bot_dodgeskill)/7,1);
+
+ dir = normalize(dir + dodge + evadeobstacle + evadelava);
+ // this.bot_dodgevector = dir;
+ // this.bot_dodgevector_jumpbutton = PHYS_INPUT_BUTTON_JUMP(this);
+ }
+
+ if(time < this.ladder_time)
+ {
+ if(this.goalcurrent.origin.z + this.goalcurrent.mins.z > this.origin.z + this.mins.z)
+ {
+ if(this.origin.z + this.mins.z < this.ladder_entity.origin.z + this.ladder_entity.maxs.z)
+ dir.z = 1;
+ }
+ else
+ {
+ if(this.origin.z + this.mins.z > this.ladder_entity.origin.z + this.ladder_entity.mins.z)
+ dir.z = -1;
+ }
+ }
+
+ //dir = this.bot_dodgevector;
+ //if (this.bot_dodgevector_jumpbutton)
+ // PHYS_INPUT_BUTTON_JUMP(this) = true;
+ this.movement_x = dir * v_forward * maxspeed;
+ this.movement_y = dir * v_right * maxspeed;
+ this.movement_z = dir * v_up * maxspeed;
+
+ // Emulate keyboard interface
+ if (skill < 10)
+ havocbot_keyboard_movement(this, destorg);
+
+ // Bunnyhop!
+// if(this.aistatus & AI_STATUS_ROAMING)
+ if(this.goalcurrent)
+ if(skill+this.bot_moveskill >= autocvar_bot_ai_bunnyhop_skilloffset)
+ havocbot_bunnyhop(this, dir);
+
+ if ((dir * v_up) >= autocvar_sv_jumpvelocity*0.5 && (IS_ONGROUND(this))) PHYS_INPUT_BUTTON_JUMP(this) = true;
+ if (((dodge * v_up) > 0) && random()*frametime >= 0.2*bound(0,(10-skill-this.bot_dodgeskill)*0.1,1)) PHYS_INPUT_BUTTON_JUMP(this) = true;
+ if (((dodge * v_up) < 0) && random()*frametime >= 0.5*bound(0,(10-skill-this.bot_dodgeskill)*0.1,1)) this.havocbot_ducktime=time+0.3/bound(0.1,skill+this.bot_dodgeskill,10);
+}
+
+void havocbot_chooseenemy(entity this)
+{
+ entity head, best, head2;
+ float rating, bestrating, hf;
+ vector eye, v;
+ if (autocvar_bot_nofire || IS_INDEPENDENT_PLAYER(this))
+ {
+ this.enemy = NULL;
+ return;
+ }
+ if (this.enemy)
+ {
+ if (!bot_shouldattack(this, this.enemy))
+ {
+ // enemy died or something, find a new target
+ this.enemy = NULL;
+ this.havocbot_chooseenemy_finished = time;
+ }
+ else if (this.havocbot_stickenemy)
+ {
+ // tracking last chosen enemy
+ // if enemy is visible
+ // and not really really far away
+ // and we're not severely injured
+ // then keep tracking for a half second into the future
+ traceline(this.origin+this.view_ofs, ( this.enemy.absmin + this.enemy.absmax ) * 0.5,false,NULL);
+ if (trace_ent == this.enemy || trace_fraction == 1)
+ if (vdist(((this.enemy.absmin + this.enemy.absmax) * 0.5) - this.origin, <, 1000))
+ if (this.health > 30)
+ {
+ // remain tracking him for a shot while (case he went after a small corner or pilar
+ this.havocbot_chooseenemy_finished = time + 0.5;
+ return;
+ }
+ // enemy isn't visible, or is far away, or we're injured severely
+ // so stop preferring this enemy
+ // (it will still take a half second until a new one is chosen)
+ this.havocbot_stickenemy = 0;
+ }
+ }
+ if (time < this.havocbot_chooseenemy_finished)
+ return;
+ this.havocbot_chooseenemy_finished = time + autocvar_bot_ai_enemydetectioninterval;
+ eye = this.origin + this.view_ofs;
+ best = NULL;
+ bestrating = 100000000;
+ head = head2 = findchainfloat(bot_attack, true);
+
+ // Backup hit flags
+ hf = this.dphitcontentsmask;
+
+ // Search for enemies, if no enemy can be seen directly try to look through transparent objects
+
+ this.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
+
+ bool scan_transparent = false;
+ bool scan_secondary_targets = false;
+ bool have_secondary_targets = false;
+ while(true)
+ {
+ scan_secondary_targets = false;
+LABEL(scan_targets)
+ for( ; head; head = head.chain)
+ {
+ if(!scan_secondary_targets)
+ {
+ if(head.classname == "misc_breakablemodel")
+ {
+ have_secondary_targets = true;
+ continue;
+ }
+ }
+ else
+ {
+ if(head.classname != "misc_breakablemodel")
+ continue;
+ }
+
+ v = (head.absmin + head.absmax) * 0.5;
+ rating = vlen(v - eye);
+ if (rating<autocvar_bot_ai_enemydetectionradius)
+ if (bestrating > rating)
+ if (bot_shouldattack(this, head))
+ {
+ traceline(eye, v, true, this);
+ if (trace_ent == head || trace_fraction >= 1)
+ {
+ best = head;
+ bestrating = rating;
+ }
+ }
+ }
+
+ if(!best && have_secondary_targets && !scan_secondary_targets)
+ {
+ scan_secondary_targets = true;
+ // restart the loop
+ head = head2;
+ bestrating = 100000000;
+ goto scan_targets;
+ }
+
+ // I want to do a second scan if no enemy was found or I don't have weapons
+ // TODO: Perform the scan when using the rifle (requires changes on the rifle code)
+ if(best || this.weapons) // || this.weapon == WEP_RIFLE.m_id
+ break;
+ if(scan_transparent)
+ break;
+
+ // Set flags to see through transparent objects
+ this.dphitcontentsmask |= DPCONTENTS_OPAQUE;
+
+ head = head2;
+ scan_transparent = true;
+ }
+
+ // Restore hit flags
+ this.dphitcontentsmask = hf;
+
+ this.enemy = best;
+ this.havocbot_stickenemy = true;
+ if(best && best.classname == "misc_breakablemodel")
+ this.havocbot_stickenemy = false;
+}
+
+float havocbot_chooseweapon_checkreload(entity this, int new_weapon)
+{
+ // bots under this skill cannot find unloaded weapons to reload idly when not in combat,
+ // so skip this for them, or they'll never get to reload their weapons at all.
+ // this also allows bots under this skill to be more stupid, and reload more often during combat :)
+ if(skill < 5)
+ return false;
+
+ // if this weapon is scheduled for reloading, don't switch to it during combat
+ if (this.weapon_load[new_weapon] < 0)
+ {
+ bool other_weapon_available = false;
+ FOREACH(Weapons, it != WEP_Null, LAMBDA(
+ if(it.wr_checkammo1(it, this) + it.wr_checkammo2(it, this))
+ other_weapon_available = true;
+ ));
+ if(other_weapon_available)
+ return true;
+ }
+
+ return false;
+}
+
+void havocbot_chooseweapon(entity this)
+{
+ int i;
+
+ // ;)
+ if(g_weaponarena_weapons == WEPSET(TUBA))
+ {
+ PS(this).m_switchweapon = WEP_TUBA;
+ return;
+ }
+
+ // TODO: clean this up by moving it to weapon code
+ if(this.enemy==NULL)
+ {
+ // If no weapon was chosen get the first available weapon
+ if(PS(this).m_weapon==WEP_Null)
+ FOREACH(Weapons, it != WEP_Null, LAMBDA(
+ if(client_hasweapon(this, it, true, false))
+ {
+ PS(this).m_switchweapon = it;
+ return;
+ }
+ ));
+ return;
+ }
+
+ // Do not change weapon during the next second after a combo
+ float f = time - this.lastcombotime;
+ if(f < 1)
+ return;
+
+ float w;
+ float distance; distance=bound(10,vlen(this.origin-this.enemy.origin)-200,10000);
+
+ // Should it do a weapon combo?
+ float af, ct, combo_time, combo;
+
+ af = ATTACK_FINISHED(this, 0);
+ ct = autocvar_bot_ai_weapon_combo_threshold;
+
+ // Bots with no skill will be 4 times more slower than "godlike" bots when doing weapon combos
+ // Ideally this 4 should be calculated as longest_weapon_refire / bot_ai_weapon_combo_threshold
+ combo_time = time + ct + (ct * ((-0.3*(skill+this.bot_weaponskill))+3));
+
+ combo = false;
+
+ if(autocvar_bot_ai_weapon_combo)
+ if(PS(this).m_weapon.m_id == this.lastfiredweapon)
+ if(af > combo_time)
+ {
+ combo = true;
+ this.lastcombotime = time;
+ }
+
+ distance *= pow(2, this.bot_rangepreference);
+
+ // Custom weapon list based on distance to the enemy
+ if(bot_custom_weapon){
+
+ // Choose weapons for far distance
+ if ( distance > bot_distance_far ) {
+ for(i=0; i < Weapons_COUNT && bot_weapons_far[i] != -1 ; ++i){
+ w = bot_weapons_far[i];
+ if ( client_hasweapon(this, Weapons_from(w), true, false) )
+ {
+ if ((PS(this).m_weapon.m_id == w && combo) || havocbot_chooseweapon_checkreload(this, w))
+ continue;
+ PS(this).m_switchweapon = Weapons_from(w);
+ return;
+ }
+ }
+ }
+
+ // Choose weapons for mid distance
+ if ( distance > bot_distance_close) {
+ for(i=0; i < Weapons_COUNT && bot_weapons_mid[i] != -1 ; ++i){
+ w = bot_weapons_mid[i];
+ if ( client_hasweapon(this, Weapons_from(w), true, false) )
+ {
+ if ((PS(this).m_weapon.m_id == w && combo) || havocbot_chooseweapon_checkreload(this, w))
+ continue;
+ PS(this).m_switchweapon = Weapons_from(w);
+ return;
+ }
+ }
+ }
+
+ // Choose weapons for close distance
+ for(i=0; i < Weapons_COUNT && bot_weapons_close[i] != -1 ; ++i){
+ w = bot_weapons_close[i];
+ if ( client_hasweapon(this, Weapons_from(w), true, false) )
+ {
+ if ((PS(this).m_weapon.m_id == w && combo) || havocbot_chooseweapon_checkreload(this, w))
+ continue;
+ PS(this).m_switchweapon = Weapons_from(w);
+ return;
+ }
+ }
+ }
+}
+
+void havocbot_aim(entity this)
+{
+ vector myvel, enemyvel;
+// if(this.flags & FL_INWATER)
+// return;
+ if (time < this.nextaim)
+ return;
+ this.nextaim = time + 0.1;
+ myvel = this.velocity;
+ if (!this.waterlevel)
+ myvel.z = 0;
+ if (this.enemy)
+ {
+ enemyvel = this.enemy.velocity;
+ if (!this.enemy.waterlevel)
+ enemyvel.z = 0;
+ lag_additem(this, time + this.ping, 0, 0, this.enemy, this.origin, myvel, (this.enemy.absmin + this.enemy.absmax) * 0.5, enemyvel);
+ }
+ else
+ lag_additem(this, time + this.ping, 0, 0, NULL, this.origin, myvel, ( this.goalcurrent.absmin + this.goalcurrent.absmax ) * 0.5, '0 0 0');
+}
+
+bool havocbot_moveto_refresh_route(entity this)
+{
+ // Refresh path to goal if necessary
+ entity wp;
+ wp = this.havocbot_personal_waypoint;
+ navigation_goalrating_start(this);
+ navigation_routerating(this, wp, 10000, 10000);
+ navigation_goalrating_end(this);
+ return this.navigation_hasgoals;
+}
+
+float havocbot_moveto(entity this, vector pos)
+{
+ entity wp;
+
+ if(this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_GOING)
+ {
+ // Step 4: Move to waypoint
+ if(this.havocbot_personal_waypoint==NULL)
+ {
+ LOG_TRACE("Error: ", this.netname, " trying to walk to a non existent personal waypoint");
+ this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_GOING;
+ return CMD_STATUS_ERROR;
+ }
+
+ if (!bot_strategytoken_taken)
+ if(this.havocbot_personal_waypoint_searchtime<time)
+ {
+ bot_strategytoken_taken = true;
+ if(havocbot_moveto_refresh_route(this))
+ {
+ LOG_TRACE(this.netname, " walking to its personal waypoint (after ", ftos(this.havocbot_personal_waypoint_failcounter), " failed attempts)");
+ this.havocbot_personal_waypoint_searchtime = time + 10;
+ this.havocbot_personal_waypoint_failcounter = 0;
+ }
+ else
+ {
+ this.havocbot_personal_waypoint_failcounter += 1;
+ this.havocbot_personal_waypoint_searchtime = time + 2;
+ if(this.havocbot_personal_waypoint_failcounter >= 30)
+ {
+ LOG_TRACE("Warning: can't walk to the personal waypoint located at ", vtos(this.havocbot_personal_waypoint.origin));
+ this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_LINKING;
+ delete(this.havocbot_personal_waypoint);
+ return CMD_STATUS_ERROR;
+ }
+ else
+ LOG_TRACE(this.netname, " can't walk to its personal waypoint (after ", ftos(this.havocbot_personal_waypoint_failcounter), " failed attempts), trying later");
+ }
+ }
+
+ if(autocvar_bot_debug_goalstack)
+ debuggoalstack(this);
+
+ // Heading
+ vector dir = ( ( this.goalcurrent.absmin + this.goalcurrent.absmax ) * 0.5 ) - (this.origin + this.view_ofs);
+ dir.z = 0;
+ bot_aimdir(this, dir, -1);
+
+ // Go!
+ havocbot_movetogoal(this);
+
+ if(this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_REACHED)
+ {
+ // Step 5: Waypoint reached
+ LOG_TRACE(this.netname, "'s personal waypoint reached");
+ delete(this.havocbot_personal_waypoint);
+ this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_REACHED;
+ return CMD_STATUS_FINISHED;
+ }
+
+ return CMD_STATUS_EXECUTING;
+ }
+
+ // Step 2: Linking waypoint
+ if(this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_LINKING)
+ {
+ // Wait until it is linked
+ if(!this.havocbot_personal_waypoint.wplinked)
+ {
+ LOG_TRACE(this.netname, " waiting for personal waypoint to be linked");
+ return CMD_STATUS_EXECUTING;
+ }
+
+ this.havocbot_personal_waypoint_searchtime = time; // so we set the route next frame
+ this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_LINKING;
+ this.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_GOING;
+
+ // Step 3: Route to waypoint
+ LOG_TRACE(this.netname, " walking to its personal waypoint");
+
+ return CMD_STATUS_EXECUTING;
+ }
+
+ // Step 1: Spawning waypoint
+ wp = waypoint_spawnpersonal(this, pos);
+ if(wp==NULL)
+ {
+ LOG_TRACE("Error: Can't spawn personal waypoint at ",vtos(pos));
+ return CMD_STATUS_ERROR;
+ }
+
+ this.havocbot_personal_waypoint = wp;
+ this.havocbot_personal_waypoint_failcounter = 0;
+ this.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_LINKING;
+
+ // if pos is inside a teleport, then let's mark it as teleport waypoint
+ FOREACH_ENTITY_CLASS("trigger_teleport", WarpZoneLib_BoxTouchesBrush(pos, pos, it, NULL),
+ {
+ wp.wpflags |= WAYPOINTFLAG_TELEPORT;
+ this.lastteleporttime = 0;
+ });
+
+/*
+ if(wp.wpflags & WAYPOINTFLAG_TELEPORT)
+ print("routing to a teleporter\n");
+ else
+ print("routing to a non-teleporter\n");
+*/
+
+ return CMD_STATUS_EXECUTING;
+}
+
+float havocbot_resetgoal(entity this)
+{
+ navigation_clearroute(this);
+ return CMD_STATUS_FINISHED;
+}
+
+void havocbot_setupbot(entity this)
+{
+ this.bot_ai = havocbot_ai;
+ this.cmd_moveto = havocbot_moveto;
+ this.cmd_resetgoal = havocbot_resetgoal;
+
+ havocbot_chooserole(this);
+}
+
+vector havocbot_dodge(entity this)
+{
+ // LordHavoc: disabled because this is too expensive
+ return '0 0 0';
+#if 0
+ entity head;
+ vector dodge, v, n;
+ float danger, bestdanger, vl, d;
+ dodge = '0 0 0';
+ bestdanger = -20;
+ // check for dangerous objects near bot or approaching bot
+ head = findchainfloat(bot_dodge, true);
+ while(head)
+ {
+ if (head.owner != this)
+ {
+ vl = vlen(head.velocity);
+ if (vl > autocvar_sv_maxspeed * 0.3)
+ {
+ n = normalize(head.velocity);
+ v = this.origin - head.origin;
+ d = v * n;
+ if (d > (0 - head.bot_dodgerating))
+ if (d < (vl * 0.2 + head.bot_dodgerating))
+ {
+ // calculate direction and distance from the flight path, by removing the forward axis
+ v = v - (n * (v * n));
+ danger = head.bot_dodgerating - vlen(v);
+ if (bestdanger < danger)
+ {
+ bestdanger = danger;
+ // dodge to the side of the object
+ dodge = normalize(v);
+ }
+ }
+ }
+ else
+ {
+ danger = head.bot_dodgerating - vlen(head.origin - this.origin);
+ if (bestdanger < danger)
+ {
+ bestdanger = danger;
+ dodge = normalize(this.origin - head.origin);
+ }
+ }
+ }
+ head = head.chain;
+ }
+ return dodge;
+#endif
+}
--- /dev/null
+#pragma once
+
+/*
+ * Globals and Fields
+ */
+
+.float havocbot_keyboardskill;
+.float facingwalltime, ignoregoaltime;
+.float lastfiredweapon;
+.float lastcombotime;
+.float havocbot_blockhead;
+
+.float havocbot_keyboardtime;
+.float havocbot_ducktime;
+.float bot_timelastseengoal;
+.float bot_canruntogoal;
+.float bot_chooseweapontime;
+.float rocketjumptime;
+.float nextaim;
+.float havocbot_personal_waypoint_searchtime;
+.float havocbot_personal_waypoint_failcounter;
+.float havocbot_chooseenemy_finished;
+.float havocbot_stickenemy;
+.float havocbot_role_timeout;
+
+.entity ignoregoal;
+.entity bot_lastseengoal;
+.entity havocbot_personal_waypoint;
+
+.vector havocbot_keyboard;
+
+/*
+ * Functions
+ */
+
+void havocbot_ai(entity this);
+void havocbot_aim(entity this);
+void havocbot_setupbot(entity this);
+void havocbot_movetogoal(entity this);
+void havocbot_chooserole(entity this);
+void havocbot_chooseenemy(entity this);
+void havocbot_chooseweapon(entity this);
+void havocbot_bunnyhop(entity this, vector dir);
+void havocbot_keyboard_movement(entity this, vector destorg);
+
+float havocbot_resetgoal(entity this);
+float havocbot_moveto(entity this, vector pos);
+float havocbot_moveto_refresh_route(entity this);
+
+vector havocbot_dodge(entity this);
+
+.void(entity this) havocbot_role;
+.void(entity this) havocbot_previous_role;
+
+void(entity this, float ratingscale, vector org, float sradius) havocbot_goalrating_items;
+void(entity this, float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers;
+
+/*
+ * Imports
+ */
+
+.entity draggedby;
+.float ladder_time;
+.entity ladder_entity;
--- /dev/null
+#include "roles.qh"
+
+#include "havocbot.qh"
+
+#include "../cvars.qh"
+
+#include "../bot.qh"
+#include "../navigation.qh"
+
+.float max_armorvalue;
+.float havocbot_role_timeout;
+
+.void(entity this) havocbot_previous_role;
+.void(entity this) havocbot_role;
+
+void havocbot_goalrating_items(entity this, float ratingscale, vector org, float sradius)
+{
+ float rating, d, discard, friend_distance, enemy_distance;
+ vector o;
+ ratingscale = ratingscale * 0.0001; // items are rated around 10000 already
+
+ FOREACH_ENTITY_FLOAT(bot_pickup, true,
+ {
+ o = (it.absmin + it.absmax) * 0.5;
+ friend_distance = 10000; enemy_distance = 10000;
+ rating = 0;
+
+ if(!it.solid || vdist(o - org, >, sradius) || (it == this.ignoregoal && time < this.ignoregoaltime) )
+ continue;
+
+ // Check if the item can be picked up safely
+ if(it.classname == "droppedweapon")
+ {
+ traceline(o, o + '0 0 -1500', true, NULL);
+
+ d = pointcontents(trace_endpos + '0 0 1');
+ if(d & CONTENT_WATER || d & CONTENT_SLIME || d & CONTENT_LAVA)
+ continue;
+ if(tracebox_hits_trigger_hurt(it.origin, it.mins, it.maxs, trace_endpos))
+ continue;
+ }
+ else
+ {
+ // Ignore items under water
+ traceline(it.origin + it.maxs, it.origin + it.maxs, MOVE_NORMAL, it);
+ if(trace_dpstartcontents & DPCONTENTS_LIQUIDSMASK)
+ continue;
+ }
+
+ if(teamplay)
+ {
+ discard = false;
+
+ entity picker = it;
+ FOREACH_CLIENT(IS_PLAYER(it) && it != this && !IS_DEAD(it),
+ {
+ d = vlen(it.origin - o); // distance between player and item
+
+ if ( it.team == this.team )
+ {
+ if ( !IS_REAL_CLIENT(it) || discard )
+ continue;
+
+ if( d > friend_distance)
+ continue;
+
+ friend_distance = d;
+
+ discard = true;
+
+ if( picker.health && it.health > this.health )
+ continue;
+
+ if( picker.armorvalue && it.armorvalue > this.armorvalue)
+ continue;
+
+ if( picker.weapons )
+ if( picker.weapons & ~it.weapons )
+ continue;
+
+ if (picker.ammo_shells && it.ammo_shells > this.ammo_shells)
+ continue;
+
+ if (picker.ammo_nails && it.ammo_nails > this.ammo_nails)
+ continue;
+
+ if (picker.ammo_rockets && it.ammo_rockets > this.ammo_rockets)
+ continue;
+
+ if (picker.ammo_cells && it.ammo_cells > this.ammo_cells)
+ continue;
+
+ if (picker.ammo_plasma && it.ammo_plasma > this.ammo_plasma)
+ continue;
+
+ discard = false;
+ }
+ else
+ {
+ // If enemy only track distances
+ // TODO: track only if visible ?
+ if( d < enemy_distance )
+ enemy_distance = d;
+ }
+ });
+
+ // Rate the item only if no one needs it, or if an enemy is closer to it
+ if ( (enemy_distance < friend_distance && vdist(o - org, <, enemy_distance)) ||
+ (friend_distance > autocvar_bot_ai_friends_aware_pickup_radius ) || !discard )
+ rating = it.bot_pickupevalfunc(this, it);
+
+ }
+ else
+ rating = it.bot_pickupevalfunc(this, it);
+
+ if(rating > 0)
+ navigation_routerating(this, it, rating * ratingscale, 2000);
+ });
+}
+
+void havocbot_goalrating_controlpoints(entity this, float ratingscale, vector org, float sradius)
+{
+ FOREACH_ENTITY_CLASS("dom_controlpoint", vdist((((it.absmin + it.absmax) * 0.5) - org), <, sradius),
+ {
+ if(it.cnt > -1) // this is just being fought
+ navigation_routerating(this, it, ratingscale, 5000);
+ else if(it.goalentity.cnt == 0) // unclaimed
+ navigation_routerating(this, it, ratingscale * 0.5, 5000);
+ else if(it.goalentity.team != this.team) // other team's point
+ navigation_routerating(this, it, ratingscale * 0.2, 5000);
+ });
+}
+
+void havocbot_goalrating_enemyplayers(entity this, float ratingscale, vector org, float sradius)
+{
+ if (autocvar_bot_nofire)
+ return;
+
+ // don't chase players if we're under water
+ if(this.waterlevel>WATERLEVEL_WETFEET)
+ return;
+
+ int t;
+
+ FOREACH_CLIENT(IS_PLAYER(it) && bot_shouldattack(this, it), LAMBDA(
+ // TODO: Merge this logic with the bot_shouldattack function
+ if(vdist(it.origin - org, <, 100) || vdist(it.origin - org, >, sradius))
+ continue;
+
+ // rate only visible enemies
+ /*
+ traceline(this.origin + this.view_ofs, it.origin, MOVE_NOMONSTERS, this);
+ if (trace_fraction < 1 || trace_ent != it)
+ continue;
+ */
+
+ if((it.flags & FL_INWATER) || (it.flags & FL_PARTIALGROUND))
+ continue;
+
+ // not falling
+ if((IS_ONGROUND(it)) == 0)
+ {
+ traceline(it.origin, it.origin + '0 0 -1500', true, NULL);
+ t = pointcontents(trace_endpos + '0 0 1');
+ if(t != CONTENT_SOLID )
+ if(t & CONTENT_WATER || t & CONTENT_SLIME || t & CONTENT_LAVA)
+ continue;
+ if(tracebox_hits_trigger_hurt(it.origin, it.mins, it.maxs, trace_endpos))
+ continue;
+ }
+
+ // TODO: rate waypoints near the targetted player at that moment, instead of the player itthis
+ // adding a player as a goal seems to be quite dangerous, especially on space maps
+ // remove hack in navigation_poptouchedgoals() after performing this change
+
+ t = (this.health + this.armorvalue ) / (it.health + it.armorvalue );
+ navigation_routerating(this, it, t * ratingscale, 2000);
+ ));
+}
+
+// legacy bot role for standard gamemodes
+// go to best items
+void havocbot_role_generic(entity this)
+{
+ if(IS_DEAD(this))
+ return;
+
+ if (this.bot_strategytime < time)
+ {
+ this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+ navigation_goalrating_start(this);
+ havocbot_goalrating_items(this, 10000, this.origin, 10000);
+ havocbot_goalrating_enemyplayers(this, 20000, this.origin, 10000);
+ //havocbot_goalrating_waypoints(1, this.origin, 1000);
+ navigation_goalrating_end(this);
+ }
+}
+
+void havocbot_chooserole_generic(entity this)
+{
+ this.havocbot_role = havocbot_role_generic;
+}
+
+void havocbot_chooserole(entity this)
+{
+ LOG_TRACE("choosing a role...");
+ this.bot_strategytime = 0;
+ if(!MUTATOR_CALLHOOK(HavocBot_ChooseRole, this))
+ havocbot_chooserole_generic(this);
+}
--- /dev/null
+#pragma once
+void havocbot_goalrating_controlpoints(entity this, float ratingscale, vector org, float sradius);
--- /dev/null
+#pragma once
+
+void bot_clearqueue(entity bot);
--- /dev/null
+#include "navigation.qh"
+
+#include "cvars.qh"
+
+#include "bot.qh"
+#include "waypoints.qh"
+
+#include <common/t_items.qh>
+
+#include <common/items/all.qh>
+
+#include <common/constants.qh>
+#include <common/triggers/trigger/jumppads.qh>
+
+.float speed;
+
+// rough simulation of walking from one point to another to test if a path
+// can be traveled, used for waypoint linking and havocbot
+
+bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float movemode)
+{
+ vector org;
+ vector move;
+ vector dir;
+ float dist;
+ float totaldist;
+ float stepdist;
+ float yaw;
+ float ignorehazards;
+ float swimming;
+
+ if(autocvar_bot_debug_tracewalk)
+ {
+ debugresetnodes();
+ debugnode(e, start);
+ }
+
+ move = end - start;
+ move.z = 0;
+ org = start;
+ dist = totaldist = vlen(move);
+ dir = normalize(move);
+ stepdist = 32;
+ ignorehazards = false;
+ swimming = false;
+
+ // Analyze starting point
+ traceline(start, start, MOVE_NORMAL, e);
+ if (trace_dpstartcontents & (DPCONTENTS_SLIME | DPCONTENTS_LAVA))
+ ignorehazards = true;
+ else
+ {
+ traceline( start, start + '0 0 -65536', MOVE_NORMAL, e);
+ if (trace_dpstartcontents & (DPCONTENTS_SLIME | DPCONTENTS_LAVA))
+ {
+ ignorehazards = true;
+ swimming = true;
+ }
+ }
+ tracebox(start, m1, m2, start, MOVE_NOMONSTERS, e);
+ if (trace_startsolid)
+ {
+ // Bad start
+ if(autocvar_bot_debug_tracewalk)
+ debugnodestatus(start, DEBUG_NODE_FAIL);
+
+ //print("tracewalk: ", vtos(start), " is a bad start\n");
+ return false;
+ }
+
+ // Movement loop
+ yaw = vectoyaw(move);
+ move = end - org;
+ for (;;)
+ {
+ if (boxesoverlap(end, end, org + m1 + '-1 -1 -1', org + m2 + '1 1 1'))
+ {
+ // Succeeded
+ if(autocvar_bot_debug_tracewalk)
+ debugnodestatus(org, DEBUG_NODE_SUCCESS);
+
+ //print("tracewalk: ", vtos(start), " can reach ", vtos(end), "\n");
+ return true;
+ }
+ if(autocvar_bot_debug_tracewalk)
+ debugnode(e, org);
+
+ if (dist <= 0)
+ break;
+ if (stepdist > dist)
+ stepdist = dist;
+ dist = dist - stepdist;
+ traceline(org, org, MOVE_NORMAL, e);
+ if (!ignorehazards)
+ {
+ if (trace_dpstartcontents & (DPCONTENTS_SLIME | DPCONTENTS_LAVA))
+ {
+ // hazards blocking path
+ if(autocvar_bot_debug_tracewalk)
+ debugnodestatus(org, DEBUG_NODE_FAIL);
+
+ //print("tracewalk: ", vtos(start), " hits a hazard when trying to reach ", vtos(end), "\n");
+ return false;
+ }
+ }
+ if (trace_dpstartcontents & DPCONTENTS_LIQUIDSMASK)
+ {
+ move = normalize(end - org);
+ tracebox(org, m1, m2, org + move * stepdist, movemode, e);
+
+ if(autocvar_bot_debug_tracewalk)
+ debugnode(e, trace_endpos);
+
+ if (trace_fraction < 1)
+ {
+ swimming = true;
+ org = trace_endpos - normalize(org - trace_endpos) * stepdist;
+ for (; org.z < end.z + e.maxs.z; org.z += stepdist)
+ {
+ if(autocvar_bot_debug_tracewalk)
+ debugnode(e, org);
+
+ if(pointcontents(org) == CONTENT_EMPTY)
+ break;
+ }
+
+ if(pointcontents(org + '0 0 1') != CONTENT_EMPTY)
+ {
+ if(autocvar_bot_debug_tracewalk)
+ debugnodestatus(org, DEBUG_NODE_FAIL);
+
+ return false;
+ //print("tracewalk: ", vtos(start), " failed under water\n");
+ }
+ continue;
+
+ }
+ else
+ org = trace_endpos;
+ }
+ else
+ {
+ move = dir * stepdist + org;
+ tracebox(org, m1, m2, move, movemode, e);
+
+ if(autocvar_bot_debug_tracewalk)
+ debugnode(e, trace_endpos);
+
+ // hit something
+ if (trace_fraction < 1)
+ {
+ // check if we can walk over this obstacle, possibly by jumpstepping
+ tracebox(org + stepheightvec, m1, m2, move + stepheightvec, movemode, e);
+ if (trace_fraction < 1 || trace_startsolid)
+ {
+ tracebox(org + jumpstepheightvec, m1, m2, move + jumpstepheightvec, movemode, e);
+ if (trace_fraction < 1 || trace_startsolid)
+ {
+ if(autocvar_bot_debug_tracewalk)
+ debugnodestatus(trace_endpos, DEBUG_NODE_WARNING);
+
+ // check for doors
+ traceline( org, move, movemode, e);
+ if ( trace_ent.classname == "door_rotating" || trace_ent.classname == "door")
+ {
+ vector nextmove;
+ move = trace_endpos;
+ while(trace_ent.classname == "door_rotating" || trace_ent.classname == "door")
+ {
+ nextmove = move + (dir * stepdist);
+ traceline( move, nextmove, movemode, e);
+ move = nextmove;
+ }
+ }
+ else
+ {
+ if(autocvar_bot_debug_tracewalk)
+ debugnodestatus(trace_endpos, DEBUG_NODE_FAIL);
+
+ //print("tracewalk: ", vtos(start), " hit something when trying to reach ", vtos(end), "\n");
+ //te_explosion(trace_endpos);
+ //print(ftos(e.dphitcontentsmask), "\n");
+ return false; // failed
+ }
+ }
+ else
+ move = trace_endpos;
+ }
+ else
+ move = trace_endpos;
+ }
+ else
+ move = trace_endpos;
+
+ // trace down from stepheight as far as possible and move there,
+ // if this starts in solid we try again without the stepup, and
+ // if that also fails we assume it is a wall
+ // (this is the same logic as the Quake walkmove function used)
+ tracebox(move, m1, m2, move + '0 0 -65536', movemode, e);
+
+ // moved successfully
+ if(swimming)
+ {
+ float c;
+ c = pointcontents(org + '0 0 1');
+ if (!(c == CONTENT_WATER || c == CONTENT_LAVA || c == CONTENT_SLIME))
+ swimming = false;
+ else
+ continue;
+ }
+
+ org = trace_endpos;
+ }
+ }
+
+ //print("tracewalk: ", vtos(start), " did not arrive at ", vtos(end), " but at ", vtos(org), "\n");
+
+ // moved but didn't arrive at the intended destination
+ if(autocvar_bot_debug_tracewalk)
+ debugnodestatus(org, DEBUG_NODE_FAIL);
+
+ return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// goal stack
+/////////////////////////////////////////////////////////////////////////////
+
+// completely empty the goal stack, used when deciding where to go
+void navigation_clearroute(entity this)
+{
+ //print("bot ", etos(this), " clear\n");
+ this.navigation_hasgoals = false;
+ this.goalcurrent = NULL;
+ this.goalstack01 = NULL;
+ this.goalstack02 = NULL;
+ this.goalstack03 = NULL;
+ this.goalstack04 = NULL;
+ this.goalstack05 = NULL;
+ this.goalstack06 = NULL;
+ this.goalstack07 = NULL;
+ this.goalstack08 = NULL;
+ this.goalstack09 = NULL;
+ this.goalstack10 = NULL;
+ this.goalstack11 = NULL;
+ this.goalstack12 = NULL;
+ this.goalstack13 = NULL;
+ this.goalstack14 = NULL;
+ this.goalstack15 = NULL;
+ this.goalstack16 = NULL;
+ this.goalstack17 = NULL;
+ this.goalstack18 = NULL;
+ this.goalstack19 = NULL;
+ this.goalstack20 = NULL;
+ this.goalstack21 = NULL;
+ this.goalstack22 = NULL;
+ this.goalstack23 = NULL;
+ this.goalstack24 = NULL;
+ this.goalstack25 = NULL;
+ this.goalstack26 = NULL;
+ this.goalstack27 = NULL;
+ this.goalstack28 = NULL;
+ this.goalstack29 = NULL;
+ this.goalstack30 = NULL;
+ this.goalstack31 = NULL;
+}
+
+// add a new goal at the beginning of the stack
+// (in other words: add a new prerequisite before going to the later goals)
+// NOTE: when a waypoint is added, the WP gets pushed first, then the
+// next-closest WP on the shortest path to the WP
+// That means, if the stack overflows, the bot will know how to do the FIRST 32
+// steps to the goal, and then recalculate the path.
+void navigation_pushroute(entity this, entity e)
+{
+ //print("bot ", etos(this), " push ", etos(e), "\n");
+ this.goalstack31 = this.goalstack30;
+ this.goalstack30 = this.goalstack29;
+ this.goalstack29 = this.goalstack28;
+ this.goalstack28 = this.goalstack27;
+ this.goalstack27 = this.goalstack26;
+ this.goalstack26 = this.goalstack25;
+ this.goalstack25 = this.goalstack24;
+ this.goalstack24 = this.goalstack23;
+ this.goalstack23 = this.goalstack22;
+ this.goalstack22 = this.goalstack21;
+ this.goalstack21 = this.goalstack20;
+ this.goalstack20 = this.goalstack19;
+ this.goalstack19 = this.goalstack18;
+ this.goalstack18 = this.goalstack17;
+ this.goalstack17 = this.goalstack16;
+ this.goalstack16 = this.goalstack15;
+ this.goalstack15 = this.goalstack14;
+ this.goalstack14 = this.goalstack13;
+ this.goalstack13 = this.goalstack12;
+ this.goalstack12 = this.goalstack11;
+ this.goalstack11 = this.goalstack10;
+ this.goalstack10 = this.goalstack09;
+ this.goalstack09 = this.goalstack08;
+ this.goalstack08 = this.goalstack07;
+ this.goalstack07 = this.goalstack06;
+ this.goalstack06 = this.goalstack05;
+ this.goalstack05 = this.goalstack04;
+ this.goalstack04 = this.goalstack03;
+ this.goalstack03 = this.goalstack02;
+ this.goalstack02 = this.goalstack01;
+ this.goalstack01 = this.goalcurrent;
+ this.goalcurrent = e;
+}
+
+// remove first goal from stack
+// (in other words: remove a prerequisite for reaching the later goals)
+// (used when a spawnfunc_waypoint is reached)
+void navigation_poproute(entity this)
+{
+ //print("bot ", etos(this), " pop\n");
+ this.goalcurrent = this.goalstack01;
+ this.goalstack01 = this.goalstack02;
+ this.goalstack02 = this.goalstack03;
+ this.goalstack03 = this.goalstack04;
+ this.goalstack04 = this.goalstack05;
+ this.goalstack05 = this.goalstack06;
+ this.goalstack06 = this.goalstack07;
+ this.goalstack07 = this.goalstack08;
+ this.goalstack08 = this.goalstack09;
+ this.goalstack09 = this.goalstack10;
+ this.goalstack10 = this.goalstack11;
+ this.goalstack11 = this.goalstack12;
+ this.goalstack12 = this.goalstack13;
+ this.goalstack13 = this.goalstack14;
+ this.goalstack14 = this.goalstack15;
+ this.goalstack15 = this.goalstack16;
+ this.goalstack16 = this.goalstack17;
+ this.goalstack17 = this.goalstack18;
+ this.goalstack18 = this.goalstack19;
+ this.goalstack19 = this.goalstack20;
+ this.goalstack20 = this.goalstack21;
+ this.goalstack21 = this.goalstack22;
+ this.goalstack22 = this.goalstack23;
+ this.goalstack23 = this.goalstack24;
+ this.goalstack24 = this.goalstack25;
+ this.goalstack25 = this.goalstack26;
+ this.goalstack26 = this.goalstack27;
+ this.goalstack27 = this.goalstack28;
+ this.goalstack28 = this.goalstack29;
+ this.goalstack29 = this.goalstack30;
+ this.goalstack30 = this.goalstack31;
+ this.goalstack31 = NULL;
+}
+
+float navigation_waypoint_will_link(vector v, vector org, entity ent, float walkfromwp, float bestdist)
+{
+ float dist;
+ dist = vlen(v - org);
+ if (bestdist > dist)
+ {
+ traceline(v, org, true, ent);
+ if (trace_fraction == 1)
+ {
+ if (walkfromwp)
+ {
+ if (tracewalk(ent, v, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), org, bot_navigation_movemode))
+ return true;
+ }
+ else
+ {
+ if (tracewalk(ent, org, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), v, bot_navigation_movemode))
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+// find the spawnfunc_waypoint near a dynamic goal such as a dropped weapon
+entity navigation_findnearestwaypoint_withdist_except(entity ent, float walkfromwp, float bestdist, entity except)
+{
+ vector pm1 = ent.origin + ent.mins;
+ vector pm2 = ent.origin + ent.maxs;
+
+ // do two scans, because box test is cheaper
+ IL_EACH(g_waypoints, it != ent && it != except,
+ {
+ if(boxesoverlap(pm1, pm2, it.absmin, it.absmax))
+ return it;
+ });
+
+ vector org = ent.origin + 0.5 * (ent.mins + ent.maxs);
+ org.z = ent.origin.z + ent.mins.z - STAT(PL_MIN, NULL).z; // player height
+ // TODO possibly make other code have the same support for bboxes
+ if(ent.tag_entity)
+ org = org + ent.tag_entity.origin;
+ if (navigation_testtracewalk)
+ te_plasmaburn(org);
+
+ entity best = NULL;
+ vector v;
+
+ // box check failed, try walk
+ IL_EACH(g_waypoints, it != ent,
+ {
+ if(it.wpisbox)
+ {
+ vector wm1 = it.origin + it.mins;
+ vector wm2 = it.origin + it.maxs;
+ v.x = bound(wm1_x, org.x, wm2_x);
+ v.y = bound(wm1_y, org.y, wm2_y);
+ v.z = bound(wm1_z, org.z, wm2_z);
+ }
+ else
+ v = it.origin;
+ if(navigation_waypoint_will_link(v, org, ent, walkfromwp, bestdist))
+ {
+ bestdist = vlen(v - org);
+ best = it;
+ }
+ });
+ return best;
+}
+entity navigation_findnearestwaypoint(entity ent, float walkfromwp)
+{
+ entity wp = navigation_findnearestwaypoint_withdist_except(ent, walkfromwp, 1050, NULL);
+ if (autocvar_g_waypointeditor_auto)
+ {
+ entity wp2 = navigation_findnearestwaypoint_withdist_except(ent, walkfromwp, 1050, wp);
+ if (wp && !wp2)
+ wp.wpflags |= WAYPOINTFLAG_PROTECTED;
+ }
+ return wp;
+}
+
+// finds the waypoints near the bot initiating a navigation query
+float navigation_markroutes_nearestwaypoints(entity this, float maxdist)
+{
+ vector v, m1, m2;
+// navigation_testtracewalk = true;
+ int c = 0;
+ IL_EACH(g_waypoints, !it.wpconsidered,
+ {
+ if (it.wpisbox)
+ {
+ m1 = it.origin + it.mins;
+ m2 = it.origin + it.maxs;
+ v = this.origin;
+ v.x = bound(m1_x, v.x, m2_x);
+ v.y = bound(m1_y, v.y, m2_y);
+ v.z = bound(m1_z, v.z, m2_z);
+ }
+ else
+ v = it.origin;
+ vector diff = v - this.origin;
+ diff.z = max(0, diff.z);
+ if(vdist(diff, <, maxdist))
+ {
+ it.wpconsidered = true;
+ if (tracewalk(this, this.origin, this.mins, this.maxs, v, bot_navigation_movemode))
+ {
+ it.wpnearestpoint = v;
+ it.wpcost = vlen(v - this.origin) + it.dmg;
+ it.wpfire = 1;
+ it.enemy = NULL;
+ c = c + 1;
+ }
+ }
+ });
+ //navigation_testtracewalk = false;
+ return c;
+}
+
+// updates a path link if a spawnfunc_waypoint link is better than the current one
+void navigation_markroutes_checkwaypoint(entity w, entity wp, float cost2, vector p)
+{
+ vector m1;
+ vector m2;
+ vector v;
+ if (wp.wpisbox)
+ {
+ m1 = wp.absmin;
+ m2 = wp.absmax;
+ v.x = bound(m1_x, p.x, m2_x);
+ v.y = bound(m1_y, p.y, m2_y);
+ v.z = bound(m1_z, p.z, m2_z);
+ }
+ else
+ v = wp.origin;
+ cost2 = cost2 + vlen(v - p);
+ if (wp.wpcost > cost2)
+ {
+ wp.wpcost = cost2;
+ wp.enemy = w;
+ wp.wpfire = 1;
+ wp.wpnearestpoint = v;
+ }
+}
+
+// queries the entire spawnfunc_waypoint network for pathes leading away from the bot
+void navigation_markroutes(entity this, entity fixed_source_waypoint)
+{
+ float cost, cost2;
+ vector p;
+
+ IL_EACH(g_waypoints, true,
+ {
+ it.wpconsidered = false;
+ it.wpnearestpoint = '0 0 0';
+ it.wpcost = 10000000;
+ it.wpfire = 0;
+ it.enemy = NULL;
+ });
+
+ if(fixed_source_waypoint)
+ {
+ fixed_source_waypoint.wpconsidered = true;
+ fixed_source_waypoint.wpnearestpoint = fixed_source_waypoint.origin + 0.5 * (fixed_source_waypoint.mins + fixed_source_waypoint.maxs);
+ fixed_source_waypoint.wpcost = fixed_source_waypoint.dmg;
+ fixed_source_waypoint.wpfire = 1;
+ fixed_source_waypoint.enemy = NULL;
+ }
+ else
+ {
+ // try a short range search for the nearest waypoints, and expand the search repeatedly if none are found
+ // as this search is expensive we will use lower values if the bot is on the air
+ float increment, maxdistance;
+ if(IS_ONGROUND(this))
+ {
+ increment = 750;
+ maxdistance = 50000;
+ }
+ else
+ {
+ increment = 500;
+ maxdistance = 1500;
+ }
+
+ for(int j = increment; !navigation_markroutes_nearestwaypoints(this, j) && j < maxdistance; j += increment);
+ }
+
+ bool searching = true;
+ while (searching)
+ {
+ searching = false;
+ IL_EACH(g_waypoints, it.wpfire,
+ {
+ searching = true;
+ it.wpfire = 0;
+ cost = it.wpcost;
+ p = it.wpnearestpoint;
+ entity wp;
+ wp = it.wp00;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp00mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp01;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp01mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp02;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp02mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp03;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp03mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp04;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp04mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp05;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp05mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp06;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp06mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp07;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp07mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp08;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp08mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp09;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp09mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp10;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp10mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp11;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp11mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp12;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp12mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp13;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp13mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp14;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp14mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp15;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp15mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp16;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp16mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp17;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp17mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp18;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp18mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp19;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp19mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp20;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp20mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp21;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp21mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp22;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp22mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp23;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp23mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp24;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp24mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp25;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp25mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp26;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp26mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp27;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp27mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp28;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp28mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp29;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp29mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp30;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp30mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ wp = it.wp31;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp31mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
+ }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
+ });
+ }
+}
+
+// queries the entire spawnfunc_waypoint network for pathes leading to the bot
+void navigation_markroutes_inverted(entity fixed_source_waypoint)
+{
+ float cost, cost2;
+ vector p;
+ IL_EACH(g_waypoints, true,
+ {
+ it.wpconsidered = false;
+ it.wpnearestpoint = '0 0 0';
+ it.wpcost = 10000000;
+ it.wpfire = 0;
+ it.enemy = NULL;
+ });
+
+ if(fixed_source_waypoint)
+ {
+ fixed_source_waypoint.wpconsidered = true;
+ fixed_source_waypoint.wpnearestpoint = fixed_source_waypoint.origin + 0.5 * (fixed_source_waypoint.mins + fixed_source_waypoint.maxs);
+ fixed_source_waypoint.wpcost = fixed_source_waypoint.dmg; // the cost to get from X to fixed_source_waypoint
+ fixed_source_waypoint.wpfire = 1;
+ fixed_source_waypoint.enemy = NULL;
+ }
+ else
+ {
+ error("need to start with a waypoint\n");
+ }
+
+ bool searching = true;
+ while (searching)
+ {
+ searching = false;
+ IL_EACH(g_waypoints, it.wpfire,
+ {
+ searching = true;
+ it.wpfire = 0;
+ cost = it.wpcost; // cost to walk from it to home
+ p = it.wpnearestpoint;
+ entity wp = it;
+ IL_EACH(g_waypoints, true,
+ {
+ if(wp != it.wp00) if(wp != it.wp01) if(wp != it.wp02) if(wp != it.wp03)
+ if(wp != it.wp04) if(wp != it.wp05) if(wp != it.wp06) if(wp != it.wp07)
+ if(wp != it.wp08) if(wp != it.wp09) if(wp != it.wp10) if(wp != it.wp11)
+ if(wp != it.wp12) if(wp != it.wp13) if(wp != it.wp14) if(wp != it.wp15)
+ if(wp != it.wp16) if(wp != it.wp17) if(wp != it.wp18) if(wp != it.wp19)
+ if(wp != it.wp20) if(wp != it.wp21) if(wp != it.wp22) if(wp != it.wp23)
+ if(wp != it.wp24) if(wp != it.wp25) if(wp != it.wp26) if(wp != it.wp27)
+ if(wp != it.wp28) if(wp != it.wp29) if(wp != it.wp30) if(wp != it.wp31)
+ continue;
+ cost2 = cost + it.dmg;
+ navigation_markroutes_checkwaypoint(wp, it, cost2, p);
+ });
+ });
+ }
+}
+
+// updates the best goal according to a weighted calculation of travel cost and item value of a new proposed item
+void navigation_routerating(entity this, entity e, float f, float rangebias)
+{
+ entity nwp;
+ vector o;
+ if (!e)
+ return;
+
+ if(e.blacklisted)
+ return;
+
+ o = (e.absmin + e.absmax) * 0.5;
+
+ //print("routerating ", etos(e), " = ", ftos(f), " - ", ftos(rangebias), "\n");
+
+ // Evaluate path using jetpack
+ if(g_jetpack)
+ if(this.items & IT_JETPACK)
+ if(autocvar_bot_ai_navigation_jetpack)
+ if(vdist(this.origin - o, >, autocvar_bot_ai_navigation_jetpack_mindistance))
+ {
+ vector pointa, pointb;
+
+ LOG_DEBUG("jetpack ai: evaluating path for ", e.classname);
+
+ // Point A
+ traceline(this.origin, this.origin + '0 0 65535', MOVE_NORMAL, this);
+ pointa = trace_endpos - '0 0 1';
+
+ // Point B
+ traceline(o, o + '0 0 65535', MOVE_NORMAL, e);
+ pointb = trace_endpos - '0 0 1';
+
+ // Can I see these two points from the sky?
+ traceline(pointa, pointb, MOVE_NORMAL, this);
+
+ if(trace_fraction==1)
+ {
+ LOG_DEBUG("jetpack ai: can bridge these two points");
+
+ // Lower the altitude of these points as much as possible
+ float zdistance, xydistance, cost, t, fuel;
+ vector down, npa, npb;
+
+ down = '0 0 -1' * (STAT(PL_MAX, NULL).z - STAT(PL_MIN, NULL).z) * 10;
+
+ do{
+ npa = pointa + down;
+ npb = pointb + down;
+
+ if(npa.z<=this.absmax.z)
+ break;
+
+ if(npb.z<=e.absmax.z)
+ break;
+
+ traceline(npa, npb, MOVE_NORMAL, this);
+ if(trace_fraction==1)
+ {
+ pointa = npa;
+ pointb = npb;
+ }
+ }
+ while(trace_fraction == 1);
+
+
+ // Rough estimation of fuel consumption
+ // (ignores acceleration and current xyz velocity)
+ xydistance = vlen(pointa - pointb);
+ zdistance = fabs(pointa.z - this.origin.z);
+
+ t = zdistance / autocvar_g_jetpack_maxspeed_up;
+ t += xydistance / autocvar_g_jetpack_maxspeed_side;
+ fuel = t * autocvar_g_jetpack_fuel * 0.8;
+
+ LOG_DEBUG("jetpack ai: required fuel ", ftos(fuel), " this.ammo_fuel ", ftos(this.ammo_fuel));
+
+ // enough fuel ?
+ if(this.ammo_fuel>fuel)
+ {
+ // Estimate cost
+ // (as onground costs calculation is mostly based on distances, here we do the same establishing some relationship
+ // - between air and ground speeds)
+
+ cost = xydistance / (autocvar_g_jetpack_maxspeed_side/autocvar_sv_maxspeed);
+ cost += zdistance / (autocvar_g_jetpack_maxspeed_up/autocvar_sv_maxspeed);
+ cost *= 1.5;
+
+ // Compare against other goals
+ f = f * rangebias / (rangebias + cost);
+
+ if (navigation_bestrating < f)
+ {
+ LOG_DEBUG("jetpack path: added goal ", e.classname, " (with rating ", ftos(f), ")");
+ navigation_bestrating = f;
+ navigation_bestgoal = e;
+ this.navigation_jetpack_goal = e;
+ this.navigation_jetpack_point = pointb;
+ }
+ return;
+ }
+ }
+ }
+
+ //te_wizspike(e.origin);
+ //bprint(etos(e));
+ //bprint("\n");
+ // update the cached spawnfunc_waypoint link on a dynamic item entity
+ if(e.classname == "waypoint" && !(e.wpflags & WAYPOINTFLAG_PERSONAL))
+ {
+ nwp = e;
+ }
+ else
+ {
+ float search;
+
+ search = true;
+
+ if(e.flags & FL_ITEM)
+ {
+ if (!(e.flags & FL_WEAPON))
+ if(e.nearestwaypoint)
+ search = false;
+ }
+ else if (e.flags & FL_WEAPON)
+ {
+ if(e.classname != "droppedweapon")
+ if(e.nearestwaypoint)
+ search = false;
+ }
+
+ if(search)
+ if (time > e.nearestwaypointtimeout)
+ {
+ nwp = navigation_findnearestwaypoint(e, true);
+ if(nwp)
+ e.nearestwaypoint = nwp;
+ else
+ {
+ LOG_DEBUG("FAILED to find a nearest waypoint to '", e.classname, "' #", etos(e));
+
+ if(e.flags & FL_ITEM)
+ e.blacklisted = true;
+ else if (e.flags & FL_WEAPON)
+ {
+ if(e.classname != "droppedweapon")
+ e.blacklisted = true;
+ }
+
+ if(e.blacklisted)
+ {
+ LOG_DEBUG("The entity '", e.classname, "' is going to be excluded from path finding during this match");
+ return;
+ }
+ }
+
+ // TODO: Cleaner solution, probably handling this timeout from ctf.qc
+ if(e.classname=="item_flag_team")
+ e.nearestwaypointtimeout = time + 2;
+ else
+ e.nearestwaypointtimeout = time + random() * 3 + 5;
+ }
+ nwp = e.nearestwaypoint;
+ }
+
+ LOG_DEBUG("-- checking ", e.classname, " (with cost ", ftos(nwp.wpcost), ")");
+ if (nwp)
+ if (nwp.wpcost < 10000000)
+ {
+ //te_wizspike(nwp.wpnearestpoint);
+ LOG_DEBUG(e.classname, " ", ftos(f), "/(1+", ftos((nwp.wpcost + vlen(e.origin - nwp.wpnearestpoint))), "/", ftos(rangebias), ") = ");
+ f = f * rangebias / (rangebias + (nwp.wpcost + vlen(o - nwp.wpnearestpoint)));
+ LOG_DEBUG("considering ", e.classname, " (with rating ", ftos(f), ")");
+ if (navigation_bestrating < f)
+ {
+ LOG_DEBUG("ground path: added goal ", e.classname, " (with rating ", ftos(f), ")");
+ navigation_bestrating = f;
+ navigation_bestgoal = e;
+ }
+ }
+}
+
+// adds an item to the the goal stack with the path to a given item
+bool navigation_routetogoal(entity this, entity e, vector startposition)
+{
+ this.goalentity = e;
+
+ // if there is no goal, just exit
+ if (!e)
+ return false;
+
+ this.navigation_hasgoals = true;
+
+ // put the entity on the goal stack
+ //print("routetogoal ", etos(e), "\n");
+ navigation_pushroute(this, e);
+
+ if(g_jetpack)
+ if(e==this.navigation_jetpack_goal)
+ return true;
+
+ // if it can reach the goal there is nothing more to do
+ if (tracewalk(this, startposition, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), (e.absmin + e.absmax) * 0.5, bot_navigation_movemode))
+ return true;
+
+ // see if there are waypoints describing a path to the item
+ if(e.classname != "waypoint" || (e.wpflags & WAYPOINTFLAG_PERSONAL))
+ e = e.nearestwaypoint;
+ else
+ e = e.enemy; // we already have added it, so...
+
+ if(e == NULL)
+ return false;
+
+ for (;;)
+ {
+ // add the spawnfunc_waypoint to the path
+ navigation_pushroute(this, e);
+ e = e.enemy;
+
+ if(e==NULL)
+ break;
+ }
+
+ return false;
+}
+
+// removes any currently touching waypoints from the goal stack
+// (this is how bots detect if they reached a goal)
+void navigation_poptouchedgoals(entity this)
+{
+ vector org, m1, m2;
+ org = this.origin;
+ m1 = org + this.mins;
+ m2 = org + this.maxs;
+
+ if(this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT)
+ {
+ if(this.lastteleporttime>0)
+ if(time-this.lastteleporttime<(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL)?2:0.15)
+ {
+ if(this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_GOING)
+ if(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL && this.goalcurrent.owner==this)
+ {
+ this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_GOING;
+ this.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_REACHED;
+ }
+ navigation_poproute(this);
+ return;
+ }
+ }
+
+ // If for some reason the bot is closer to the next goal, pop the current one
+ if(this.goalstack01)
+ if(vlen2(this.goalcurrent.origin - this.origin) > vlen2(this.goalstack01.origin - this.origin))
+ if(checkpvs(this.origin + this.view_ofs, this.goalstack01))
+ if(tracewalk(this, this.origin, this.mins, this.maxs, (this.goalstack01.absmin + this.goalstack01.absmax) * 0.5, bot_navigation_movemode))
+ {
+ LOG_DEBUG("path optimized for ", this.netname, ", removed a goal from the queue");
+ navigation_poproute(this);
+ // TODO this may also be a nice idea to do "early" (e.g. by
+ // manipulating the vlen() comparisons) to shorten paths in
+ // general - this would make bots walk more "on rails" than
+ // "zigzagging" which they currently do with sufficiently
+ // random-like waypoints, and thus can make a nice bot
+ // personality property
+ }
+
+ // HACK: remove players/bots as goals, they can lead a bot to unexpected places (cliffs, lava, etc)
+ // TODO: rate waypoints near the targetted player at that moment, instead of the player itthis
+ if(IS_PLAYER(this.goalcurrent))
+ navigation_poproute(this);
+
+ // aid for detecting jump pads better (distance based check fails sometimes)
+ if(this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT && this.jumppadcount > 0 )
+ navigation_poproute(this);
+
+ // Loose goal touching check when running
+ if(this.aistatus & AI_STATUS_RUNNING)
+ if(this.speed >= autocvar_sv_maxspeed) // if -really- running
+ if(this.goalcurrent.classname=="waypoint")
+ {
+ if(vdist(this.origin - this.goalcurrent.origin, <, 150))
+ {
+ traceline(this.origin + this.view_ofs , this.goalcurrent.origin, true, NULL);
+ if(trace_fraction==1)
+ {
+ // Detect personal waypoints
+ if(this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_GOING)
+ if(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL && this.goalcurrent.owner==this)
+ {
+ this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_GOING;
+ this.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_REACHED;
+ }
+
+ navigation_poproute(this);
+ }
+ }
+ }
+
+ while (this.goalcurrent && boxesoverlap(m1, m2, this.goalcurrent.absmin, this.goalcurrent.absmax))
+ {
+ // Detect personal waypoints
+ if(this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_GOING)
+ if(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL && this.goalcurrent.owner==this)
+ {
+ this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_GOING;
+ this.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_REACHED;
+ }
+
+ navigation_poproute(this);
+ }
+}
+
+// begin a goal selection session (queries spawnfunc_waypoint network)
+void navigation_goalrating_start(entity this)
+{
+ if(this.aistatus & AI_STATUS_STUCK)
+ return;
+
+ this.navigation_jetpack_goal = NULL;
+ navigation_bestrating = -1;
+ this.navigation_hasgoals = false;
+ navigation_clearroute(this);
+ navigation_bestgoal = NULL;
+ navigation_markroutes(this, NULL);
+}
+
+// ends a goal selection session (updates goal stack to the best goal)
+void navigation_goalrating_end(entity this)
+{
+ if(this.aistatus & AI_STATUS_STUCK)
+ return;
+
+ navigation_routetogoal(this, navigation_bestgoal, this.origin);
+ LOG_DEBUG("best goal ", this.goalcurrent.classname);
+
+ // If the bot got stuck then try to reach the farthest waypoint
+ if (!this.navigation_hasgoals)
+ if (autocvar_bot_wander_enable)
+ {
+ if (!(this.aistatus & AI_STATUS_STUCK))
+ {
+ LOG_DEBUG(this.netname, " cannot walk to any goal");
+ this.aistatus |= AI_STATUS_STUCK;
+ }
+
+ this.navigation_hasgoals = false; // Reset this value
+ }
+}
+
+void botframe_updatedangerousobjects(float maxupdate)
+{
+ vector m1, m2, v, o;
+ float c, d, danger;
+ c = 0;
+ IL_EACH(g_waypoints, true,
+ {
+ danger = 0;
+ m1 = it.mins;
+ m2 = it.maxs;
+ FOREACH_ENTITY_FLOAT(bot_dodge, true,
+ {
+ v = it.origin;
+ v.x = bound(m1_x, v.x, m2_x);
+ v.y = bound(m1_y, v.y, m2_y);
+ v.z = bound(m1_z, v.z, m2_z);
+ o = (it.absmin + it.absmax) * 0.5;
+ d = it.bot_dodgerating - vlen(o - v);
+ if (d > 0)
+ {
+ traceline(o, v, true, NULL);
+ if (trace_fraction == 1)
+ danger = danger + d;
+ }
+ });
+ it.dmg = danger;
+ c = c + 1;
+ if (c >= maxupdate)
+ break;
+ });
+}
+
+void navigation_unstuck(entity this)
+{
+ float search_radius = 1000;
+
+ if (!autocvar_bot_wander_enable)
+ return;
+
+ if (!bot_waypoint_queue_owner)
+ {
+ LOG_DEBUG(this.netname, " sutck, taking over the waypoints queue");
+ bot_waypoint_queue_owner = this;
+ bot_waypoint_queue_bestgoal = NULL;
+ bot_waypoint_queue_bestgoalrating = 0;
+ }
+
+ if(bot_waypoint_queue_owner!=this)
+ return;
+
+ if (bot_waypoint_queue_goal)
+ {
+ // evaluate the next goal on the queue
+ float d = vlen(this.origin - bot_waypoint_queue_goal.origin);
+ LOG_DEBUG(this.netname, " evaluating ", bot_waypoint_queue_goal.classname, " with distance ", ftos(d));
+ if(tracewalk(bot_waypoint_queue_goal, this.origin, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), bot_waypoint_queue_goal.origin, bot_navigation_movemode))
+ {
+ if( d > bot_waypoint_queue_bestgoalrating)
+ {
+ bot_waypoint_queue_bestgoalrating = d;
+ bot_waypoint_queue_bestgoal = bot_waypoint_queue_goal;
+ }
+ }
+ bot_waypoint_queue_goal = bot_waypoint_queue_goal.bot_waypoint_queue_nextgoal;
+
+ if (!bot_waypoint_queue_goal)
+ {
+ if (bot_waypoint_queue_bestgoal)
+ {
+ LOG_DEBUG(this.netname, " stuck, reachable waypoint found, heading to it");
+ navigation_routetogoal(this, bot_waypoint_queue_bestgoal, this.origin);
+ this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+ this.aistatus &= ~AI_STATUS_STUCK;
+ }
+ else
+ {
+ LOG_DEBUG(this.netname, " stuck, cannot walk to any waypoint at all");
+ }
+
+ bot_waypoint_queue_owner = NULL;
+ }
+ }
+ else
+ {
+ if(bot_strategytoken!=this)
+ return;
+
+ // build a new queue
+ LOG_DEBUG(this.netname, " stuck, scanning reachable waypoints within ", ftos(search_radius)," qu");
+
+ entity first = NULL;
+
+ FOREACH_ENTITY_RADIUS(this.origin, search_radius, it.classname == "waypoint" && !(it.wpflags & WAYPOINTFLAG_GENERATED),
+ {
+ if(bot_waypoint_queue_goal)
+ bot_waypoint_queue_goal.bot_waypoint_queue_nextgoal = it;
+ else
+ first = it;
+
+ bot_waypoint_queue_goal = it;
+ bot_waypoint_queue_goal.bot_waypoint_queue_nextgoal = NULL;
+ });
+
+ if (first)
+ bot_waypoint_queue_goal = first;
+ else
+ {
+ LOG_DEBUG(this.netname, " stuck, cannot walk to any waypoint at all");
+ bot_waypoint_queue_owner = NULL;
+ }
+ }
+}
+
+// Support for debugging tracewalk visually
+
+void debugresetnodes()
+{
+ debuglastnode = '0 0 0';
+}
+
+void debugnode(entity this, vector node)
+{
+ if (!IS_PLAYER(this))
+ return;
+
+ if(debuglastnode=='0 0 0')
+ {
+ debuglastnode = node;
+ return;
+ }
+
+ te_lightning2(NULL, node, debuglastnode);
+ debuglastnode = node;
+}
+
+void debugnodestatus(vector position, float status)
+{
+ vector c;
+
+ switch (status)
+ {
+ case DEBUG_NODE_SUCCESS:
+ c = '0 15 0';
+ break;
+ case DEBUG_NODE_WARNING:
+ c = '15 15 0';
+ break;
+ case DEBUG_NODE_FAIL:
+ c = '15 0 0';
+ break;
+ default:
+ c = '15 15 15';
+ }
+
+ te_customflash(position, 40, 2, c);
+}
+
+// Support for debugging the goal stack visually
+
+.float goalcounter;
+.vector lastposition;
+
+// Debug the goal stack visually
+void debuggoalstack(entity this)
+{
+ entity goal;
+ vector org, go;
+
+ if(this.goalcounter==0)goal=this.goalcurrent;
+ else if(this.goalcounter==1)goal=this.goalstack01;
+ else if(this.goalcounter==2)goal=this.goalstack02;
+ else if(this.goalcounter==3)goal=this.goalstack03;
+ else if(this.goalcounter==4)goal=this.goalstack04;
+ else if(this.goalcounter==5)goal=this.goalstack05;
+ else if(this.goalcounter==6)goal=this.goalstack06;
+ else if(this.goalcounter==7)goal=this.goalstack07;
+ else if(this.goalcounter==8)goal=this.goalstack08;
+ else if(this.goalcounter==9)goal=this.goalstack09;
+ else if(this.goalcounter==10)goal=this.goalstack10;
+ else if(this.goalcounter==11)goal=this.goalstack11;
+ else if(this.goalcounter==12)goal=this.goalstack12;
+ else if(this.goalcounter==13)goal=this.goalstack13;
+ else if(this.goalcounter==14)goal=this.goalstack14;
+ else if(this.goalcounter==15)goal=this.goalstack15;
+ else if(this.goalcounter==16)goal=this.goalstack16;
+ else if(this.goalcounter==17)goal=this.goalstack17;
+ else if(this.goalcounter==18)goal=this.goalstack18;
+ else if(this.goalcounter==19)goal=this.goalstack19;
+ else if(this.goalcounter==20)goal=this.goalstack20;
+ else if(this.goalcounter==21)goal=this.goalstack21;
+ else if(this.goalcounter==22)goal=this.goalstack22;
+ else if(this.goalcounter==23)goal=this.goalstack23;
+ else if(this.goalcounter==24)goal=this.goalstack24;
+ else if(this.goalcounter==25)goal=this.goalstack25;
+ else if(this.goalcounter==26)goal=this.goalstack26;
+ else if(this.goalcounter==27)goal=this.goalstack27;
+ else if(this.goalcounter==28)goal=this.goalstack28;
+ else if(this.goalcounter==29)goal=this.goalstack29;
+ else if(this.goalcounter==30)goal=this.goalstack30;
+ else if(this.goalcounter==31)goal=this.goalstack31;
+ else goal=NULL;
+
+ if(goal==NULL)
+ {
+ this.goalcounter = 0;
+ this.lastposition='0 0 0';
+ return;
+ }
+
+ if(this.lastposition=='0 0 0')
+ org = this.origin;
+ else
+ org = this.lastposition;
+
+
+ go = ( goal.absmin + goal.absmax ) * 0.5;
+ te_lightning2(NULL, org, go);
+ this.lastposition = go;
+
+ this.goalcounter++;
+}
--- /dev/null
+#pragma once
+/*
+ * Globals and Fields
+ */
+
+float navigation_bestrating;
+float bot_navigation_movemode;
+float navigation_testtracewalk;
+
+vector jumpstepheightvec;
+vector stepheightvec;
+
+entity navigation_bestgoal;
+
+// stack of current goals (the last one of which may be an item or other
+// desirable object, the rest are typically waypoints to reach it)
+.entity goalcurrent, goalstack01, goalstack02, goalstack03;
+.entity goalstack04, goalstack05, goalstack06, goalstack07;
+.entity goalstack08, goalstack09, goalstack10, goalstack11;
+.entity goalstack12, goalstack13, goalstack14, goalstack15;
+.entity goalstack16, goalstack17, goalstack18, goalstack19;
+.entity goalstack20, goalstack21, goalstack22, goalstack23;
+.entity goalstack24, goalstack25, goalstack26, goalstack27;
+.entity goalstack28, goalstack29, goalstack30, goalstack31;
+.entity nearestwaypoint;
+
+.float nearestwaypointtimeout;
+.float navigation_hasgoals;
+.float lastteleporttime;
+
+.float blacklisted;
+
+.entity navigation_jetpack_goal;
+.vector navigation_jetpack_point;
+
+const float DEBUG_NODE_SUCCESS = 1;
+const float DEBUG_NODE_WARNING = 2;
+const float DEBUG_NODE_FAIL = 3;
+vector debuglastnode;
+
+entity bot_waypoint_queue_owner; // Owner of the temporary list of goals
+entity bot_waypoint_queue_goal; // Head of the temporary list of goals
+.entity bot_waypoint_queue_nextgoal;
+entity bot_waypoint_queue_bestgoal;
+float bot_waypoint_queue_bestgoalrating;
+
+/*
+ * Functions
+ */
+
+void debugresetnodes();
+void debugnode(entity this, vector node);
+void debugnodestatus(vector position, float status);
+
+void debuggoalstack(entity this);
+
+float tracewalk(entity e, vector start, vector m1, vector m2, vector end, float movemode);
+
+float navigation_markroutes_nearestwaypoints(entity this, float maxdist);
+float navigation_routetogoal(entity this, entity e, vector startposition);
+
+void navigation_clearroute(entity this);
+void navigation_pushroute(entity this, entity e);
+void navigation_poproute(entity this);
+void navigation_markroutes_checkwaypoint(entity w, entity wp, float cost2, vector p);
+void navigation_markroutes(entity this, entity fixed_source_waypoint);
+void navigation_markroutes_inverted(entity fixed_source_waypoint);
+void navigation_routerating(entity this, entity e, float f, float rangebias);
+void navigation_poptouchedgoals(entity this);
+void navigation_goalrating_start(entity this);
+void navigation_goalrating_end(entity this);
+void navigation_unstuck(entity this);
+
+void botframe_updatedangerousobjects(float maxupdate);
+
+entity navigation_findnearestwaypoint(entity ent, float walkfromwp);
+float navigation_waypoint_will_link(vector v, vector org, entity ent, float walkfromwp, float bestdist);
--- /dev/null
+#include "scripting.qh"
+
+#include "cvars.qh"
+
+#include <common/state.qh>
+#include <common/physics/player.qh>
+
+#include "bot.qh"
+
+.int state;
+
+.float bot_cmdqueuebuf_allocated;
+.float bot_cmdqueuebuf;
+.float bot_cmdqueuebuf_start;
+.float bot_cmdqueuebuf_end;
+
+void bot_clearqueue(entity bot)
+{
+ if(!bot.bot_cmdqueuebuf_allocated)
+ return;
+ buf_del(bot.bot_cmdqueuebuf);
+ bot.bot_cmdqueuebuf_allocated = false;
+ LOG_TRACE("bot ", bot.netname, " queue cleared");
+}
+
+void bot_queuecommand(entity bot, string cmdstring)
+{
+ if(!bot.bot_cmdqueuebuf_allocated)
+ {
+ bot.bot_cmdqueuebuf = buf_create();
+ bot.bot_cmdqueuebuf_allocated = true;
+ bot.bot_cmdqueuebuf_start = 0;
+ bot.bot_cmdqueuebuf_end = 0;
+ }
+
+ bufstr_set(bot.bot_cmdqueuebuf, bot.bot_cmdqueuebuf_end, cmdstring);
+
+ // if the command was a "sound" command, precache the sound NOW
+ // this prevents lagging!
+ {
+ float sp;
+ string parm;
+ string cmdstr;
+
+ sp = strstrofs(cmdstring, " ", 0);
+ if(sp >= 0)
+ {
+ parm = substring(cmdstring, sp + 1, -1);
+ cmdstr = substring(cmdstring, 0, sp);
+ if(cmdstr == "sound")
+ {
+ // find the LAST word
+ for (;;)
+ {
+ sp = strstrofs(parm, " ", 0);
+ if(sp < 0)
+ break;
+ parm = substring(parm, sp + 1, -1);
+ }
+ precache_sound(parm);
+ }
+ }
+ }
+
+ bot.bot_cmdqueuebuf_end += 1;
+}
+
+void bot_dequeuecommand(entity bot, float idx)
+{
+ if(!bot.bot_cmdqueuebuf_allocated)
+ error("dequeuecommand but no queue allocated");
+ if(idx < bot.bot_cmdqueuebuf_start)
+ error("dequeueing a command in the past");
+ if(idx >= bot.bot_cmdqueuebuf_end)
+ error("dequeueing a command in the future");
+ bufstr_set(bot.bot_cmdqueuebuf, idx, "");
+ if(idx == bot.bot_cmdqueuebuf_start)
+ bot.bot_cmdqueuebuf_start += 1;
+ if(bot.bot_cmdqueuebuf_start >= bot.bot_cmdqueuebuf_end)
+ bot_clearqueue(bot);
+}
+
+string bot_readcommand(entity bot, float idx)
+{
+ if(!bot.bot_cmdqueuebuf_allocated)
+ error("readcommand but no queue allocated");
+ if(idx < bot.bot_cmdqueuebuf_start)
+ error("reading a command in the past");
+ if(idx >= bot.bot_cmdqueuebuf_end)
+ error("reading a command in the future");
+ return bufstr_get(bot.bot_cmdqueuebuf, idx);
+}
+
+bool bot_havecommand(entity this, int idx)
+{
+ if(!this.bot_cmdqueuebuf_allocated)
+ return false;
+ if(idx < this.bot_cmdqueuebuf_start)
+ return false;
+ if(idx >= this.bot_cmdqueuebuf_end)
+ return false;
+ return true;
+}
+
+const int MAX_BOT_PLACES = 4;
+.float bot_places_count;
+.entity bot_places[MAX_BOT_PLACES];
+.string bot_placenames[MAX_BOT_PLACES];
+entity bot_getplace(entity this, string placename)
+{
+ entity e;
+ if(substring(placename, 0, 1) == "@")
+ {
+ int i, p;
+ placename = substring(placename, 1, -1);
+ string s, s2;
+ for(i = 0; i < this.bot_places_count; ++i)
+ if(this.(bot_placenames[i]) == placename)
+ return this.(bot_places[i]);
+ // now: i == this.bot_places_count
+ s = s2 = cvar_string(placename);
+ p = strstrofs(s2, " ", 0);
+ if(p >= 0)
+ {
+ s = substring(s2, 0, p);
+ //print("places: ", placename, " -> ", cvar_string(placename), "\n");
+ cvar_set(placename, strcat(substring(s2, p+1, -1), " ", s));
+ //print("places: ", placename, " := ", cvar_string(placename), "\n");
+ }
+ e = find(NULL, targetname, s);
+ if(!e)
+ LOG_INFO("invalid place ", s, "\n");
+ if(i < MAX_BOT_PLACES)
+ {
+ this.(bot_placenames[i]) = strzone(placename);
+ this.(bot_places[i]) = e;
+ this.bot_places_count += 1;
+ }
+ return e;
+ }
+ else
+ {
+ e = find(NULL, targetname, placename);
+ if(!e)
+ LOG_INFO("invalid place ", placename, "\n");
+ return e;
+ }
+}
+
+
+// Initialize global commands list
+// NOTE: New commands should be initialized here
+void bot_commands_init()
+{
+ bot_cmd_string[BOT_CMD_NULL] = "";
+ bot_cmd_parm_type[BOT_CMD_NULL] = BOT_CMD_PARAMETER_NONE;
+
+ bot_cmd_string[BOT_CMD_PAUSE] = "pause";
+ bot_cmd_parm_type[BOT_CMD_PAUSE] = BOT_CMD_PARAMETER_NONE;
+
+ bot_cmd_string[BOT_CMD_CONTINUE] = "continue";
+ bot_cmd_parm_type[BOT_CMD_CONTINUE] = BOT_CMD_PARAMETER_NONE;
+
+ bot_cmd_string[BOT_CMD_WAIT] = "wait";
+ bot_cmd_parm_type[BOT_CMD_WAIT] = BOT_CMD_PARAMETER_FLOAT;
+
+ bot_cmd_string[BOT_CMD_TURN] = "turn";
+ bot_cmd_parm_type[BOT_CMD_TURN] = BOT_CMD_PARAMETER_FLOAT;
+
+ bot_cmd_string[BOT_CMD_MOVETO] = "moveto";
+ bot_cmd_parm_type[BOT_CMD_MOVETO] = BOT_CMD_PARAMETER_VECTOR;
+
+ bot_cmd_string[BOT_CMD_MOVETOTARGET] = "movetotarget";
+ bot_cmd_parm_type[BOT_CMD_MOVETOTARGET] = BOT_CMD_PARAMETER_STRING;
+
+ bot_cmd_string[BOT_CMD_RESETGOAL] = "resetgoal";
+ bot_cmd_parm_type[BOT_CMD_RESETGOAL] = BOT_CMD_PARAMETER_NONE;
+
+ bot_cmd_string[BOT_CMD_CC] = "cc";
+ bot_cmd_parm_type[BOT_CMD_CC] = BOT_CMD_PARAMETER_STRING;
+
+ bot_cmd_string[BOT_CMD_IF] = "if";
+ bot_cmd_parm_type[BOT_CMD_IF] = BOT_CMD_PARAMETER_STRING;
+
+ bot_cmd_string[BOT_CMD_ELSE] = "else";
+ bot_cmd_parm_type[BOT_CMD_ELSE] = BOT_CMD_PARAMETER_NONE;
+
+ bot_cmd_string[BOT_CMD_FI] = "fi";
+ bot_cmd_parm_type[BOT_CMD_FI] = BOT_CMD_PARAMETER_NONE;
+
+ bot_cmd_string[BOT_CMD_RESETAIM] = "resetaim";
+ bot_cmd_parm_type[BOT_CMD_RESETAIM] = BOT_CMD_PARAMETER_NONE;
+
+ bot_cmd_string[BOT_CMD_AIM] = "aim";
+ bot_cmd_parm_type[BOT_CMD_AIM] = BOT_CMD_PARAMETER_STRING;
+
+ bot_cmd_string[BOT_CMD_AIMTARGET] = "aimtarget";
+ bot_cmd_parm_type[BOT_CMD_AIMTARGET] = BOT_CMD_PARAMETER_STRING;
+
+ bot_cmd_string[BOT_CMD_PRESSKEY] = "presskey";
+ bot_cmd_parm_type[BOT_CMD_PRESSKEY] = BOT_CMD_PARAMETER_STRING;
+
+ bot_cmd_string[BOT_CMD_RELEASEKEY] = "releasekey";
+ bot_cmd_parm_type[BOT_CMD_RELEASEKEY] = BOT_CMD_PARAMETER_STRING;
+
+ bot_cmd_string[BOT_CMD_SELECTWEAPON] = "selectweapon";
+ bot_cmd_parm_type[BOT_CMD_SELECTWEAPON] = BOT_CMD_PARAMETER_FLOAT;
+
+ bot_cmd_string[BOT_CMD_IMPULSE] = "impulse";
+ bot_cmd_parm_type[BOT_CMD_IMPULSE] = BOT_CMD_PARAMETER_FLOAT;
+
+ bot_cmd_string[BOT_CMD_WAIT_UNTIL] = "wait_until";
+ bot_cmd_parm_type[BOT_CMD_WAIT_UNTIL] = BOT_CMD_PARAMETER_FLOAT;
+
+ bot_cmd_string[BOT_CMD_BARRIER] = "barrier";
+ bot_cmd_parm_type[BOT_CMD_BARRIER] = BOT_CMD_PARAMETER_NONE;
+
+ bot_cmd_string[BOT_CMD_CONSOLE] = "console";
+ bot_cmd_parm_type[BOT_CMD_CONSOLE] = BOT_CMD_PARAMETER_STRING;
+
+ bot_cmd_string[BOT_CMD_SOUND] = "sound";
+ bot_cmd_parm_type[BOT_CMD_SOUND] = BOT_CMD_PARAMETER_STRING;
+
+ bot_cmd_string[BOT_CMD_DEBUG_ASSERT_CANFIRE] = "debug_assert_canfire";
+ bot_cmd_parm_type[BOT_CMD_DEBUG_ASSERT_CANFIRE] = BOT_CMD_PARAMETER_FLOAT;
+
+ bot_cmds_initialized = true;
+}
+
+// Returns first bot with matching name
+entity find_bot_by_name(string name)
+{
+ entity bot;
+
+ bot = findchainflags(flags, FL_CLIENT);
+ while (bot)
+ {
+ if(IS_BOT_CLIENT(bot))
+ if(bot.netname==name)
+ return bot;
+
+ bot = bot.chain;
+ }
+
+ return NULL;
+}
+
+// Returns a bot by number on list
+entity find_bot_by_number(float number)
+{
+ entity bot;
+ float c = 0;
+
+ if(!number)
+ return NULL;
+
+ bot = findchainflags(flags, FL_CLIENT); // TODO: doesn't findchainflags loop backwards through entities?
+ while (bot)
+ {
+ if(IS_BOT_CLIENT(bot))
+ {
+ if(++c==number)
+ return bot;
+ }
+ bot = bot.chain;
+ }
+
+ return NULL;
+}
+
+float bot_decodecommand(string cmdstring)
+{
+ float cmd_parm_type;
+ float sp;
+ string parm;
+
+ sp = strstrofs(cmdstring, " ", 0);
+ if(sp < 0)
+ {
+ parm = "";
+ }
+ else
+ {
+ parm = substring(cmdstring, sp + 1, -1);
+ cmdstring = substring(cmdstring, 0, sp);
+ }
+
+ if(!bot_cmds_initialized)
+ bot_commands_init();
+
+ int i;
+ for(i=1;i<BOT_CMD_COUNTER;++i)
+ {
+ if(bot_cmd_string[i]!=cmdstring)
+ continue;
+
+ cmd_parm_type = bot_cmd_parm_type[i];
+
+ if(cmd_parm_type!=BOT_CMD_PARAMETER_NONE&&parm=="")
+ {
+ LOG_INFO("ERROR: A parameter is required for this command\n");
+ return 0;
+ }
+
+ // Load command into queue
+ bot_cmd.bot_cmd_type = i;
+
+ // Attach parameter
+ switch(cmd_parm_type)
+ {
+ case BOT_CMD_PARAMETER_FLOAT:
+ bot_cmd.bot_cmd_parm_float = stof(parm);
+ break;
+ case BOT_CMD_PARAMETER_STRING:
+ if(bot_cmd.bot_cmd_parm_string)
+ strunzone(bot_cmd.bot_cmd_parm_string);
+ bot_cmd.bot_cmd_parm_string = strzone(parm);
+ break;
+ case BOT_CMD_PARAMETER_VECTOR:
+ bot_cmd.bot_cmd_parm_vector = stov(parm);
+ break;
+ default:
+ break;
+ }
+ return 1;
+ }
+ LOG_INFO("ERROR: No such command '", cmdstring, "'\n");
+ return 0;
+}
+
+void bot_cmdhelp(string scmd)
+{
+ int i, ntype;
+ string stype;
+
+ if(!bot_cmds_initialized)
+ bot_commands_init();
+
+ for(i=1;i<BOT_CMD_COUNTER;++i)
+ {
+ if(bot_cmd_string[i]!=scmd)
+ continue;
+
+ ntype = bot_cmd_parm_type[i];
+
+ switch(ntype)
+ {
+ case BOT_CMD_PARAMETER_FLOAT:
+ stype = "float number";
+ break;
+ case BOT_CMD_PARAMETER_STRING:
+ stype = "string";
+ break;
+ case BOT_CMD_PARAMETER_VECTOR:
+ stype = "vector";
+ break;
+ default:
+ stype = "none";
+ break;
+ }
+
+ LOG_INFO(strcat("Command: ",bot_cmd_string[i],"\nParameter: <",stype,"> \n"));
+
+ LOG_INFO("Description: ");
+ switch(i)
+ {
+ case BOT_CMD_PAUSE:
+ LOG_INFO("Stops the bot completely. Any command other than 'continue' will be ignored.");
+ break;
+ case BOT_CMD_CONTINUE:
+ LOG_INFO("Disable paused status");
+ break;
+ case BOT_CMD_WAIT:
+ LOG_INFO("Pause command parsing and bot ai for N seconds. Pressed key will remain pressed");
+ break;
+ case BOT_CMD_WAIT_UNTIL:
+ LOG_INFO("Pause command parsing and bot ai until time is N from the last barrier. Pressed key will remain pressed");
+ break;
+ case BOT_CMD_BARRIER:
+ LOG_INFO("Waits till all bots that have a command queue reach this command. Pressed key will remain pressed");
+ break;
+ case BOT_CMD_TURN:
+ LOG_INFO("Look to the right or left N degrees. For turning to the left use positive numbers.");
+ break;
+ case BOT_CMD_MOVETO:
+ LOG_INFO("Walk to an specific coordinate on the map. Usage: moveto \"x y z\"");
+ break;
+ case BOT_CMD_MOVETOTARGET:
+ LOG_INFO("Walk to the specific target on the map");
+ break;
+ case BOT_CMD_RESETGOAL:
+ LOG_INFO("Resets the goal stack");
+ break;
+ case BOT_CMD_CC:
+ LOG_INFO("Execute client command. Examples: cc \"say something\"; cc god; cc \"name newnickname\"; cc kill;");
+ break;
+ case BOT_CMD_IF:
+ LOG_INFO("Perform simple conditional execution.\n");
+ LOG_INFO("Syntax: \n");
+ LOG_INFO(" sv_cmd .. if \"condition\"\n");
+ LOG_INFO(" sv_cmd .. <instruction if true>\n");
+ LOG_INFO(" sv_cmd .. <instruction if true>\n");
+ LOG_INFO(" sv_cmd .. else\n");
+ LOG_INFO(" sv_cmd .. <instruction if false>\n");
+ LOG_INFO(" sv_cmd .. <instruction if false>\n");
+ LOG_INFO(" sv_cmd .. fi\n");
+ LOG_INFO("Conditions: a=b, a>b, a<b, a\t\t(spaces not allowed)\n");
+ LOG_INFO(" Values in conditions can be numbers, cvars in the form cvar.cvar_string or special fields\n");
+ LOG_INFO("Fields: health, speed, flagcarrier\n");
+ LOG_INFO("Examples: if health>50; if health>cvar.g_balance_laser_primary_damage; if flagcarrier;");
+ break;
+ case BOT_CMD_RESETAIM:
+ LOG_INFO("Points the aim to the coordinates x,y 0,0");
+ break;
+ case BOT_CMD_AIM:
+ LOG_INFO("Move the aim x/y (horizontal/vertical) degrees relatives to the bot\n");
+ LOG_INFO("There is a 3rd optional parameter telling in how many seconds the aim has to reach the new position\n");
+ LOG_INFO("Examples: aim \"90 0\" // Turn 90 degrees inmediately (positive numbers move to the left/up)\n");
+ LOG_INFO(" aim \"0 90 2\" // Will gradually look to the sky in the next two seconds");
+ break;
+ case BOT_CMD_AIMTARGET:
+ LOG_INFO("Points the aim to given target");
+ break;
+ case BOT_CMD_PRESSKEY:
+ LOG_INFO("Press one of the following keys: forward, backward, left, right, jump, crouch, attack1, attack2, use\n");
+ LOG_INFO("Multiple keys can be pressed at time (with many presskey calls) and it will remain pressed until the command \"releasekey\" is called");
+ LOG_INFO("Note: The script will not return the control to the bot ai until all keys are released");
+ break;
+ case BOT_CMD_RELEASEKEY:
+ LOG_INFO("Release previoulsy used keys. Use the parameter \"all\" to release all keys");
+ break;
+ case BOT_CMD_SOUND:
+ LOG_INFO("play sound file at bot location");
+ break;
+ case BOT_CMD_DEBUG_ASSERT_CANFIRE:
+ LOG_INFO("verify the state of the weapon entity");
+ break;
+ default:
+ LOG_INFO("This command has no description yet.");
+ break;
+ }
+ LOG_INFO("\n");
+ }
+}
+
+void bot_list_commands()
+{
+ int i;
+ string ptype;
+
+ if(!bot_cmds_initialized)
+ bot_commands_init();
+
+ LOG_INFO("List of all available commands:\n");
+ LOG_INFO(" Command - Parameter Type\n");
+
+ for(i=1;i<BOT_CMD_COUNTER;++i)
+ {
+ switch(bot_cmd_parm_type[i])
+ {
+ case BOT_CMD_PARAMETER_FLOAT:
+ ptype = "float number";
+ break;
+ case BOT_CMD_PARAMETER_STRING:
+ ptype = "string";
+ break;
+ case BOT_CMD_PARAMETER_VECTOR:
+ ptype = "vector";
+ break;
+ default:
+ ptype = "none";
+ break;
+ }
+ LOG_INFO(strcat(" ",bot_cmd_string[i]," - <",ptype,"> \n"));
+ }
+}
+
+// Commands code
+.int bot_exec_status;
+
+float bot_cmd_cc(entity this)
+{
+ SV_ParseClientCommand(this, bot_cmd.bot_cmd_parm_string);
+ return CMD_STATUS_FINISHED;
+}
+
+float bot_cmd_impulse(entity this)
+{
+ this.impulse = bot_cmd.bot_cmd_parm_float;
+ return CMD_STATUS_FINISHED;
+}
+
+float bot_cmd_continue(entity this)
+{
+ this.bot_exec_status &= ~BOT_EXEC_STATUS_PAUSED;
+ return CMD_STATUS_FINISHED;
+}
+
+.float bot_cmd_wait_time;
+float bot_cmd_wait(entity this)
+{
+ if(this.bot_exec_status & BOT_EXEC_STATUS_WAITING)
+ {
+ if(time>=this.bot_cmd_wait_time)
+ {
+ this.bot_exec_status &= ~BOT_EXEC_STATUS_WAITING;
+ return CMD_STATUS_FINISHED;
+ }
+ else
+ return CMD_STATUS_EXECUTING;
+ }
+
+ this.bot_cmd_wait_time = time + bot_cmd.bot_cmd_parm_float;
+ this.bot_exec_status |= BOT_EXEC_STATUS_WAITING;
+ return CMD_STATUS_EXECUTING;
+}
+
+float bot_cmd_wait_until(entity this)
+{
+ if(time < bot_cmd.bot_cmd_parm_float + bot_barriertime)
+ {
+ this.bot_exec_status |= BOT_EXEC_STATUS_WAITING;
+ return CMD_STATUS_EXECUTING;
+ }
+ this.bot_exec_status &= ~BOT_EXEC_STATUS_WAITING;
+ return CMD_STATUS_FINISHED;
+}
+
+float bot_cmd_barrier(entity this)
+{
+ // 0 = no barrier, 1 = waiting, 2 = waiting finished
+
+ if(this.bot_barrier == 0) // initialization
+ {
+ this.bot_barrier = 1;
+
+ //this.colormod = '4 4 0';
+ }
+
+ if(this.bot_barrier == 1) // find other bots
+ {
+ FOREACH_CLIENT(it.isbot, LAMBDA(
+ if(it.bot_cmdqueuebuf_allocated)
+ if(it.bot_barrier != 1)
+ return CMD_STATUS_EXECUTING; // not all are at the barrier yet
+ ));
+
+ // all bots hit the barrier!
+
+ // acknowledge barrier
+ FOREACH_CLIENT(it.isbot, LAMBDA(it.bot_barrier = 2));
+
+ bot_barriertime = time;
+ }
+
+ // if we get here, the barrier is finished
+ // so end it...
+ this.bot_barrier = 0;
+ //this.colormod = '0 0 0';
+
+ return CMD_STATUS_FINISHED;
+}
+
+float bot_cmd_turn(entity this)
+{
+ this.v_angle_y = this.v_angle.y + bot_cmd.bot_cmd_parm_float;
+ this.v_angle_y = this.v_angle.y - floor(this.v_angle.y / 360) * 360;
+ return CMD_STATUS_FINISHED;
+}
+
+float bot_cmd_select_weapon(entity this)
+{
+ float id = bot_cmd.bot_cmd_parm_float;
+
+ if(id < WEP_FIRST || id > WEP_LAST)
+ return CMD_STATUS_ERROR;
+
+ if(client_hasweapon(this, Weapons_from(id), true, false))
+ PS(this).m_switchweapon = Weapons_from(id);
+ else
+ return CMD_STATUS_ERROR;
+
+ return CMD_STATUS_FINISHED;
+}
+
+.int bot_cmd_condition_status;
+
+const int CMD_CONDITION_NONE = 0;
+const int CMD_CONDITION_true = 1;
+const int CMD_CONDITION_false = 2;
+const int CMD_CONDITION_true_BLOCK = 4;
+const int CMD_CONDITION_false_BLOCK = 8;
+
+float bot_cmd_eval(entity this, string expr)
+{
+ // Search for numbers
+ if(strstrofs("0123456789", substring(expr, 0, 1), 0) >= 0)
+ {
+ return stof(expr);
+ }
+
+ // Search for cvars
+ if(substring(expr, 0, 5)=="cvar.")
+ {
+ return cvar(substring(expr, 5, strlen(expr)));
+ }
+
+ // Search for fields
+ switch(expr)
+ {
+ case "health":
+ return this.health;
+ case "speed":
+ return vlen(this.velocity);
+ case "flagcarrier":
+ return ((this.flagcarried!=NULL));
+ }
+
+ LOG_INFO(strcat("ERROR: Unable to convert the expression '",expr,"' into a numeric value\n"));
+ return 0;
+}
+
+float bot_cmd_if(entity this)
+{
+ string expr, val_a, val_b;
+ float cmpofs;
+
+ if(this.bot_cmd_condition_status != CMD_CONDITION_NONE)
+ {
+ // Only one "if" block is allowed at time
+ LOG_INFO("ERROR: Only one conditional block can be processed at time");
+ bot_clearqueue(this);
+ return CMD_STATUS_ERROR;
+ }
+
+ this.bot_cmd_condition_status |= CMD_CONDITION_true_BLOCK;
+
+ // search for operators
+ expr = bot_cmd.bot_cmd_parm_string;
+
+ cmpofs = strstrofs(expr,"=",0);
+
+ if(cmpofs>0)
+ {
+ val_a = substring(expr,0,cmpofs);
+ val_b = substring(expr,cmpofs+1,strlen(expr));
+
+ if(bot_cmd_eval(this, val_a)==bot_cmd_eval(this, val_b))
+ this.bot_cmd_condition_status |= CMD_CONDITION_true;
+ else
+ this.bot_cmd_condition_status |= CMD_CONDITION_false;
+
+ return CMD_STATUS_FINISHED;
+ }
+
+ cmpofs = strstrofs(expr,">",0);
+
+ if(cmpofs>0)
+ {
+ val_a = substring(expr,0,cmpofs);
+ val_b = substring(expr,cmpofs+1,strlen(expr));
+
+ if(bot_cmd_eval(this, val_a)>bot_cmd_eval(this, val_b))
+ this.bot_cmd_condition_status |= CMD_CONDITION_true;
+ else
+ this.bot_cmd_condition_status |= CMD_CONDITION_false;
+
+ return CMD_STATUS_FINISHED;
+ }
+
+ cmpofs = strstrofs(expr,"<",0);
+
+ if(cmpofs>0)
+ {
+ val_a = substring(expr,0,cmpofs);
+ val_b = substring(expr,cmpofs+1,strlen(expr));
+
+ if(bot_cmd_eval(this, val_a)<bot_cmd_eval(this, val_b))
+ this.bot_cmd_condition_status |= CMD_CONDITION_true;
+ else
+ this.bot_cmd_condition_status |= CMD_CONDITION_false;
+
+ return CMD_STATUS_FINISHED;
+ }
+
+ if(bot_cmd_eval(this, expr))
+ this.bot_cmd_condition_status |= CMD_CONDITION_true;
+ else
+ this.bot_cmd_condition_status |= CMD_CONDITION_false;
+
+ return CMD_STATUS_FINISHED;
+}
+
+float bot_cmd_else(entity this)
+{
+ this.bot_cmd_condition_status &= ~CMD_CONDITION_true_BLOCK;
+ this.bot_cmd_condition_status |= CMD_CONDITION_false_BLOCK;
+ return CMD_STATUS_FINISHED;
+}
+
+float bot_cmd_fi(entity this)
+{
+ this.bot_cmd_condition_status = CMD_CONDITION_NONE;
+ return CMD_STATUS_FINISHED;
+}
+
+float bot_cmd_resetaim(entity this)
+{
+ this.v_angle = '0 0 0';
+ return CMD_STATUS_FINISHED;
+}
+
+.float bot_cmd_aim_begintime;
+.float bot_cmd_aim_endtime;
+.vector bot_cmd_aim_begin;
+.vector bot_cmd_aim_end;
+
+float bot_cmd_aim(entity this)
+{
+ // Current direction
+ if(this.bot_cmd_aim_endtime)
+ {
+ float progress;
+
+ progress = min(1 - (this.bot_cmd_aim_endtime - time) / (this.bot_cmd_aim_endtime - this.bot_cmd_aim_begintime),1);
+ this.v_angle = this.bot_cmd_aim_begin + ((this.bot_cmd_aim_end - this.bot_cmd_aim_begin) * progress);
+
+ if(time>=this.bot_cmd_aim_endtime)
+ {
+ this.bot_cmd_aim_endtime = 0;
+ return CMD_STATUS_FINISHED;
+ }
+ else
+ return CMD_STATUS_EXECUTING;
+ }
+
+ // New aiming direction
+ string parms;
+ float tokens, step;
+
+ parms = bot_cmd.bot_cmd_parm_string;
+
+ tokens = tokenizebyseparator(parms, " ");
+
+ if(tokens<2||tokens>3)
+ return CMD_STATUS_ERROR;
+
+ step = (tokens == 3) ? stof(argv(2)) : 0;
+
+ if(step == 0)
+ {
+ this.v_angle_x -= stof(argv(1));
+ this.v_angle_y += stof(argv(0));
+ return CMD_STATUS_FINISHED;
+ }
+
+ this.bot_cmd_aim_begin = this.v_angle;
+
+ this.bot_cmd_aim_end_x = this.v_angle.x - stof(argv(1));
+ this.bot_cmd_aim_end_y = this.v_angle.y + stof(argv(0));
+ this.bot_cmd_aim_end_z = 0;
+
+ this.bot_cmd_aim_begintime = time;
+ this.bot_cmd_aim_endtime = time + step;
+
+ return CMD_STATUS_EXECUTING;
+}
+
+float bot_cmd_aimtarget(entity this)
+{
+ if(this.bot_cmd_aim_endtime)
+ {
+ return bot_cmd_aim(this);
+ }
+
+ entity e;
+ string parms;
+ vector v;
+ float tokens, step;
+
+ parms = bot_cmd.bot_cmd_parm_string;
+
+ tokens = tokenizebyseparator(parms, " ");
+
+ e = bot_getplace(this, argv(0));
+ if(!e)
+ return CMD_STATUS_ERROR;
+
+ v = e.origin + (e.mins + e.maxs) * 0.5;
+
+ if(tokens==1)
+ {
+ this.v_angle = vectoangles(v - (this.origin + this.view_ofs));
+ this.v_angle_x = -this.v_angle.x;
+ return CMD_STATUS_FINISHED;
+ }
+
+ if(tokens<1||tokens>2)
+ return CMD_STATUS_ERROR;
+
+ step = stof(argv(1));
+
+ this.bot_cmd_aim_begin = this.v_angle;
+ this.bot_cmd_aim_end = vectoangles(v - (this.origin + this.view_ofs));
+ this.bot_cmd_aim_end_x = -this.bot_cmd_aim_end.x;
+
+ this.bot_cmd_aim_begintime = time;
+ this.bot_cmd_aim_endtime = time + step;
+
+ return CMD_STATUS_EXECUTING;
+}
+
+.int bot_cmd_keys;
+
+const int BOT_CMD_KEY_NONE = 0;
+const int BOT_CMD_KEY_FORWARD = BIT(0);
+const int BOT_CMD_KEY_BACKWARD = BIT(1);
+const int BOT_CMD_KEY_RIGHT = BIT(2);
+const int BOT_CMD_KEY_LEFT = BIT(3);
+const int BOT_CMD_KEY_JUMP = BIT(4);
+const int BOT_CMD_KEY_ATTACK1 = BIT(5);
+const int BOT_CMD_KEY_ATTACK2 = BIT(6);
+const int BOT_CMD_KEY_USE = BIT(7);
+const int BOT_CMD_KEY_HOOK = BIT(8);
+const int BOT_CMD_KEY_CROUCH = BIT(9);
+const int BOT_CMD_KEY_CHAT = BIT(10);
+
+bool bot_presskeys(entity this)
+{
+ this.movement = '0 0 0';
+ PHYS_INPUT_BUTTON_JUMP(this) = false;
+ PHYS_INPUT_BUTTON_CROUCH(this) = false;
+ PHYS_INPUT_BUTTON_ATCK(this) = false;
+ PHYS_INPUT_BUTTON_ATCK2(this) = false;
+ PHYS_INPUT_BUTTON_USE(this) = false;
+ PHYS_INPUT_BUTTON_HOOK(this) = false;
+ PHYS_INPUT_BUTTON_CHAT(this) = false;
+
+ if(this.bot_cmd_keys == BOT_CMD_KEY_NONE)
+ return false;
+
+ if(this.bot_cmd_keys & BOT_CMD_KEY_FORWARD)
+ this.movement_x = autocvar_sv_maxspeed;
+ else if(this.bot_cmd_keys & BOT_CMD_KEY_BACKWARD)
+ this.movement_x = -autocvar_sv_maxspeed;
+
+ if(this.bot_cmd_keys & BOT_CMD_KEY_RIGHT)
+ this.movement_y = autocvar_sv_maxspeed;
+ else if(this.bot_cmd_keys & BOT_CMD_KEY_LEFT)
+ this.movement_y = -autocvar_sv_maxspeed;
+
+ if(this.bot_cmd_keys & BOT_CMD_KEY_JUMP)
+ PHYS_INPUT_BUTTON_JUMP(this) = true;
+
+ if(this.bot_cmd_keys & BOT_CMD_KEY_CROUCH)
+ PHYS_INPUT_BUTTON_CROUCH(this) = true;
+
+ if(this.bot_cmd_keys & BOT_CMD_KEY_ATTACK1)
+ PHYS_INPUT_BUTTON_ATCK(this) = true;
+
+ if(this.bot_cmd_keys & BOT_CMD_KEY_ATTACK2)
+ PHYS_INPUT_BUTTON_ATCK2(this) = true;
+
+ if(this.bot_cmd_keys & BOT_CMD_KEY_USE)
+ PHYS_INPUT_BUTTON_USE(this) = true;
+
+ if(this.bot_cmd_keys & BOT_CMD_KEY_HOOK)
+ PHYS_INPUT_BUTTON_HOOK(this) = true;
+
+ if(this.bot_cmd_keys & BOT_CMD_KEY_CHAT)
+ PHYS_INPUT_BUTTON_CHAT(this) = true;
+
+ return true;
+}
+
+
+float bot_cmd_keypress_handler(entity this, string key, float enabled)
+{
+ switch(key)
+ {
+ case "all":
+ if(enabled)
+ this.bot_cmd_keys = power2of(20) - 1; // >:)
+ else
+ this.bot_cmd_keys = BOT_CMD_KEY_NONE;
+ case "forward":
+ if(enabled)
+ {
+ this.bot_cmd_keys |= BOT_CMD_KEY_FORWARD;
+ this.bot_cmd_keys &= ~BOT_CMD_KEY_BACKWARD;
+ }
+ else
+ this.bot_cmd_keys &= ~BOT_CMD_KEY_FORWARD;
+ break;
+ case "backward":
+ if(enabled)
+ {
+ this.bot_cmd_keys |= BOT_CMD_KEY_BACKWARD;
+ this.bot_cmd_keys &= ~BOT_CMD_KEY_FORWARD;
+ }
+ else
+ this.bot_cmd_keys &= ~BOT_CMD_KEY_BACKWARD;
+ break;
+ case "left":
+ if(enabled)
+ {
+ this.bot_cmd_keys |= BOT_CMD_KEY_LEFT;
+ this.bot_cmd_keys &= ~BOT_CMD_KEY_RIGHT;
+ }
+ else
+ this.bot_cmd_keys &= ~BOT_CMD_KEY_LEFT;
+ break;
+ case "right":
+ if(enabled)
+ {
+ this.bot_cmd_keys |= BOT_CMD_KEY_RIGHT;
+ this.bot_cmd_keys &= ~BOT_CMD_KEY_LEFT;
+ }
+ else
+ this.bot_cmd_keys &= ~BOT_CMD_KEY_RIGHT;
+ break;
+ case "jump":
+ if(enabled)
+ this.bot_cmd_keys |= BOT_CMD_KEY_JUMP;
+ else
+ this.bot_cmd_keys &= ~BOT_CMD_KEY_JUMP;
+ break;
+ case "crouch":
+ if(enabled)
+ this.bot_cmd_keys |= BOT_CMD_KEY_CROUCH;
+ else
+ this.bot_cmd_keys &= ~BOT_CMD_KEY_CROUCH;
+ break;
+ case "attack1":
+ if(enabled)
+ this.bot_cmd_keys |= BOT_CMD_KEY_ATTACK1;
+ else
+ this.bot_cmd_keys &= ~BOT_CMD_KEY_ATTACK1;
+ break;
+ case "attack2":
+ if(enabled)
+ this.bot_cmd_keys |= BOT_CMD_KEY_ATTACK2;
+ else
+ this.bot_cmd_keys &= ~BOT_CMD_KEY_ATTACK2;
+ break;
+ case "use":
+ if(enabled)
+ this.bot_cmd_keys |= BOT_CMD_KEY_USE;
+ else
+ this.bot_cmd_keys &= ~BOT_CMD_KEY_USE;
+ break;
+ case "hook":
+ if(enabled)
+ this.bot_cmd_keys |= BOT_CMD_KEY_HOOK;
+ else
+ this.bot_cmd_keys &= ~BOT_CMD_KEY_HOOK;
+ break;
+ case "chat":
+ if(enabled)
+ this.bot_cmd_keys |= BOT_CMD_KEY_CHAT;
+ else
+ this.bot_cmd_keys &= ~BOT_CMD_KEY_CHAT;
+ break;
+ default:
+ break;
+ }
+
+ return CMD_STATUS_FINISHED;
+}
+
+float bot_cmd_presskey(entity this)
+{
+ string key;
+
+ key = bot_cmd.bot_cmd_parm_string;
+
+ bot_cmd_keypress_handler(this, key,true);
+
+ return CMD_STATUS_FINISHED;
+}
+
+float bot_cmd_releasekey(entity this)
+{
+ string key;
+
+ key = bot_cmd.bot_cmd_parm_string;
+
+ return bot_cmd_keypress_handler(this, key,false);
+}
+
+float bot_cmd_pause(entity this)
+{
+ PHYS_INPUT_BUTTON_DRAG(this) = false;
+ PHYS_INPUT_BUTTON_USE(this) = false;
+ PHYS_INPUT_BUTTON_ATCK(this) = false;
+ PHYS_INPUT_BUTTON_JUMP(this) = false;
+ PHYS_INPUT_BUTTON_HOOK(this) = false;
+ PHYS_INPUT_BUTTON_CHAT(this) = false;
+ PHYS_INPUT_BUTTON_ATCK2(this) = false;
+ PHYS_INPUT_BUTTON_CROUCH(this) = false;
+
+ this.movement = '0 0 0';
+ this.bot_cmd_keys = BOT_CMD_KEY_NONE;
+
+ this.bot_exec_status |= BOT_EXEC_STATUS_PAUSED;
+ return CMD_STATUS_FINISHED;
+}
+
+float bot_cmd_moveto(entity this)
+{
+ return this.cmd_moveto(this, bot_cmd.bot_cmd_parm_vector);
+}
+
+float bot_cmd_movetotarget(entity this)
+{
+ entity e;
+ e = bot_getplace(this, bot_cmd.bot_cmd_parm_string);
+ if(!e)
+ return CMD_STATUS_ERROR;
+ return this.cmd_moveto(this, e.origin + (e.mins + e.maxs) * 0.5);
+}
+
+float bot_cmd_resetgoal(entity this)
+{
+ return this.cmd_resetgoal(this);
+}
+
+
+float bot_cmd_sound(entity this)
+{
+ string f;
+ f = bot_cmd.bot_cmd_parm_string;
+
+ float n = tokenizebyseparator(f, " ");
+
+ string sample = f;
+ float chan = CH_WEAPON_B;
+ float vol = VOL_BASE;
+ float atten = ATTEN_MIN;
+
+ if(n >= 1)
+ sample = argv(n - 1);
+ if(n >= 2)
+ chan = stof(argv(0));
+ if(n >= 3)
+ vol = stof(argv(1));
+ if(n >= 4)
+ atten = stof(argv(2));
+
+ precache_sound(f);
+ _sound(this, chan, sample, vol, atten);
+
+ return CMD_STATUS_FINISHED;
+}
+
+.entity tuba_note;
+float bot_cmd_debug_assert_canfire(entity this)
+{
+ float f = bot_cmd.bot_cmd_parm_float;
+
+ int slot = 0; // TODO: unhardcode?
+ .entity weaponentity = weaponentities[slot];
+ if(this.(weaponentity).state != WS_READY)
+ {
+ if(f)
+ {
+ this.colormod = '0 8 8';
+ LOG_INFO("Bot ", this.netname, " using ", this.weaponname, " wants to fire, inhibited by weaponentity state\n");
+ }
+ }
+ else if(ATTACK_FINISHED(this, slot) > time)
+ {
+ if(f)
+ {
+ this.colormod = '8 0 8';
+ LOG_INFO("Bot ", this.netname, " using ", this.weaponname, " wants to fire, inhibited by ATTACK_FINISHED (", ftos(ATTACK_FINISHED(this, slot) - time), " seconds left)\n");
+ }
+ }
+ else if(this.tuba_note)
+ {
+ if(f)
+ {
+ this.colormod = '8 0 0';
+ LOG_INFO("Bot ", this.netname, " using ", this.weaponname, " wants to fire, bot still has an active tuba note\n");
+ }
+ }
+ else
+ {
+ if(!f)
+ {
+ this.colormod = '8 8 0';
+ LOG_INFO("Bot ", this.netname, " using ", this.weaponname, " thinks it has fired, but apparently did not; ATTACK_FINISHED says ", ftos(ATTACK_FINISHED(this, slot) - time), " seconds left\n");
+ }
+ }
+
+ return CMD_STATUS_FINISHED;
+}
+
+//
+
+void bot_command_executed(entity this, bool rm)
+{
+ entity cmd;
+
+ cmd = bot_cmd;
+
+ if(rm)
+ bot_dequeuecommand(this, this.bot_cmd_execution_index);
+
+ this.bot_cmd_execution_index++;
+}
+
+void bot_setcurrentcommand(entity this)
+{
+ bot_cmd = NULL;
+
+ if(!this.bot_cmd_current)
+ {
+ this.bot_cmd_current = new_pure(bot_cmd);
+ this.bot_cmd_current.is_bot_cmd = true;
+ }
+
+ bot_cmd = this.bot_cmd_current;
+ if(bot_cmd.bot_cmd_index != this.bot_cmd_execution_index || this.bot_cmd_execution_index == 0)
+ {
+ if(bot_havecommand(this, this.bot_cmd_execution_index))
+ {
+ string cmdstring;
+ cmdstring = bot_readcommand(this, this.bot_cmd_execution_index);
+ if(bot_decodecommand(cmdstring))
+ {
+ bot_cmd.owner = this;
+ bot_cmd.bot_cmd_index = this.bot_cmd_execution_index;
+ }
+ else
+ {
+ // Invalid command, remove from queue
+ bot_cmd = NULL;
+ bot_dequeuecommand(this, this.bot_cmd_execution_index);
+ this.bot_cmd_execution_index++;
+ }
+ }
+ else
+ bot_cmd = NULL;
+ }
+}
+
+void bot_resetqueues()
+{
+ FOREACH_CLIENT(it.isbot, LAMBDA(
+ it.bot_cmd_execution_index = 0;
+ bot_clearqueue(it);
+ // also, cancel all barriers
+ it.bot_barrier = 0;
+ for(int i = 0; i < it.bot_places_count; ++i)
+ {
+ strunzone(it.(bot_placenames[i]));
+ it.(bot_placenames[i]) = string_null;
+ }
+ it.bot_places_count = 0;
+ ));
+
+ bot_barriertime = time;
+}
+
+// Here we map commands to functions and deal with complex interactions between commands and execution states
+// NOTE: Of course you need to include your commands here too :)
+float bot_execute_commands_once(entity this)
+{
+ float status, ispressingkey;
+
+ // Find command
+ bot_setcurrentcommand(this);
+
+ // if we have no bot command, better return
+ // old logic kept pressing previously pressed keys, but that has problems
+ // (namely, it means you cannot make a bot "normal" ever again)
+ // to keep a bot walking for a while, use the "wait" bot command
+ if(bot_cmd == NULL)
+ return false;
+
+ // Ignore all commands except continue when the bot is paused
+ if(this.bot_exec_status & BOT_EXEC_STATUS_PAUSED)
+ if(bot_cmd.bot_cmd_type!=BOT_CMD_CONTINUE)
+ {
+ if(bot_cmd.bot_cmd_type!=BOT_CMD_NULL)
+ {
+ bot_command_executed(this, true);
+ LOG_INFO( "WARNING: Commands are ignored while the bot is paused. Use the command 'continue' instead.\n");
+ }
+ return 1;
+ }
+
+ // Keep pressing keys raised by the "presskey" command
+ ispressingkey = boolean(bot_presskeys(this));
+
+ // Handle conditions
+ if (!(bot_cmd.bot_cmd_type==BOT_CMD_FI||bot_cmd.bot_cmd_type==BOT_CMD_ELSE))
+ if(this.bot_cmd_condition_status & CMD_CONDITION_true && this.bot_cmd_condition_status & CMD_CONDITION_false_BLOCK)
+ {
+ bot_command_executed(this, true);
+ return -1;
+ }
+ else if(this.bot_cmd_condition_status & CMD_CONDITION_false && this.bot_cmd_condition_status & CMD_CONDITION_true_BLOCK)
+ {
+ bot_command_executed(this, true);
+ return -1;
+ }
+
+ // Map commands to functions
+ switch(bot_cmd.bot_cmd_type)
+ {
+ case BOT_CMD_NULL:
+ return ispressingkey;
+ //break;
+ case BOT_CMD_PAUSE:
+ status = bot_cmd_pause(this);
+ break;
+ case BOT_CMD_CONTINUE:
+ status = bot_cmd_continue(this);
+ break;
+ case BOT_CMD_WAIT:
+ status = bot_cmd_wait(this);
+ break;
+ case BOT_CMD_WAIT_UNTIL:
+ status = bot_cmd_wait_until(this);
+ break;
+ case BOT_CMD_TURN:
+ status = bot_cmd_turn(this);
+ break;
+ case BOT_CMD_MOVETO:
+ status = bot_cmd_moveto(this);
+ break;
+ case BOT_CMD_MOVETOTARGET:
+ status = bot_cmd_movetotarget(this);
+ break;
+ case BOT_CMD_RESETGOAL:
+ status = bot_cmd_resetgoal(this);
+ break;
+ case BOT_CMD_CC:
+ status = bot_cmd_cc(this);
+ break;
+ case BOT_CMD_IF:
+ status = bot_cmd_if(this);
+ break;
+ case BOT_CMD_ELSE:
+ status = bot_cmd_else(this);
+ break;
+ case BOT_CMD_FI:
+ status = bot_cmd_fi(this);
+ break;
+ case BOT_CMD_RESETAIM:
+ status = bot_cmd_resetaim(this);
+ break;
+ case BOT_CMD_AIM:
+ status = bot_cmd_aim(this);
+ break;
+ case BOT_CMD_AIMTARGET:
+ status = bot_cmd_aimtarget(this);
+ break;
+ case BOT_CMD_PRESSKEY:
+ status = bot_cmd_presskey(this);
+ break;
+ case BOT_CMD_RELEASEKEY:
+ status = bot_cmd_releasekey(this);
+ break;
+ case BOT_CMD_SELECTWEAPON:
+ status = bot_cmd_select_weapon(this);
+ break;
+ case BOT_CMD_IMPULSE:
+ status = bot_cmd_impulse(this);
+ break;
+ case BOT_CMD_BARRIER:
+ status = bot_cmd_barrier(this);
+ break;
+ case BOT_CMD_CONSOLE:
+ localcmd(strcat(bot_cmd.bot_cmd_parm_string, "\n"));
+ status = CMD_STATUS_FINISHED;
+ break;
+ case BOT_CMD_SOUND:
+ status = bot_cmd_sound(this);
+ break;
+ case BOT_CMD_DEBUG_ASSERT_CANFIRE:
+ status = bot_cmd_debug_assert_canfire(this);
+ break;
+ default:
+ LOG_INFO(strcat("ERROR: Invalid command on queue with id '",ftos(bot_cmd.bot_cmd_type),"'\n"));
+ return 0;
+ }
+
+ if (status==CMD_STATUS_ERROR)
+ LOG_INFO(strcat("ERROR: The command '",bot_cmd_string[bot_cmd.bot_cmd_type],"' returned an error status\n"));
+
+ // Move execution pointer
+ if(status==CMD_STATUS_EXECUTING)
+ {
+ return 1;
+ }
+ else
+ {
+ if(autocvar_g_debug_bot_commands)
+ {
+ string parms;
+
+ switch(bot_cmd_parm_type[bot_cmd.bot_cmd_type])
+ {
+ case BOT_CMD_PARAMETER_FLOAT:
+ parms = ftos(bot_cmd.bot_cmd_parm_float);
+ break;
+ case BOT_CMD_PARAMETER_STRING:
+ parms = bot_cmd.bot_cmd_parm_string;
+ break;
+ case BOT_CMD_PARAMETER_VECTOR:
+ parms = vtos(bot_cmd.bot_cmd_parm_vector);
+ break;
+ default:
+ parms = "";
+ break;
+ }
+ clientcommand(this,strcat("say ^7", bot_cmd_string[bot_cmd.bot_cmd_type]," ",parms,"\n"));
+ }
+
+ bot_command_executed(this, true);
+ }
+
+ if(status == CMD_STATUS_FINISHED)
+ return -1;
+
+ return CMD_STATUS_ERROR;
+}
+
+// This function should be (the only) called directly from the bot ai loop
+int bot_execute_commands(entity this)
+{
+ int f;
+ do
+ {
+ f = bot_execute_commands_once(this);
+ }
+ while(f < 0);
+ return f;
+}
--- /dev/null
+#pragma once
+
+#define BOT_EXEC_STATUS_IDLE 0
+#define BOT_EXEC_STATUS_PAUSED 1
+#define BOT_EXEC_STATUS_WAITING 2
+
+#define CMD_STATUS_EXECUTING 0
+#define CMD_STATUS_FINISHED 1
+#define CMD_STATUS_ERROR 2
+
+
+// NOTE: New commands should be added here. Do not forget to update BOT_CMD_COUNTER
+const int BOT_CMD_NULL = 0;
+const int BOT_CMD_PAUSE = 1;
+const int BOT_CMD_CONTINUE = 2;
+const int BOT_CMD_WAIT = 3;
+const int BOT_CMD_TURN = 4;
+const int BOT_CMD_MOVETO = 5;
+const int BOT_CMD_RESETGOAL = 6; // Not implemented yet
+const int BOT_CMD_CC = 7;
+const int BOT_CMD_IF = 8;
+const int BOT_CMD_ELSE = 9;
+const int BOT_CMD_FI = 10;
+const int BOT_CMD_RESETAIM = 11;
+const int BOT_CMD_AIM = 12;
+const int BOT_CMD_PRESSKEY = 13;
+const int BOT_CMD_RELEASEKEY = 14;
+const int BOT_CMD_SELECTWEAPON = 15;
+const int BOT_CMD_IMPULSE = 16;
+const int BOT_CMD_WAIT_UNTIL = 17;
+const int BOT_CMD_MOVETOTARGET = 18;
+const int BOT_CMD_AIMTARGET = 19;
+const int BOT_CMD_BARRIER = 20;
+const int BOT_CMD_CONSOLE = 21;
+const int BOT_CMD_SOUND = 22;
+const int BOT_CMD_DEBUG_ASSERT_CANFIRE = 23;
+const int BOT_CMD_WHILE = 24; // TODO: Not implemented yet
+const int BOT_CMD_WEND = 25; // TODO: Not implemented yet
+const int BOT_CMD_CHASE = 26; // TODO: Not implemented yet
+
+const int BOT_CMD_COUNTER = 24; // Update this value if you add/remove a command
+
+// NOTE: Following commands should be implemented on the bot ai
+// If a new command should be handled by the target ai(s) please declare it here
+.float(entity, vector) cmd_moveto;
+.float(entity) cmd_resetgoal;
+
+//
+const int BOT_CMD_PARAMETER_NONE = 0;
+const int BOT_CMD_PARAMETER_FLOAT = 1;
+const int BOT_CMD_PARAMETER_STRING = 2;
+const int BOT_CMD_PARAMETER_VECTOR = 3;
+
+float bot_cmds_initialized;
+int bot_cmd_parm_type[BOT_CMD_COUNTER];
+string bot_cmd_string[BOT_CMD_COUNTER];
+
+// Bots command queue
+entity bot_cmd; // global current command
+.entity bot_cmd_current; // current command of this bot
+
+.float is_bot_cmd; // Tells if the entity is a bot command
+.float bot_cmd_index; // Position of the command in the queue
+.int bot_cmd_type; // If of command (see the BOT_CMD_* defines)
+.float bot_cmd_parm_float; // Field to store a float parameter
+.string bot_cmd_parm_string; // Field to store a string parameter
+.vector bot_cmd_parm_vector; // Field to store a vector parameter
+
+float bot_barriertime;
+.float bot_barrier;
+
+.float bot_cmd_execution_index; // Position in the queue of the command to be executed
+
+
+void bot_resetqueues();
+void bot_queuecommand(entity bot, string cmdstring);
+void bot_cmdhelp(string scmd);
+void bot_list_commands();
+float bot_execute_commands(entity this);
+entity find_bot_by_name(string name);
+entity find_bot_by_number(float number);
--- /dev/null
+#include "waypoints.qh"
+
+#include "cvars.qh"
+
+#include "bot.qh"
+#include "navigation.qh"
+
+#include <common/state.qh>
+
+#include "../../antilag.qh"
+
+#include <common/constants.qh>
+
+#include <lib/warpzone/common.qh>
+#include <lib/warpzone/util_server.qh>
+
+// create a new spawnfunc_waypoint and automatically link it to other waypoints, and link
+// them back to it as well
+// (suitable for spawnfunc_waypoint editor)
+entity waypoint_spawn(vector m1, vector m2, float f)
+{
+ if(!(f & WAYPOINTFLAG_PERSONAL))
+ {
+ IL_EACH(g_waypoints, boxesoverlap(m1, m2, it.absmin, it.absmax),
+ {
+ return it;
+ });
+ }
+
+ entity w = new(waypoint);
+ IL_PUSH(g_waypoints, w);
+ w.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
+ w.wpflags = f;
+ w.solid = SOLID_TRIGGER;
+ setorigin(w, (m1 + m2) * 0.5);
+ setsize(w, m1 - w.origin, m2 - w.origin);
+ if (vlen(w.size) > 0)
+ w.wpisbox = true;
+
+ if(!w.wpisbox)
+ {
+ setsize(w, STAT(PL_MIN, NULL) - '1 1 0', STAT(PL_MAX, NULL) + '1 1 0');
+ if(!move_out_of_solid(w))
+ {
+ if(!(f & WAYPOINTFLAG_GENERATED))
+ {
+ LOG_TRACE("Killed a waypoint that was stuck in solid at ", vtos(w.origin));
+ delete(w);
+ return NULL;
+ }
+ else
+ {
+ if(autocvar_developer)
+ {
+ LOG_INFO("A generated waypoint is stuck in solid at ", vtos(w.origin), "\n");
+ backtrace("Waypoint stuck");
+ }
+ }
+ }
+ setsize(w, '0 0 0', '0 0 0');
+ }
+
+ waypoint_clearlinks(w);
+ //waypoint_schedulerelink(w);
+
+ if (autocvar_g_waypointeditor)
+ {
+ m1 = w.mins;
+ m2 = w.maxs;
+ setmodel(w, MDL_WAYPOINT); w.effects = EF_LOWPRECISION;
+ setsize(w, m1, m2);
+ if (w.wpflags & WAYPOINTFLAG_ITEM)
+ w.colormod = '1 0 0';
+ else if (w.wpflags & WAYPOINTFLAG_GENERATED)
+ w.colormod = '1 1 0';
+ else
+ w.colormod = '1 1 1';
+ }
+ else
+ w.model = "";
+
+ return w;
+}
+
+// add a new link to the spawnfunc_waypoint, replacing the furthest link it already has
+void waypoint_addlink(entity from, entity to)
+{
+ float c;
+
+ if (from == to)
+ return;
+ if (from.wpflags & WAYPOINTFLAG_NORELINK)
+ return;
+
+ if (from.wp00 == to) return;if (from.wp01 == to) return;if (from.wp02 == to) return;if (from.wp03 == to) return;
+ if (from.wp04 == to) return;if (from.wp05 == to) return;if (from.wp06 == to) return;if (from.wp07 == to) return;
+ if (from.wp08 == to) return;if (from.wp09 == to) return;if (from.wp10 == to) return;if (from.wp11 == to) return;
+ if (from.wp12 == to) return;if (from.wp13 == to) return;if (from.wp14 == to) return;if (from.wp15 == to) return;
+ if (from.wp16 == to) return;if (from.wp17 == to) return;if (from.wp18 == to) return;if (from.wp19 == to) return;
+ if (from.wp20 == to) return;if (from.wp21 == to) return;if (from.wp22 == to) return;if (from.wp23 == to) return;
+ if (from.wp24 == to) return;if (from.wp25 == to) return;if (from.wp26 == to) return;if (from.wp27 == to) return;
+ if (from.wp28 == to) return;if (from.wp29 == to) return;if (from.wp30 == to) return;if (from.wp31 == to) return;
+
+ if (to.wpisbox || from.wpisbox)
+ {
+ // if either is a box we have to find the nearest points on them to
+ // calculate the distance properly
+ vector v1, v2, m1, m2;
+ v1 = from.origin;
+ m1 = to.absmin;
+ m2 = to.absmax;
+ v1_x = bound(m1_x, v1_x, m2_x);
+ v1_y = bound(m1_y, v1_y, m2_y);
+ v1_z = bound(m1_z, v1_z, m2_z);
+ v2 = to.origin;
+ m1 = from.absmin;
+ m2 = from.absmax;
+ v2_x = bound(m1_x, v2_x, m2_x);
+ v2_y = bound(m1_y, v2_y, m2_y);
+ v2_z = bound(m1_z, v2_z, m2_z);
+ v2 = to.origin;
+ c = vlen(v2 - v1);
+ }
+ else
+ c = vlen(to.origin - from.origin);
+
+ if (from.wp31mincost < c) return;
+ if (from.wp30mincost < c) {from.wp31 = to;from.wp31mincost = c;return;} from.wp31 = from.wp30;from.wp31mincost = from.wp30mincost;
+ if (from.wp29mincost < c) {from.wp30 = to;from.wp30mincost = c;return;} from.wp30 = from.wp29;from.wp30mincost = from.wp29mincost;
+ if (from.wp28mincost < c) {from.wp29 = to;from.wp29mincost = c;return;} from.wp29 = from.wp28;from.wp29mincost = from.wp28mincost;
+ if (from.wp27mincost < c) {from.wp28 = to;from.wp28mincost = c;return;} from.wp28 = from.wp27;from.wp28mincost = from.wp27mincost;
+ if (from.wp26mincost < c) {from.wp27 = to;from.wp27mincost = c;return;} from.wp27 = from.wp26;from.wp27mincost = from.wp26mincost;
+ if (from.wp25mincost < c) {from.wp26 = to;from.wp26mincost = c;return;} from.wp26 = from.wp25;from.wp26mincost = from.wp25mincost;
+ if (from.wp24mincost < c) {from.wp25 = to;from.wp25mincost = c;return;} from.wp25 = from.wp24;from.wp25mincost = from.wp24mincost;
+ if (from.wp23mincost < c) {from.wp24 = to;from.wp24mincost = c;return;} from.wp24 = from.wp23;from.wp24mincost = from.wp23mincost;
+ if (from.wp22mincost < c) {from.wp23 = to;from.wp23mincost = c;return;} from.wp23 = from.wp22;from.wp23mincost = from.wp22mincost;
+ if (from.wp21mincost < c) {from.wp22 = to;from.wp22mincost = c;return;} from.wp22 = from.wp21;from.wp22mincost = from.wp21mincost;
+ if (from.wp20mincost < c) {from.wp21 = to;from.wp21mincost = c;return;} from.wp21 = from.wp20;from.wp21mincost = from.wp20mincost;
+ if (from.wp19mincost < c) {from.wp20 = to;from.wp20mincost = c;return;} from.wp20 = from.wp19;from.wp20mincost = from.wp19mincost;
+ if (from.wp18mincost < c) {from.wp19 = to;from.wp19mincost = c;return;} from.wp19 = from.wp18;from.wp19mincost = from.wp18mincost;
+ if (from.wp17mincost < c) {from.wp18 = to;from.wp18mincost = c;return;} from.wp18 = from.wp17;from.wp18mincost = from.wp17mincost;
+ if (from.wp16mincost < c) {from.wp17 = to;from.wp17mincost = c;return;} from.wp17 = from.wp16;from.wp17mincost = from.wp16mincost;
+ if (from.wp15mincost < c) {from.wp16 = to;from.wp16mincost = c;return;} from.wp16 = from.wp15;from.wp16mincost = from.wp15mincost;
+ if (from.wp14mincost < c) {from.wp15 = to;from.wp15mincost = c;return;} from.wp15 = from.wp14;from.wp15mincost = from.wp14mincost;
+ if (from.wp13mincost < c) {from.wp14 = to;from.wp14mincost = c;return;} from.wp14 = from.wp13;from.wp14mincost = from.wp13mincost;
+ if (from.wp12mincost < c) {from.wp13 = to;from.wp13mincost = c;return;} from.wp13 = from.wp12;from.wp13mincost = from.wp12mincost;
+ if (from.wp11mincost < c) {from.wp12 = to;from.wp12mincost = c;return;} from.wp12 = from.wp11;from.wp12mincost = from.wp11mincost;
+ if (from.wp10mincost < c) {from.wp11 = to;from.wp11mincost = c;return;} from.wp11 = from.wp10;from.wp11mincost = from.wp10mincost;
+ if (from.wp09mincost < c) {from.wp10 = to;from.wp10mincost = c;return;} from.wp10 = from.wp09;from.wp10mincost = from.wp09mincost;
+ if (from.wp08mincost < c) {from.wp09 = to;from.wp09mincost = c;return;} from.wp09 = from.wp08;from.wp09mincost = from.wp08mincost;
+ if (from.wp07mincost < c) {from.wp08 = to;from.wp08mincost = c;return;} from.wp08 = from.wp07;from.wp08mincost = from.wp07mincost;
+ if (from.wp06mincost < c) {from.wp07 = to;from.wp07mincost = c;return;} from.wp07 = from.wp06;from.wp07mincost = from.wp06mincost;
+ if (from.wp05mincost < c) {from.wp06 = to;from.wp06mincost = c;return;} from.wp06 = from.wp05;from.wp06mincost = from.wp05mincost;
+ if (from.wp04mincost < c) {from.wp05 = to;from.wp05mincost = c;return;} from.wp05 = from.wp04;from.wp05mincost = from.wp04mincost;
+ if (from.wp03mincost < c) {from.wp04 = to;from.wp04mincost = c;return;} from.wp04 = from.wp03;from.wp04mincost = from.wp03mincost;
+ if (from.wp02mincost < c) {from.wp03 = to;from.wp03mincost = c;return;} from.wp03 = from.wp02;from.wp03mincost = from.wp02mincost;
+ if (from.wp01mincost < c) {from.wp02 = to;from.wp02mincost = c;return;} from.wp02 = from.wp01;from.wp02mincost = from.wp01mincost;
+ if (from.wp00mincost < c) {from.wp01 = to;from.wp01mincost = c;return;} from.wp01 = from.wp00;from.wp01mincost = from.wp00mincost;
+ from.wp00 = to;from.wp00mincost = c;return;
+}
+
+// relink this spawnfunc_waypoint
+// (precompile a list of all reachable waypoints from this spawnfunc_waypoint)
+// (SLOW!)
+void waypoint_think(entity this)
+{
+ vector sv, sm1, sm2, ev, em1, em2, dv;
+
+ bot_calculate_stepheightvec();
+
+ bot_navigation_movemode = ((autocvar_bot_navigation_ignoreplayers) ? MOVE_NOMONSTERS : MOVE_NORMAL);
+
+ //dprint("waypoint_think wpisbox = ", ftos(this.wpisbox), "\n");
+ sm1 = this.origin + this.mins;
+ sm2 = this.origin + this.maxs;
+ IL_EACH(g_waypoints, true,
+ {
+ if (boxesoverlap(this.absmin, this.absmax, it.absmin, it.absmax))
+ {
+ waypoint_addlink(this, it);
+ waypoint_addlink(it, this);
+ }
+ else
+ {
+ ++relink_total;
+ if(!checkpvs(this.origin, it))
+ {
+ ++relink_pvsculled;
+ continue;
+ }
+ sv = it.origin;
+ sv.x = bound(sm1_x, sv.x, sm2_x);
+ sv.y = bound(sm1_y, sv.y, sm2_y);
+ sv.z = bound(sm1_z, sv.z, sm2_z);
+ ev = this.origin;
+ em1 = it.origin + it.mins;
+ em2 = it.origin + it.maxs;
+ ev.x = bound(em1_x, ev.x, em2_x);
+ ev.y = bound(em1_y, ev.y, em2_y);
+ ev.z = bound(em1_z, ev.z, em2_z);
+ dv = ev - sv;
+ dv.z = 0;
+ if(vdist(dv, >=, 1050)) // max search distance in XY
+ {
+ ++relink_lengthculled;
+ continue;
+ }
+ navigation_testtracewalk = 0;
+ if (!this.wpisbox)
+ {
+ tracebox(sv - STAT(PL_MIN, NULL).z * '0 0 1', STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), sv, false, this);
+ if (!trace_startsolid)
+ {
+ //dprint("sv deviation", vtos(trace_endpos - sv), "\n");
+ sv = trace_endpos + '0 0 1';
+ }
+ }
+ if (!it.wpisbox)
+ {
+ tracebox(ev - STAT(PL_MIN, NULL).z * '0 0 1', STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), ev, false, it);
+ if (!trace_startsolid)
+ {
+ //dprint("ev deviation", vtos(trace_endpos - ev), "\n");
+ ev = trace_endpos + '0 0 1';
+ }
+ }
+ //traceline(this.origin, it.origin, false, NULL);
+ //if (trace_fraction == 1)
+ if (!this.wpisbox && tracewalk(this, sv, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), ev, MOVE_NOMONSTERS))
+ waypoint_addlink(this, it);
+ else
+ relink_walkculled += 0.5;
+ if (!it.wpisbox && tracewalk(it, ev, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), sv, MOVE_NOMONSTERS))
+ waypoint_addlink(it, this);
+ else
+ relink_walkculled += 0.5;
+ }
+ });
+ navigation_testtracewalk = 0;
+ this.wplinked = true;
+}
+
+void waypoint_clearlinks(entity wp)
+{
+ // clear links to other waypoints
+ float f;
+ f = 10000000;
+ wp.wp00 = wp.wp01 = wp.wp02 = wp.wp03 = wp.wp04 = wp.wp05 = wp.wp06 = wp.wp07 = NULL;
+ wp.wp08 = wp.wp09 = wp.wp10 = wp.wp11 = wp.wp12 = wp.wp13 = wp.wp14 = wp.wp15 = NULL;
+ wp.wp16 = wp.wp17 = wp.wp18 = wp.wp19 = wp.wp20 = wp.wp21 = wp.wp22 = wp.wp23 = NULL;
+ wp.wp24 = wp.wp25 = wp.wp26 = wp.wp27 = wp.wp28 = wp.wp29 = wp.wp30 = wp.wp31 = NULL;
+
+ wp.wp00mincost = wp.wp01mincost = wp.wp02mincost = wp.wp03mincost = wp.wp04mincost = wp.wp05mincost = wp.wp06mincost = wp.wp07mincost = f;
+ wp.wp08mincost = wp.wp09mincost = wp.wp10mincost = wp.wp11mincost = wp.wp12mincost = wp.wp13mincost = wp.wp14mincost = wp.wp15mincost = f;
+ wp.wp16mincost = wp.wp17mincost = wp.wp18mincost = wp.wp19mincost = wp.wp20mincost = wp.wp21mincost = wp.wp22mincost = wp.wp23mincost = f;
+ wp.wp24mincost = wp.wp25mincost = wp.wp26mincost = wp.wp27mincost = wp.wp28mincost = wp.wp29mincost = wp.wp30mincost = wp.wp31mincost = f;
+
+ wp.wplinked = false;
+}
+
+// tell a spawnfunc_waypoint to relink
+void waypoint_schedulerelink(entity wp)
+{
+ if (wp == NULL)
+ return;
+ // TODO: add some sort of visible box in edit mode for box waypoints
+ if (autocvar_g_waypointeditor)
+ {
+ vector m1, m2;
+ m1 = wp.mins;
+ m2 = wp.maxs;
+ setmodel(wp, MDL_WAYPOINT); wp.effects = EF_LOWPRECISION;
+ setsize(wp, m1, m2);
+ if (wp.wpflags & WAYPOINTFLAG_ITEM)
+ wp.colormod = '1 0 0';
+ else if (wp.wpflags & WAYPOINTFLAG_GENERATED)
+ wp.colormod = '1 1 0';
+ else
+ wp.colormod = '1 1 1';
+ }
+ else
+ wp.model = "";
+ wp.wpisbox = vlen(wp.size) > 0;
+ wp.enemy = NULL;
+ if (!(wp.wpflags & WAYPOINTFLAG_PERSONAL))
+ wp.owner = NULL;
+ if (!(wp.wpflags & WAYPOINTFLAG_NORELINK))
+ waypoint_clearlinks(wp);
+ // schedule an actual relink on next frame
+ setthink(wp, waypoint_think);
+ wp.nextthink = time;
+ wp.effects = EF_LOWPRECISION;
+}
+
+// spawnfunc_waypoint map entity
+spawnfunc(waypoint)
+{
+ IL_PUSH(g_waypoints, this);
+
+ setorigin(this, this.origin);
+ // schedule a relink after other waypoints have had a chance to spawn
+ waypoint_clearlinks(this);
+ //waypoint_schedulerelink(this);
+}
+
+// remove a spawnfunc_waypoint, and schedule all neighbors to relink
+void waypoint_remove(entity e)
+{
+ // tell all linked waypoints that they need to relink
+ waypoint_schedulerelink(e.wp00);
+ waypoint_schedulerelink(e.wp01);
+ waypoint_schedulerelink(e.wp02);
+ waypoint_schedulerelink(e.wp03);
+ waypoint_schedulerelink(e.wp04);
+ waypoint_schedulerelink(e.wp05);
+ waypoint_schedulerelink(e.wp06);
+ waypoint_schedulerelink(e.wp07);
+ waypoint_schedulerelink(e.wp08);
+ waypoint_schedulerelink(e.wp09);
+ waypoint_schedulerelink(e.wp10);
+ waypoint_schedulerelink(e.wp11);
+ waypoint_schedulerelink(e.wp12);
+ waypoint_schedulerelink(e.wp13);
+ waypoint_schedulerelink(e.wp14);
+ waypoint_schedulerelink(e.wp15);
+ waypoint_schedulerelink(e.wp16);
+ waypoint_schedulerelink(e.wp17);
+ waypoint_schedulerelink(e.wp18);
+ waypoint_schedulerelink(e.wp19);
+ waypoint_schedulerelink(e.wp20);
+ waypoint_schedulerelink(e.wp21);
+ waypoint_schedulerelink(e.wp22);
+ waypoint_schedulerelink(e.wp23);
+ waypoint_schedulerelink(e.wp24);
+ waypoint_schedulerelink(e.wp25);
+ waypoint_schedulerelink(e.wp26);
+ waypoint_schedulerelink(e.wp27);
+ waypoint_schedulerelink(e.wp28);
+ waypoint_schedulerelink(e.wp29);
+ waypoint_schedulerelink(e.wp30);
+ waypoint_schedulerelink(e.wp31);
+ // and now remove the spawnfunc_waypoint
+ delete(e);
+}
+
+// empties the map of waypoints
+void waypoint_removeall()
+{
+ IL_EACH(g_waypoints, true,
+ {
+ delete(it);
+ });
+}
+
+// tell all waypoints to relink
+// (is this useful at all?)
+void waypoint_schedulerelinkall()
+{
+ relink_total = relink_walkculled = relink_pvsculled = relink_lengthculled = 0;
+ IL_EACH(g_waypoints, true,
+ {
+ waypoint_schedulerelink(it);
+ });
+}
+
+// Load waypoint links from file
+float waypoint_load_links()
+{
+ string filename, s;
+ float file, tokens, c = 0, found;
+ entity wp_from = NULL, wp_to;
+ vector wp_to_pos, wp_from_pos;
+ filename = strcat("maps/", mapname);
+ filename = strcat(filename, ".waypoints.cache");
+ file = fopen(filename, FILE_READ);
+
+ if (file < 0)
+ {
+ LOG_TRACE("waypoint links load from ");
+ LOG_TRACE(filename);
+ LOG_TRACE(" failed");
+ return false;
+ }
+
+ while ((s = fgets(file)))
+ {
+ tokens = tokenizebyseparator(s, "*");
+
+ if (tokens!=2)
+ {
+ // bad file format
+ fclose(file);
+ return false;
+ }
+
+ wp_from_pos = stov(argv(0));
+ wp_to_pos = stov(argv(1));
+
+ // Search "from" waypoint
+ if(!wp_from || wp_from.origin!=wp_from_pos)
+ {
+ wp_from = findradius(wp_from_pos, 1);
+ found = false;
+ while(wp_from)
+ {
+ if(vdist(wp_from.origin - wp_from_pos, <, 1))
+ if(wp_from.classname == "waypoint")
+ {
+ found = true;
+ break;
+ }
+ wp_from = wp_from.chain;
+ }
+
+ if(!found)
+ {
+ LOG_TRACE("waypoint_load_links: couldn't find 'from' waypoint at ", vtos(wp_from.origin));
+ continue;
+ }
+
+ }
+
+ // Search "to" waypoint
+ wp_to = findradius(wp_to_pos, 1);
+ found = false;
+ while(wp_to)
+ {
+ if(vdist(wp_to.origin - wp_to_pos, <, 1))
+ if(wp_to.classname == "waypoint")
+ {
+ found = true;
+ break;
+ }
+ wp_to = wp_to.chain;
+ }
+
+ if(!found)
+ {
+ LOG_TRACE("waypoint_load_links: couldn't find 'to' waypoint at ", vtos(wp_to.origin));
+ continue;
+ }
+
+ ++c;
+ waypoint_addlink(wp_from, wp_to);
+ }
+
+ fclose(file);
+
+ LOG_TRACE("loaded ", ftos(c), " waypoint links from maps/", mapname, ".waypoints.cache");
+
+ botframe_cachedwaypointlinks = true;
+ return true;
+}
+
+void waypoint_load_links_hardwired()
+{
+ string filename, s;
+ float file, tokens, c = 0, found;
+ entity wp_from = NULL, wp_to;
+ vector wp_to_pos, wp_from_pos;
+ filename = strcat("maps/", mapname);
+ filename = strcat(filename, ".waypoints.hardwired");
+ file = fopen(filename, FILE_READ);
+
+ botframe_loadedforcedlinks = true;
+
+ if (file < 0)
+ {
+ LOG_TRACE("waypoint links load from ", filename, " failed");
+ return;
+ }
+
+ while ((s = fgets(file)))
+ {
+ if(substring(s, 0, 2)=="//")
+ continue;
+
+ if(substring(s, 0, 1)=="#")
+ continue;
+
+ tokens = tokenizebyseparator(s, "*");
+
+ if (tokens!=2)
+ continue;
+
+ wp_from_pos = stov(argv(0));
+ wp_to_pos = stov(argv(1));
+
+ // Search "from" waypoint
+ if(!wp_from || wp_from.origin!=wp_from_pos)
+ {
+ wp_from = findradius(wp_from_pos, 5);
+ found = false;
+ while(wp_from)
+ {
+ if(vdist(wp_from.origin - wp_from_pos, <, 5))
+ if(wp_from.classname == "waypoint")
+ {
+ found = true;
+ break;
+ }
+ wp_from = wp_from.chain;
+ }
+
+ if(!found)
+ {
+ LOG_INFO(strcat("NOTICE: Can not find waypoint at ", vtos(wp_from_pos), ". Path skipped\n"));
+ continue;
+ }
+ }
+
+ // Search "to" waypoint
+ wp_to = findradius(wp_to_pos, 5);
+ found = false;
+ while(wp_to)
+ {
+ if(vdist(wp_to.origin - wp_to_pos, <, 5))
+ if(wp_to.classname == "waypoint")
+ {
+ found = true;
+ break;
+ }
+ wp_to = wp_to.chain;
+ }
+
+ if(!found)
+ {
+ LOG_INFO(strcat("NOTICE: Can not find waypoint at ", vtos(wp_to_pos), ". Path skipped\n"));
+ continue;
+ }
+
+ ++c;
+ waypoint_addlink(wp_from, wp_to);
+ wp_from.wphardwired = true;
+ wp_to.wphardwired = true;
+ }
+
+ fclose(file);
+
+ LOG_TRACE("loaded ", ftos(c), " waypoint links from maps/", mapname, ".waypoints.hardwired");
+}
+
+entity waypoint_get_link(entity w, float i)
+{
+ switch(i)
+ {
+ case 0:return w.wp00;
+ case 1:return w.wp01;
+ case 2:return w.wp02;
+ case 3:return w.wp03;
+ case 4:return w.wp04;
+ case 5:return w.wp05;
+ case 6:return w.wp06;
+ case 7:return w.wp07;
+ case 8:return w.wp08;
+ case 9:return w.wp09;
+ case 10:return w.wp10;
+ case 11:return w.wp11;
+ case 12:return w.wp12;
+ case 13:return w.wp13;
+ case 14:return w.wp14;
+ case 15:return w.wp15;
+ case 16:return w.wp16;
+ case 17:return w.wp17;
+ case 18:return w.wp18;
+ case 19:return w.wp19;
+ case 20:return w.wp20;
+ case 21:return w.wp21;
+ case 22:return w.wp22;
+ case 23:return w.wp23;
+ case 24:return w.wp24;
+ case 25:return w.wp25;
+ case 26:return w.wp26;
+ case 27:return w.wp27;
+ case 28:return w.wp28;
+ case 29:return w.wp29;
+ case 30:return w.wp30;
+ case 31:return w.wp31;
+ default:return NULL;
+ }
+}
+
+// Save all waypoint links to a file
+void waypoint_save_links()
+{
+ string filename = sprintf("maps/%s.waypoints.cache", mapname);
+ int file = fopen(filename, FILE_WRITE);
+ if (file < 0)
+ {
+ LOG_INFOF("waypoint link save to %s failed\n", filename);
+ return;
+ }
+
+ int c = 0;
+ IL_EACH(g_waypoints, true,
+ {
+ for(int j = 0; j < 32; ++j)
+ {
+ entity link = waypoint_get_link(it, j);
+ if(link)
+ {
+ string s = strcat(vtos(it.origin), "*", vtos(link.origin), "\n");
+ fputs(file, s);
+ ++c;
+ }
+ }
+ });
+ fclose(file);
+ botframe_cachedwaypointlinks = true;
+
+ LOG_INFOF("saved %d waypoint links to maps/%s.waypoints.cache\n", c, mapname);
+}
+
+// save waypoints to gamedir/data/maps/mapname.waypoints
+void waypoint_saveall()
+{
+ string filename = sprintf("maps/%s.waypoints", mapname);
+ int file = fopen(filename, FILE_WRITE);
+ if (file < 0)
+ {
+ waypoint_save_links(); // save anyway?
+ botframe_loadedforcedlinks = false;
+
+ LOG_INFOF("waypoint links: save to %s failed\n", filename);
+ return;
+ }
+
+ int c = 0;
+ IL_EACH(g_waypoints, true,
+ {
+ if(it.wpflags & WAYPOINTFLAG_GENERATED)
+ continue;
+
+ for(int j = 0; j < 32; ++j)
+ {
+ string s;
+ s = strcat(vtos(it.origin + it.mins), "\n");
+ s = strcat(s, vtos(it.origin + it.maxs));
+ s = strcat(s, "\n");
+ s = strcat(s, ftos(it.wpflags));
+ s = strcat(s, "\n");
+ fputs(file, s);
+ ++c;
+ }
+ });
+ fclose(file);
+ waypoint_save_links();
+ botframe_loadedforcedlinks = false;
+
+ LOG_INFOF("saved %d waypoints to maps/%s.waypoints\n", c, mapname);
+}
+
+// load waypoints from file
+float waypoint_loadall()
+{
+ string filename, s;
+ float file, cwp, cwb, fl;
+ vector m1, m2;
+ cwp = 0;
+ cwb = 0;
+ filename = strcat("maps/", mapname);
+ filename = strcat(filename, ".waypoints");
+ file = fopen(filename, FILE_READ);
+ if (file >= 0)
+ {
+ while ((s = fgets(file)))
+ {
+ m1 = stov(s);
+ s = fgets(file);
+ if (!s)
+ break;
+ m2 = stov(s);
+ s = fgets(file);
+ if (!s)
+ break;
+ fl = stof(s);
+ waypoint_spawn(m1, m2, fl);
+ if (m1 == m2)
+ cwp = cwp + 1;
+ else
+ cwb = cwb + 1;
+ }
+ fclose(file);
+ LOG_TRACE("loaded ", ftos(cwp), " waypoints and ", ftos(cwb), " wayboxes from maps/", mapname, ".waypoints");
+ }
+ else
+ {
+ LOG_TRACE("waypoint load from ", filename, " failed");
+ }
+ return cwp + cwb;
+}
+
+vector waypoint_fixorigin(vector position)
+{
+ tracebox(position + '0 0 1' * (1 - STAT(PL_MIN, NULL).z), STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), position + '0 0 -512', MOVE_NOMONSTERS, NULL);
+ if(trace_fraction < 1)
+ position = trace_endpos;
+ //traceline(position, position + '0 0 -512', MOVE_NOMONSTERS, NULL);
+ //print("position is ", ftos(trace_endpos_z - position_z), " above solid\n");
+ return position;
+}
+
+void waypoint_spawnforitem_force(entity e, vector org)
+{
+ // Fix the waypoint altitude if necessary
+ org = waypoint_fixorigin(org);
+
+ // don't spawn an item spawnfunc_waypoint if it already exists
+ IL_EACH(g_waypoints, true,
+ {
+ if(it.wpisbox)
+ {
+ if(boxesoverlap(org, org, it.absmin, it.absmax))
+ {
+ e.nearestwaypoint = it;
+ return;
+ }
+ }
+ else
+ {
+ if(vdist(it.origin - org, <, 16))
+ {
+ e.nearestwaypoint = it;
+ return;
+ }
+ }
+ });
+
+ e.nearestwaypoint = waypoint_spawn(org, org, WAYPOINTFLAG_GENERATED | WAYPOINTFLAG_ITEM);
+}
+
+void waypoint_spawnforitem(entity e)
+{
+ if(!bot_waypoints_for_items)
+ return;
+
+ waypoint_spawnforitem_force(e, e.origin);
+}
+
+void waypoint_spawnforteleporter_boxes(entity e, vector org1, vector org2, vector destination1, vector destination2, float timetaken)
+{
+ entity w;
+ entity dw;
+ w = waypoint_spawn(org1, org2, WAYPOINTFLAG_GENERATED | WAYPOINTFLAG_TELEPORT | WAYPOINTFLAG_NORELINK);
+ dw = waypoint_spawn(destination1, destination2, WAYPOINTFLAG_GENERATED);
+ // one way link to the destination
+ w.wp00 = dw;
+ w.wp00mincost = timetaken; // this is just for jump pads
+ // the teleporter's nearest spawnfunc_waypoint is this one
+ // (teleporters are not goals, so this is probably useless)
+ e.nearestwaypoint = w;
+ e.nearestwaypointtimeout = time + 1000000000;
+}
+
+void waypoint_spawnforteleporter_v(entity e, vector org, vector destination, float timetaken)
+{
+ org = waypoint_fixorigin(org);
+ destination = waypoint_fixorigin(destination);
+ waypoint_spawnforteleporter_boxes(e, org, org, destination, destination, timetaken);
+}
+
+void waypoint_spawnforteleporter(entity e, vector destination, float timetaken)
+{
+ destination = waypoint_fixorigin(destination);
+ waypoint_spawnforteleporter_boxes(e, e.absmin, e.absmax, destination, destination, timetaken);
+}
+
+entity waypoint_spawnpersonal(entity this, vector position)
+{
+ entity w;
+
+ // drop the waypoint to a proper location:
+ // first move it up by a player height
+ // then move it down to hit the floor with player bbox size
+ position = waypoint_fixorigin(position);
+
+ w = waypoint_spawn(position, position, WAYPOINTFLAG_GENERATED | WAYPOINTFLAG_PERSONAL);
+ w.nearestwaypoint = NULL;
+ w.nearestwaypointtimeout = 0;
+ w.owner = this;
+
+ waypoint_schedulerelink(w);
+
+ return w;
+}
+
+void botframe_showwaypointlinks()
+{
+ if (time < botframe_waypointeditorlightningtime)
+ return;
+ botframe_waypointeditorlightningtime = time + 0.5;
+ FOREACH_CLIENT(IS_PLAYER(it) && !it.isbot,
+ {
+ if(IS_ONGROUND(it) || it.waterlevel > WATERLEVEL_NONE)
+ {
+ //navigation_testtracewalk = true;
+ entity head = navigation_findnearestwaypoint(it, false);
+ // print("currently selected WP is ", etos(head), "\n");
+ //navigation_testtracewalk = false;
+ if (head)
+ {
+ entity w;
+ w = head ;if (w) te_lightning2(NULL, w.origin, it.origin);
+ w = head.wp00;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp01;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp02;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp03;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp04;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp05;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp06;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp07;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp08;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp09;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp10;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp11;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp12;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp13;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp14;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp15;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp16;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp17;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp18;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp19;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp20;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp21;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp22;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp23;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp24;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp25;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp26;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp27;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp28;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp29;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp30;if (w) te_lightning2(NULL, w.origin, head.origin);
+ w = head.wp31;if (w) te_lightning2(NULL, w.origin, head.origin);
+ }
+ }
+ });
+}
+
+float botframe_autowaypoints_fixdown(vector v)
+{
+ tracebox(v, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), v + '0 0 -64', MOVE_NOMONSTERS, NULL);
+ if(trace_fraction >= 1)
+ return 0;
+ return 1;
+}
+
+float botframe_autowaypoints_createwp(vector v, entity p, .entity fld, float f)
+{
+ IL_EACH(g_waypoints, boxesoverlap(v - '32 32 32', v + '32 32 32', it.absmin, it.absmax),
+ {
+ // if a matching spawnfunc_waypoint already exists, don't add a duplicate
+ return 0;
+ });
+
+ waypoint_schedulerelink(p.(fld) = waypoint_spawn(v, v, f));
+ return 1;
+}
+
+// return value:
+// 1 = WP created
+// 0 = no action needed
+// -1 = temp fail, try from world too
+// -2 = permanent fail, do not retry
+float botframe_autowaypoints_fix_from(entity p, float walkfromwp, entity wp, .entity fld)
+{
+ // make it possible to go from p to wp, if we can
+ // if wp is NULL, nearest is chosen
+
+ entity w;
+ vector porg;
+ float t, tmin, tmax;
+ vector o;
+ vector save;
+
+ if(!botframe_autowaypoints_fixdown(p.origin))
+ return -2;
+ porg = trace_endpos;
+
+ if(wp)
+ {
+ // if any WP w fulfills wp -> w -> porg and w is closer than wp, then switch from wp to w
+
+ // if wp -> porg, then OK
+ float maxdist;
+ if(navigation_waypoint_will_link(wp.origin, porg, p, walkfromwp, 1050))
+ {
+ // we may find a better one
+ maxdist = vlen(wp.origin - porg);
+ }
+ else
+ {
+ // accept any "good"
+ maxdist = 2100;
+ }
+
+ float bestdist = maxdist;
+ IL_EACH(g_waypoints, it != wp && !(it.wpflags & WAYPOINTFLAG_NORELINK),
+ {
+ float d = vlen(wp.origin - it.origin) + vlen(it.origin - porg);
+ if(d < bestdist)
+ if(navigation_waypoint_will_link(wp.origin, it.origin, p, walkfromwp, 1050))
+ if(navigation_waypoint_will_link(it.origin, porg, p, walkfromwp, 1050))
+ {
+ bestdist = d;
+ p.(fld) = it;
+ }
+ });
+ if(bestdist < maxdist)
+ {
+ LOG_INFO("update chain to new nearest WP ", etos(p.(fld)), "\n");
+ return 0;
+ }
+
+ if(bestdist < 2100)
+ {
+ // we know maxdist < 2100
+ // so wp -> porg is still valid
+ // all is good
+ p.(fld) = wp;
+ return 0;
+ }
+
+ // otherwise, no existing WP can fix our issues
+ }
+ else
+ {
+ save = p.origin;
+ setorigin(p, porg);
+ w = navigation_findnearestwaypoint(p, walkfromwp);
+ setorigin(p, save);
+ if(w)
+ {
+ p.(fld) = w;
+ return 0;
+ }
+ }
+
+ tmin = 0;
+ tmax = 1;
+ for (;;)
+ {
+ if(tmax - tmin < 0.001)
+ {
+ // did not get a good candidate
+ return -1;
+ }
+
+ t = (tmin + tmax) * 0.5;
+ o = antilag_takebackorigin(p, CS(p), time - t);
+ if(!botframe_autowaypoints_fixdown(o))
+ return -2;
+ o = trace_endpos;
+
+ if(wp)
+ {
+ if(!navigation_waypoint_will_link(wp.origin, o, p, walkfromwp, 1050))
+ {
+ // we cannot walk from wp.origin to o
+ // get closer to tmax
+ tmin = t;
+ continue;
+ }
+ }
+ else
+ {
+ save = p.origin;
+ setorigin(p, o);
+ w = navigation_findnearestwaypoint(p, walkfromwp);
+ setorigin(p, save);
+ if(!w)
+ {
+ // we cannot walk from any WP to o
+ // get closer to tmax
+ tmin = t;
+ continue;
+ }
+ }
+
+ // if we get here, o is valid regarding waypoints
+ // check if o is connected right to the player
+ // we break if it succeeds, as that means o is a good waypoint location
+ if(navigation_waypoint_will_link(o, porg, p, walkfromwp, 1050))
+ break;
+
+ // o is no good, we need to get closer to the player
+ tmax = t;
+ }
+
+ LOG_INFO("spawning a waypoint for connecting to ", etos(wp), "\n");
+ botframe_autowaypoints_createwp(o, p, fld, 0);
+ return 1;
+}
+
+// automatically create missing waypoints
+.entity botframe_autowaypoints_lastwp0, botframe_autowaypoints_lastwp1;
+void botframe_autowaypoints_fix(entity p, float walkfromwp, .entity fld)
+{
+ float r = botframe_autowaypoints_fix_from(p, walkfromwp, p.(fld), fld);
+ if(r != -1)
+ return;
+ r = botframe_autowaypoints_fix_from(p, walkfromwp, NULL, fld);
+ if(r != -1)
+ return;
+
+ LOG_INFO("emergency: got no good nearby WP to build a link from, starting a new chain\n");
+ if(!botframe_autowaypoints_fixdown(p.origin))
+ return; // shouldn't happen, caught above
+ botframe_autowaypoints_createwp(trace_endpos, p, fld, WAYPOINTFLAG_PROTECTED);
+}
+
+void botframe_deleteuselesswaypoints()
+{
+ FOREACH_ENTITY_FLOAT(bot_pickup, true,
+ {
+ // NOTE: this protects waypoints if they're the ONLY nearest
+ // waypoint. That's the intention.
+ navigation_findnearestwaypoint(it, false); // Walk TO item.
+ navigation_findnearestwaypoint(it, true); // Walk FROM item.
+ });
+ IL_EACH(g_waypoints, true,
+ {
+ it.wpflags |= WAYPOINTFLAG_DEAD_END;
+ it.wpflags &= ~WAYPOINTFLAG_USEFUL;
+ // WP is useful if:
+ if (it.wpflags & WAYPOINTFLAG_ITEM)
+ it.wpflags |= WAYPOINTFLAG_USEFUL;
+ if (it.wpflags & WAYPOINTFLAG_TELEPORT)
+ it.wpflags |= WAYPOINTFLAG_USEFUL;
+ if (it.wpflags & WAYPOINTFLAG_PROTECTED)
+ it.wpflags |= WAYPOINTFLAG_USEFUL;
+ // b) WP is closest WP for an item/spawnpoint/other entity
+ // This has been done above by protecting these WPs.
+ });
+ // c) There are w1, w, w2 so that w1 -> w, w -> w2 and not w1 -> w2.
+ IL_EACH(g_waypoints, !(it.wpflags & WAYPOINTFLAG_PERSONAL),
+ {
+ for (int m = 0; m < 32; ++m)
+ {
+ entity w = waypoint_get_link(it, m);
+ if (!w)
+ break;
+ if (w.wpflags & WAYPOINTFLAG_PERSONAL)
+ continue;
+ if (w.wpflags & WAYPOINTFLAG_USEFUL)
+ continue;
+ for (int j = 0; j < 32; ++j)
+ {
+ entity w2 = waypoint_get_link(w, j);
+ if (!w2)
+ break;
+ if (it == w2)
+ continue;
+ if (w2.wpflags & WAYPOINTFLAG_PERSONAL)
+ continue;
+ // If we got here, it != w2 exist with it -> w
+ // and w -> w2. That means the waypoint is not
+ // a dead end.
+ w.wpflags &= ~WAYPOINTFLAG_DEAD_END;
+ for (int k = 0; k < 32; ++k)
+ {
+ if (waypoint_get_link(it, k) == w2)
+ continue;
+ // IF WE GET HERE, w is proven useful
+ // to get from it to w2!
+ w.wpflags |= WAYPOINTFLAG_USEFUL;
+ goto next;
+ }
+ }
+LABEL(next)
+ }
+ });
+ // d) The waypoint is a dead end. Dead end waypoints must be kept as
+ // they are needed to complete routes while autowaypointing.
+
+ IL_EACH(g_waypoints, !(it.wpflags & (WAYPOINTFLAG_USEFUL | WAYPOINTFLAG_DEAD_END)),
+ {
+ LOG_INFOF("Removed a waypoint at %v. Try again for more!\n", it.origin);
+ te_explosion(it.origin);
+ waypoint_remove(it);
+ break;
+ });
+
+ IL_EACH(g_waypoints, true,
+ {
+ it.wpflags &= ~(WAYPOINTFLAG_USEFUL | WAYPOINTFLAG_DEAD_END); // temp flag
+ });
+}
+
+void botframe_autowaypoints()
+{
+ FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && !IS_DEAD(it), LAMBDA(
+ // going back is broken, so only fix waypoints to walk TO the player
+ //botframe_autowaypoints_fix(p, false, botframe_autowaypoints_lastwp0);
+ botframe_autowaypoints_fix(it, true, botframe_autowaypoints_lastwp1);
+ //te_explosion(p.botframe_autowaypoints_lastwp0.origin);
+ ));
+
+ if (autocvar_g_waypointeditor_auto >= 2) {
+ botframe_deleteuselesswaypoints();
+ }
+}
+
--- /dev/null
+#pragma once
+/*
+ * Globals and Fields
+ */
+
+// fields you can query using prvm_global server to get some statistics about waypoint linking culling
+float relink_total, relink_walkculled, relink_pvsculled, relink_lengthculled;
+
+float botframe_waypointeditorlightningtime;
+float botframe_loadedforcedlinks;
+float botframe_cachedwaypointlinks;
+
+.entity wp00, wp01, wp02, wp03, wp04, wp05, wp06, wp07, wp08, wp09, wp10, wp11, wp12, wp13, wp14, wp15;
+.entity wp16, wp17, wp18, wp19, wp20, wp21, wp22, wp23, wp24, wp25, wp26, wp27, wp28, wp29, wp30, wp31;
+
+// itemscore = (howmuchmoreIwant / howmuchIcanwant) / itemdistance
+.float wp00mincost, wp01mincost, wp02mincost, wp03mincost, wp04mincost, wp05mincost, wp06mincost, wp07mincost;
+.float wp08mincost, wp09mincost, wp10mincost, wp11mincost, wp12mincost, wp13mincost, wp14mincost, wp15mincost;
+.float wp16mincost, wp17mincost, wp18mincost, wp19mincost, wp20mincost, wp21mincost, wp22mincost, wp23mincost;
+.float wp24mincost, wp25mincost, wp26mincost, wp27mincost, wp28mincost, wp29mincost, wp30mincost, wp31mincost;
+
+.float wpfire, wpcost, wpconsidered, wpisbox, wplinked, wphardwired;
+.int wpflags;
+
+.vector wpnearestpoint;
+
+/*
+ * Functions
+ */
+
+spawnfunc(waypoint);
+void waypoint_addlink(entity from, entity to);
+void waypoint_think(entity this);
+void waypoint_clearlinks(entity wp);
+void waypoint_schedulerelink(entity wp);
+
+void waypoint_remove(entity e);
+void waypoint_removeall();
+void waypoint_schedulerelinkall();
+void waypoint_load_links_hardwired();
+void waypoint_save_links();
+void waypoint_saveall();
+
+void waypoint_spawnforitem_force(entity e, vector org);
+void waypoint_spawnforitem(entity e);
+void waypoint_spawnforteleporter(entity e, vector destination, float timetaken);
+void waypoint_spawnforteleporter_v(entity e, vector org, vector destination, float timetaken);
+void botframe_showwaypointlinks();
+
+float waypoint_loadall();
+float waypoint_load_links();
+
+entity waypoint_spawn(vector m1, vector m2, float f);
+entity waypoint_spawnpersonal(entity this, vector position);
+
+vector waypoint_fixorigin(vector position);
+
+void botframe_autowaypoints();
+++ /dev/null
-// generated file; do not modify
-#include <server/bot/havocbot/havocbot.qc>
-#include <server/bot/havocbot/roles.qc>
+++ /dev/null
-// generated file; do not modify
-#include <server/bot/havocbot/havocbot.qh>
-#include <server/bot/havocbot/roles.qh>
+++ /dev/null
-#include "havocbot.qh"
-
-#include "../aim.qh"
-#include "../bot.qh"
-#include "../navigation.qh"
-#include "../scripting.qh"
-#include "../waypoints.qh"
-
-#include <common/constants.qh>
-#include <common/physics/player.qh>
-#include <common/state.qh>
-#include <common/items/all.qh>
-
-#include <common/triggers/trigger/jumppads.qh>
-
-#include <lib/warpzone/common.qh>
-
-.float speed;
-
-void havocbot_ai(entity this)
-{
- if(this.draggedby)
- return;
-
- if(bot_execute_commands(this))
- return;
-
- if (bot_strategytoken == this)
- if (!bot_strategytoken_taken)
- {
- if(this.havocbot_blockhead)
- {
- this.havocbot_blockhead = false;
- }
- else
- {
- if (!this.jumppadcount)
- this.havocbot_role(this); // little too far down the rabbit hole
- }
-
- // TODO: tracewalk() should take care of this job (better path finding under water)
- // if we don't have a goal and we're under water look for a waypoint near the "shore" and push it
- if(IS_DEAD(this))
- if(!this.goalcurrent)
- if(this.waterlevel == WATERLEVEL_SWIMMING || (this.aistatus & AI_STATUS_OUT_WATER))
- {
- // Look for the closest waypoint out of water
- entity newgoal = NULL;
- IL_EACH(g_waypoints, vdist(it.origin - this.origin, <=, 10000),
- {
- if(it.origin.z < this.origin.z)
- continue;
-
- if(it.origin.z - this.origin.z - this.view_ofs.z > 100)
- continue;
-
- if (pointcontents(it.origin + it.maxs + '0 0 1') != CONTENT_EMPTY)
- continue;
-
- traceline(this.origin + this.view_ofs, ((it.absmin + it.absmax) * 0.5), true, this);
-
- if(trace_fraction < 1)
- continue;
-
- if(!newgoal || vlen2(it.origin - this.origin) < vlen2(newgoal.origin - this.origin))
- newgoal = it;
- });
-
- if(newgoal)
- {
- // te_wizspike(newgoal.origin);
- navigation_pushroute(this, newgoal);
- }
- }
-
- // token has been used this frame
- bot_strategytoken_taken = true;
- }
-
- if(IS_DEAD(this))
- return;
-
- havocbot_chooseenemy(this);
- if (this.bot_chooseweapontime < time )
- {
- this.bot_chooseweapontime = time + autocvar_bot_ai_chooseweaponinterval;
- havocbot_chooseweapon(this);
- }
- havocbot_aim(this);
- lag_update(this);
- if (this.bot_aimtarg)
- {
- this.aistatus |= AI_STATUS_ATTACKING;
- this.aistatus &= ~AI_STATUS_ROAMING;
-
- if(this.weapons)
- {
- Weapon w = PS(this).m_weapon;
- w.wr_aim(w, this);
- if (autocvar_bot_nofire || IS_INDEPENDENT_PLAYER(this))
- {
- PHYS_INPUT_BUTTON_ATCK(this) = false;
- PHYS_INPUT_BUTTON_ATCK2(this) = false;
- }
- else
- {
- if(PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_ATCK2(this))
- this.lastfiredweapon = PS(this).m_weapon.m_id;
- }
- }
- else
- {
- if(IS_PLAYER(this.bot_aimtarg))
- bot_aimdir(this, this.bot_aimtarg.origin + this.bot_aimtarg.view_ofs - this.origin - this.view_ofs , -1);
- }
- }
- else if (this.goalcurrent)
- {
- this.aistatus |= AI_STATUS_ROAMING;
- this.aistatus &= ~AI_STATUS_ATTACKING;
-
- vector now,v,next;//,heading;
- float aimdistance,skillblend,distanceblend,blend;
- next = now = ( (this.goalcurrent.absmin + this.goalcurrent.absmax) * 0.5) - (this.origin + this.view_ofs);
- aimdistance = vlen(now);
- //heading = this.velocity;
- //dprint(this.goalstack01.classname,etos(this.goalstack01),"\n");
- if(
- this.goalstack01 != this && this.goalstack01 != NULL && ((this.aistatus & AI_STATUS_RUNNING) == 0) &&
- !(this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT)
- )
- next = ((this.goalstack01.absmin + this.goalstack01.absmax) * 0.5) - (this.origin + this.view_ofs);
-
- skillblend=bound(0,(skill+this.bot_moveskill-2.5)*0.5,1); //lower skill player can't preturn
- distanceblend=bound(0,aimdistance/autocvar_bot_ai_keyboard_distance,1);
- blend = skillblend * (1-distanceblend);
- //v = (now * (distanceblend) + next * (1-distanceblend)) * (skillblend) + now * (1-skillblend);
- //v = now * (distanceblend) * (skillblend) + next * (1-distanceblend) * (skillblend) + now * (1-skillblend);
- //v = now * ((1-skillblend) + (distanceblend) * (skillblend)) + next * (1-distanceblend) * (skillblend);
- v = now + blend * (next - now);
- //dprint(etos(this), " ");
- //dprint(vtos(now), ":", vtos(next), "=", vtos(v), " (blend ", ftos(blend), ")\n");
- //v = now * (distanceblend) + next * (1-distanceblend);
- if (this.waterlevel < WATERLEVEL_SWIMMING)
- v.z = 0;
- //dprint("walk at:", vtos(v), "\n");
- //te_lightning2(NULL, this.origin, this.goalcurrent.origin);
- bot_aimdir(this, v, -1);
- }
- havocbot_movetogoal(this);
-
- // if the bot is not attacking, consider reloading weapons
- if (!(this.aistatus & AI_STATUS_ATTACKING))
- {
- // we are currently holding a weapon that's not fully loaded, reload it
- if(skill >= 2) // bots can only reload the held weapon on purpose past this skill
- if(this.clip_load < this.clip_size)
- this.impulse = 20; // "press" the reload button, not sure if this is done right
-
- // if we're not reloading a weapon, switch to any weapon in our invnetory that's not fully loaded to reload it next
- // the code above executes next frame, starting the reloading then
- if(skill >= 5) // bots can only look for unloaded weapons past this skill
- if(this.clip_load >= 0) // only if we're not reloading a weapon already
- {
- FOREACH(Weapons, it != WEP_Null, LAMBDA(
- if((this.weapons & (it.m_wepset)) && (it.spawnflags & WEP_FLAG_RELOADABLE) && (this.weapon_load[it.m_id] < it.reloading_ammo))
- PS(this).m_switchweapon = it;
- ));
- }
- }
-}
-
-void havocbot_keyboard_movement(entity this, vector destorg)
-{
- vector keyboard;
- float blend, maxspeed;
- float sk;
-
- sk = skill + this.bot_moveskill;
-
- maxspeed = autocvar_sv_maxspeed;
-
- if (time < this.havocbot_keyboardtime)
- return;
-
- this.havocbot_keyboardtime =
- max(
- this.havocbot_keyboardtime
- + 0.05/max(1, sk+this.havocbot_keyboardskill)
- + random()*0.025/max(0.00025, skill+this.havocbot_keyboardskill)
- , time);
- keyboard = this.movement * (1.0 / maxspeed);
-
- float trigger, trigger1;
- blend = bound(0,sk*0.1,1);
- trigger = autocvar_bot_ai_keyboard_threshold;
- trigger1 = 0 - trigger;
-
- // categorize forward movement
- // at skill < 1.5 only forward
- // at skill < 2.5 only individual directions
- // at skill < 4.5 only individual directions, and forward diagonals
- // at skill >= 4.5, all cases allowed
- if (keyboard.x > trigger)
- {
- keyboard.x = 1;
- if (sk < 2.5)
- keyboard.y = 0;
- }
- else if (keyboard.x < trigger1 && sk > 1.5)
- {
- keyboard.x = -1;
- if (sk < 4.5)
- keyboard.y = 0;
- }
- else
- {
- keyboard.x = 0;
- if (sk < 1.5)
- keyboard.y = 0;
- }
- if (sk < 4.5)
- keyboard.z = 0;
-
- if (keyboard.y > trigger)
- keyboard.y = 1;
- else if (keyboard.y < trigger1)
- keyboard.y = -1;
- else
- keyboard.y = 0;
-
- if (keyboard.z > trigger)
- keyboard.z = 1;
- else if (keyboard.z < trigger1)
- keyboard.z = -1;
- else
- keyboard.z = 0;
-
- this.havocbot_keyboard = keyboard * maxspeed;
- if (this.havocbot_ducktime>time) PHYS_INPUT_BUTTON_CROUCH(this) = true;
-
- keyboard = this.havocbot_keyboard;
- blend = bound(0,vlen(destorg-this.origin)/autocvar_bot_ai_keyboard_distance,1); // When getting close move with 360 degree
- //dprint("movement ", vtos(this.movement), " keyboard ", vtos(keyboard), " blend ", ftos(blend), "\n");
- this.movement = this.movement + (keyboard - this.movement) * blend;
-}
-
-void havocbot_bunnyhop(entity this, vector dir)
-{
- float bunnyhopdistance;
- vector deviation;
- float maxspeed;
- vector gco, gno;
-
- // Don't jump when attacking
- if(this.aistatus & AI_STATUS_ATTACKING)
- return;
-
- if(IS_PLAYER(this.goalcurrent))
- return;
-
- maxspeed = autocvar_sv_maxspeed;
-
- if(this.aistatus & AI_STATUS_DANGER_AHEAD)
- {
- this.aistatus &= ~AI_STATUS_RUNNING;
- PHYS_INPUT_BUTTON_JUMP(this) = false;
- this.bot_canruntogoal = 0;
- this.bot_timelastseengoal = 0;
- return;
- }
-
- if(this.waterlevel > WATERLEVEL_WETFEET)
- {
- this.aistatus &= ~AI_STATUS_RUNNING;
- return;
- }
-
- if(this.bot_lastseengoal != this.goalcurrent && !(this.aistatus & AI_STATUS_RUNNING))
- {
- this.bot_canruntogoal = 0;
- this.bot_timelastseengoal = 0;
- }
-
- gco = (this.goalcurrent.absmin + this.goalcurrent.absmax) * 0.5;
- bunnyhopdistance = vlen(this.origin - gco);
-
- // Run only to visible goals
- if(IS_ONGROUND(this))
- if(this.speed==maxspeed)
- if(checkpvs(this.origin + this.view_ofs, this.goalcurrent))
- {
- this.bot_lastseengoal = this.goalcurrent;
-
- // seen it before
- if(this.bot_timelastseengoal)
- {
- // for a period of time
- if(time - this.bot_timelastseengoal > autocvar_bot_ai_bunnyhop_firstjumpdelay)
- {
- float checkdistance;
- checkdistance = true;
-
- // don't run if it is too close
- if(this.bot_canruntogoal==0)
- {
- if(bunnyhopdistance > autocvar_bot_ai_bunnyhop_startdistance)
- this.bot_canruntogoal = 1;
- else
- this.bot_canruntogoal = -1;
- }
-
- if(this.bot_canruntogoal != 1)
- return;
-
- if(this.aistatus & AI_STATUS_ROAMING)
- if(this.goalcurrent.classname=="waypoint")
- if (!(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL))
- if(fabs(gco.z - this.origin.z) < this.maxs.z - this.mins.z)
- if(this.goalstack01!=NULL)
- {
- gno = (this.goalstack01.absmin + this.goalstack01.absmax) * 0.5;
- deviation = vectoangles(gno - this.origin) - vectoangles(gco - this.origin);
- while (deviation.y < -180) deviation.y = deviation.y + 360;
- while (deviation.y > 180) deviation.y = deviation.y - 360;
-
- if(fabs(deviation.y) < 20)
- if(bunnyhopdistance < vlen(this.origin - gno))
- if(fabs(gno.z - gco.z) < this.maxs.z - this.mins.z)
- {
- if(vdist(gco - gno, >, autocvar_bot_ai_bunnyhop_startdistance))
- if(checkpvs(this.origin + this.view_ofs, this.goalstack01))
- {
- checkdistance = false;
- }
- }
- }
-
- if(checkdistance)
- {
- this.aistatus &= ~AI_STATUS_RUNNING;
- if(bunnyhopdistance > autocvar_bot_ai_bunnyhop_stopdistance)
- PHYS_INPUT_BUTTON_JUMP(this) = true;
- }
- else
- {
- this.aistatus |= AI_STATUS_RUNNING;
- PHYS_INPUT_BUTTON_JUMP(this) = true;
- }
- }
- }
- else
- {
- this.bot_timelastseengoal = time;
- }
- }
- else
- {
- this.bot_timelastseengoal = 0;
- }
-
-#if 0
- // Release jump button
- if(!cvar("sv_pogostick"))
- if((IS_ONGROUND(this)) == 0)
- {
- if(this.velocity.z < 0 || vlen(this.velocity)<maxspeed)
- PHYS_INPUT_BUTTON_JUMP(this) = false;
-
- // Strafe
- if(this.aistatus & AI_STATUS_RUNNING)
- if(vlen(this.velocity)>maxspeed)
- {
- deviation = vectoangles(dir) - vectoangles(this.velocity);
- while (deviation.y < -180) deviation.y = deviation.y + 360;
- while (deviation.y > 180) deviation.y = deviation.y - 360;
-
- if(fabs(deviation.y)>10)
- this.movement_x = 0;
-
- if(deviation.y>10)
- this.movement_y = maxspeed * -1;
- else if(deviation.y<10)
- this.movement_y = maxspeed;
-
- }
- }
-#endif
-}
-
-void havocbot_movetogoal(entity this)
-{
- vector destorg;
- vector diff;
- vector dir;
- vector flatdir;
- vector m1;
- vector m2;
- vector evadeobstacle;
- vector evadelava;
- float s;
- float maxspeed;
- vector gco;
- //float dist;
- vector dodge;
- //if (this.goalentity)
- // te_lightning2(this, this.origin, (this.goalentity.absmin + this.goalentity.absmax) * 0.5);
- this.movement = '0 0 0';
- maxspeed = autocvar_sv_maxspeed;
-
- // Jetpack navigation
- if(this.goalcurrent)
- if(this.navigation_jetpack_goal)
- if(this.goalcurrent==this.navigation_jetpack_goal)
- if(this.ammo_fuel)
- {
- if(autocvar_bot_debug_goalstack)
- {
- debuggoalstack(this);
- te_wizspike(this.navigation_jetpack_point);
- }
-
- // Take off
- if (!(this.aistatus & AI_STATUS_JETPACK_FLYING))
- {
- // Brake almost completely so it can get a good direction
- if(vdist(this.velocity, >, 10))
- return;
- this.aistatus |= AI_STATUS_JETPACK_FLYING;
- }
-
- makevectors(this.v_angle.y * '0 1 0');
- dir = normalize(this.navigation_jetpack_point - this.origin);
-
- // Landing
- if(this.aistatus & AI_STATUS_JETPACK_LANDING)
- {
- // Calculate brake distance in xy
- float db, v, d;
- vector dxy;
-
- dxy = this.origin - ( ( this.goalcurrent.absmin + this.goalcurrent.absmax ) * 0.5 ); dxy.z = 0;
- d = vlen(dxy);
- v = vlen(this.velocity - this.velocity.z * '0 0 1');
- db = (pow(v,2) / (autocvar_g_jetpack_acceleration_side * 2)) + 100;
- // dprint("distance ", ftos(ceil(d)), " velocity ", ftos(ceil(v)), " brake at ", ftos(ceil(db)), "\n");
- if(d < db || d < 500)
- {
- // Brake
- if(fabs(this.velocity.x)>maxspeed*0.3)
- {
- this.movement_x = dir * v_forward * -maxspeed;
- return;
- }
- // Switch to normal mode
- this.navigation_jetpack_goal = NULL;
- this.aistatus &= ~AI_STATUS_JETPACK_LANDING;
- this.aistatus &= ~AI_STATUS_JETPACK_FLYING;
- return;
- }
- }
- else if(checkpvs(this.origin,this.goalcurrent))
- {
- // If I can see the goal switch to landing code
- this.aistatus &= ~AI_STATUS_JETPACK_FLYING;
- this.aistatus |= AI_STATUS_JETPACK_LANDING;
- return;
- }
-
- // Flying
- PHYS_INPUT_BUTTON_HOOK(this) = true;
- if(this.navigation_jetpack_point.z - STAT(PL_MAX, NULL).z + STAT(PL_MIN, NULL).z < this.origin.z)
- {
- this.movement_x = dir * v_forward * maxspeed;
- this.movement_y = dir * v_right * maxspeed;
- }
- return;
- }
-
- // Handling of jump pads
- if(this.jumppadcount)
- {
- // If got stuck on the jump pad try to reach the farthest visible waypoint
- if(this.aistatus & AI_STATUS_OUT_JUMPPAD)
- {
- if(fabs(this.velocity.z)<50)
- {
- entity newgoal = NULL;
- IL_EACH(g_waypoints, vdist(it.origin - this.origin, <=, 1000),
- {
- traceline(this.origin + this.view_ofs, ((it.absmin + it.absmax) * 0.5), true, this);
-
- if(trace_fraction < 1)
- continue;
-
- if(!newgoal || vlen2(it.origin - this.origin) > vlen2(newgoal.origin - this.origin))
- newgoal = it;
- });
-
- if(newgoal)
- {
- this.ignoregoal = this.goalcurrent;
- this.ignoregoaltime = time + autocvar_bot_ai_ignoregoal_timeout;
- navigation_clearroute(this);
- navigation_routetogoal(this, newgoal, this.origin);
- this.aistatus &= ~AI_STATUS_OUT_JUMPPAD;
- }
- }
- else
- return;
- }
- else
- {
- if(this.velocity.z>0)
- {
- float threshold;
- vector velxy = this.velocity; velxy_z = 0;
- threshold = maxspeed * 0.2;
- if(vdist(velxy, <, threshold))
- {
- LOG_TRACE("Warning: ", this.netname, " got stuck on a jumppad (velocity in xy is ", vtos(velxy), "), trying to get out of it now\n");
- this.aistatus |= AI_STATUS_OUT_JUMPPAD;
- }
- return;
- }
-
- // Don't chase players while using a jump pad
- if(IS_PLAYER(this.goalcurrent) || IS_PLAYER(this.goalstack01))
- return;
- }
- }
- else if(this.aistatus & AI_STATUS_OUT_JUMPPAD)
- this.aistatus &= ~AI_STATUS_OUT_JUMPPAD;
-
- // If there is a trigger_hurt right below try to use the jetpack or make a rocketjump
- if(skill>6)
- if (!(IS_ONGROUND(this)))
- {
- tracebox(this.origin, this.mins, this.maxs, this.origin + '0 0 -65536', MOVE_NOMONSTERS, this);
- if(tracebox_hits_trigger_hurt(this.origin, this.mins, this.maxs, trace_endpos ))
- if(this.items & IT_JETPACK)
- {
- tracebox(this.origin, this.mins, this.maxs, this.origin + '0 0 65536', MOVE_NOMONSTERS, this);
- if(tracebox_hits_trigger_hurt(this.origin, this.mins, this.maxs, trace_endpos + '0 0 1' ))
- {
- if(this.velocity.z<0)
- {
- PHYS_INPUT_BUTTON_HOOK(this) = true;
- }
- }
- else
- PHYS_INPUT_BUTTON_HOOK(this) = true;
-
- // If there is no goal try to move forward
-
- if(this.goalcurrent==NULL)
- dir = v_forward;
- else
- dir = normalize(( ( this.goalcurrent.absmin + this.goalcurrent.absmax ) * 0.5 ) - this.origin);
-
- vector xyvelocity = this.velocity; xyvelocity_z = 0;
- float xyspeed = xyvelocity * dir;
-
- if(xyspeed < (maxspeed / 2))
- {
- makevectors(this.v_angle.y * '0 1 0');
- tracebox(this.origin, this.mins, this.maxs, this.origin + (dir * maxspeed * 3), MOVE_NOMONSTERS, this);
- if(trace_fraction==1)
- {
- this.movement_x = dir * v_forward * maxspeed;
- this.movement_y = dir * v_right * maxspeed;
- if (skill < 10)
- havocbot_keyboard_movement(this, this.origin + dir * 100);
- }
- }
-
- this.havocbot_blockhead = true;
-
- return;
- }
- else if(this.health>WEP_CVAR(devastator, damage)*0.5)
- {
- if(this.velocity.z < 0)
- if(client_hasweapon(this, WEP_DEVASTATOR, true, false))
- {
- this.movement_x = maxspeed;
-
- if(this.rocketjumptime)
- {
- if(time > this.rocketjumptime)
- {
- PHYS_INPUT_BUTTON_ATCK2(this) = true;
- this.rocketjumptime = 0;
- }
- return;
- }
-
- PS(this).m_switchweapon = WEP_DEVASTATOR;
- this.v_angle_x = 90;
- PHYS_INPUT_BUTTON_ATCK(this) = true;
- this.rocketjumptime = time + WEP_CVAR(devastator, detonatedelay);
- return;
- }
- }
- else
- {
- // If there is no goal try to move forward
- if(this.goalcurrent==NULL)
- this.movement_x = maxspeed;
- }
- }
-
- // If we are under water with no goals, swim up
- if(this.waterlevel)
- if(this.goalcurrent==NULL)
- {
- dir = '0 0 0';
- if(this.waterlevel>WATERLEVEL_SWIMMING)
- dir.z = 1;
- else if(this.velocity.z >= 0 && !(this.waterlevel == WATERLEVEL_WETFEET && this.watertype == CONTENT_WATER))
- PHYS_INPUT_BUTTON_JUMP(this) = true;
- else
- PHYS_INPUT_BUTTON_JUMP(this) = false;
- makevectors(this.v_angle.y * '0 1 0');
- this.movement_x = dir * v_forward * maxspeed;
- this.movement_y = dir * v_right * maxspeed;
- this.movement_z = dir * v_up * maxspeed;
- }
-
- // if there is nowhere to go, exit
- if (this.goalcurrent == NULL)
- return;
-
- if (this.goalcurrent)
- navigation_poptouchedgoals(this);
-
- // if ran out of goals try to use an alternative goal or get a new strategy asap
- if(this.goalcurrent == NULL)
- {
- this.bot_strategytime = 0;
- return;
- }
-
-
- if(autocvar_bot_debug_goalstack)
- debuggoalstack(this);
-
- m1 = this.goalcurrent.origin + this.goalcurrent.mins;
- m2 = this.goalcurrent.origin + this.goalcurrent.maxs;
- destorg = this.origin;
- destorg.x = bound(m1_x, destorg.x, m2_x);
- destorg.y = bound(m1_y, destorg.y, m2_y);
- destorg.z = bound(m1_z, destorg.z, m2_z);
- diff = destorg - this.origin;
- //dist = vlen(diff);
- dir = normalize(diff);
- flatdir = diff;flatdir.z = 0;
- flatdir = normalize(flatdir);
- gco = (this.goalcurrent.absmin + this.goalcurrent.absmax) * 0.5;
-
- //if (this.bot_dodgevector_time < time)
- {
- // this.bot_dodgevector_time = time + cvar("bot_ai_dodgeupdateinterval");
- // this.bot_dodgevector_jumpbutton = 1;
- evadeobstacle = '0 0 0';
- evadelava = '0 0 0';
-
- if (this.waterlevel)
- {
- if(this.waterlevel>WATERLEVEL_SWIMMING)
- {
- // flatdir_z = 1;
- this.aistatus |= AI_STATUS_OUT_WATER;
- }
- else
- {
- if(this.velocity.z >= 0 && !(this.watertype == CONTENT_WATER && gco.z < this.origin.z) &&
- ( !(this.waterlevel == WATERLEVEL_WETFEET && this.watertype == CONTENT_WATER) || this.aistatus & AI_STATUS_OUT_WATER))
- PHYS_INPUT_BUTTON_JUMP(this) = true;
- else
- PHYS_INPUT_BUTTON_JUMP(this) = false;
- }
- dir = normalize(flatdir);
- makevectors(this.v_angle.y * '0 1 0');
- }
- else
- {
- if(this.aistatus & AI_STATUS_OUT_WATER)
- this.aistatus &= ~AI_STATUS_OUT_WATER;
-
- // jump if going toward an obstacle that doesn't look like stairs we
- // can walk up directly
- tracebox(this.origin, this.mins, this.maxs, this.origin + this.velocity * 0.2, false, this);
- if (trace_fraction < 1)
- if (trace_plane_normal.z < 0.7)
- {
- s = trace_fraction;
- tracebox(this.origin + stepheightvec, this.mins, this.maxs, this.origin + this.velocity * 0.2 + stepheightvec, false, this);
- if (trace_fraction < s + 0.01)
- if (trace_plane_normal.z < 0.7)
- {
- s = trace_fraction;
- tracebox(this.origin + jumpstepheightvec, this.mins, this.maxs, this.origin + this.velocity * 0.2 + jumpstepheightvec, false, this);
- if (trace_fraction > s)
- PHYS_INPUT_BUTTON_JUMP(this) = true;
- }
- }
-
- // avoiding dangers and obstacles
- vector dst_ahead, dst_down;
- makevectors(this.v_angle.y * '0 1 0');
- dst_ahead = this.origin + this.view_ofs + (this.velocity * 0.4) + (v_forward * 32 * 3);
- dst_down = dst_ahead - '0 0 1500';
-
- // Look ahead
- traceline(this.origin + this.view_ofs, dst_ahead, true, NULL);
-
- // Check head-banging against walls
- if(vdist(this.origin + this.view_ofs - trace_endpos, <, 25) && !(this.aistatus & AI_STATUS_OUT_WATER))
- {
- PHYS_INPUT_BUTTON_JUMP(this) = true;
- if(this.facingwalltime && time > this.facingwalltime)
- {
- this.ignoregoal = this.goalcurrent;
- this.ignoregoaltime = time + autocvar_bot_ai_ignoregoal_timeout;
- this.bot_strategytime = 0;
- return;
- }
- else
- {
- this.facingwalltime = time + 0.05;
- }
- }
- else
- {
- this.facingwalltime = 0;
-
- if(this.ignoregoal != NULL && time > this.ignoregoaltime)
- {
- this.ignoregoal = NULL;
- this.ignoregoaltime = 0;
- }
- }
-
- // Check for water/slime/lava and dangerous edges
- // (only when the bot is on the ground or jumping intentionally)
- this.aistatus &= ~AI_STATUS_DANGER_AHEAD;
-
- if(trace_fraction == 1 && this.jumppadcount == 0 && !this.goalcurrent.wphardwired )
- if((IS_ONGROUND(this)) || (this.aistatus & AI_STATUS_RUNNING) || PHYS_INPUT_BUTTON_JUMP(this))
- {
- // Look downwards
- traceline(dst_ahead , dst_down, true, NULL);
- // te_lightning2(NULL, this.origin, dst_ahead); // Draw "ahead" look
- // te_lightning2(NULL, dst_ahead, dst_down); // Draw "downwards" look
- if(trace_endpos.z < this.origin.z + this.mins.z)
- {
- s = pointcontents(trace_endpos + '0 0 1');
- if (s != CONTENT_SOLID)
- if (s == CONTENT_LAVA || s == CONTENT_SLIME)
- evadelava = normalize(this.velocity) * -1;
- else if (s == CONTENT_SKY)
- evadeobstacle = normalize(this.velocity) * -1;
- else if (!boxesoverlap(dst_ahead - this.view_ofs + this.mins, dst_ahead - this.view_ofs + this.maxs,
- this.goalcurrent.absmin, this.goalcurrent.absmax))
- {
- // if ain't a safe goal with "holes" (like the jumpad on soylent)
- // and there is a trigger_hurt below
- if(tracebox_hits_trigger_hurt(dst_ahead, this.mins, this.maxs, trace_endpos))
- {
- // Remove dangerous dynamic goals from stack
- LOG_TRACE("bot ", this.netname, " avoided the goal ", this.goalcurrent.classname, " ", etos(this.goalcurrent), " because it led to a dangerous path; goal stack cleared\n");
- navigation_clearroute(this);
- return;
- }
- }
- }
- }
-
- dir = flatdir;
- evadeobstacle.z = 0;
- evadelava.z = 0;
- makevectors(this.v_angle.y * '0 1 0');
-
- if(evadeobstacle!='0 0 0'||evadelava!='0 0 0')
- this.aistatus |= AI_STATUS_DANGER_AHEAD;
- }
-
- dodge = havocbot_dodge(this);
- dodge = dodge * bound(0,0.5+(skill+this.bot_dodgeskill)*0.1,1);
- evadelava = evadelava * bound(1,3-(skill+this.bot_dodgeskill),3); //Noobs fear lava a lot and take more distance from it
- traceline(this.origin, ( ( this.enemy.absmin + this.enemy.absmax ) * 0.5 ), true, NULL);
- if(IS_PLAYER(trace_ent))
- dir = dir * bound(0,(skill+this.bot_dodgeskill)/7,1);
-
- dir = normalize(dir + dodge + evadeobstacle + evadelava);
- // this.bot_dodgevector = dir;
- // this.bot_dodgevector_jumpbutton = PHYS_INPUT_BUTTON_JUMP(this);
- }
-
- if(time < this.ladder_time)
- {
- if(this.goalcurrent.origin.z + this.goalcurrent.mins.z > this.origin.z + this.mins.z)
- {
- if(this.origin.z + this.mins.z < this.ladder_entity.origin.z + this.ladder_entity.maxs.z)
- dir.z = 1;
- }
- else
- {
- if(this.origin.z + this.mins.z > this.ladder_entity.origin.z + this.ladder_entity.mins.z)
- dir.z = -1;
- }
- }
-
- //dir = this.bot_dodgevector;
- //if (this.bot_dodgevector_jumpbutton)
- // PHYS_INPUT_BUTTON_JUMP(this) = true;
- this.movement_x = dir * v_forward * maxspeed;
- this.movement_y = dir * v_right * maxspeed;
- this.movement_z = dir * v_up * maxspeed;
-
- // Emulate keyboard interface
- if (skill < 10)
- havocbot_keyboard_movement(this, destorg);
-
- // Bunnyhop!
-// if(this.aistatus & AI_STATUS_ROAMING)
- if(this.goalcurrent)
- if(skill+this.bot_moveskill >= autocvar_bot_ai_bunnyhop_skilloffset)
- havocbot_bunnyhop(this, dir);
-
- if ((dir * v_up) >= autocvar_sv_jumpvelocity*0.5 && (IS_ONGROUND(this))) PHYS_INPUT_BUTTON_JUMP(this) = true;
- if (((dodge * v_up) > 0) && random()*frametime >= 0.2*bound(0,(10-skill-this.bot_dodgeskill)*0.1,1)) PHYS_INPUT_BUTTON_JUMP(this) = true;
- if (((dodge * v_up) < 0) && random()*frametime >= 0.5*bound(0,(10-skill-this.bot_dodgeskill)*0.1,1)) this.havocbot_ducktime=time+0.3/bound(0.1,skill+this.bot_dodgeskill,10);
-}
-
-void havocbot_chooseenemy(entity this)
-{
- entity head, best, head2;
- float rating, bestrating, hf;
- vector eye, v;
- if (autocvar_bot_nofire || IS_INDEPENDENT_PLAYER(this))
- {
- this.enemy = NULL;
- return;
- }
- if (this.enemy)
- {
- if (!bot_shouldattack(this, this.enemy))
- {
- // enemy died or something, find a new target
- this.enemy = NULL;
- this.havocbot_chooseenemy_finished = time;
- }
- else if (this.havocbot_stickenemy)
- {
- // tracking last chosen enemy
- // if enemy is visible
- // and not really really far away
- // and we're not severely injured
- // then keep tracking for a half second into the future
- traceline(this.origin+this.view_ofs, ( this.enemy.absmin + this.enemy.absmax ) * 0.5,false,NULL);
- if (trace_ent == this.enemy || trace_fraction == 1)
- if (vdist(((this.enemy.absmin + this.enemy.absmax) * 0.5) - this.origin, <, 1000))
- if (this.health > 30)
- {
- // remain tracking him for a shot while (case he went after a small corner or pilar
- this.havocbot_chooseenemy_finished = time + 0.5;
- return;
- }
- // enemy isn't visible, or is far away, or we're injured severely
- // so stop preferring this enemy
- // (it will still take a half second until a new one is chosen)
- this.havocbot_stickenemy = 0;
- }
- }
- if (time < this.havocbot_chooseenemy_finished)
- return;
- this.havocbot_chooseenemy_finished = time + autocvar_bot_ai_enemydetectioninterval;
- eye = this.origin + this.view_ofs;
- best = NULL;
- bestrating = 100000000;
- head = head2 = findchainfloat(bot_attack, true);
-
- // Backup hit flags
- hf = this.dphitcontentsmask;
-
- // Search for enemies, if no enemy can be seen directly try to look through transparent objects
-
- this.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
-
- bool scan_transparent = false;
- bool scan_secondary_targets = false;
- bool have_secondary_targets = false;
- while(true)
- {
- scan_secondary_targets = false;
-LABEL(scan_targets)
- for( ; head; head = head.chain)
- {
- if(!scan_secondary_targets)
- {
- if(head.classname == "misc_breakablemodel")
- {
- have_secondary_targets = true;
- continue;
- }
- }
- else
- {
- if(head.classname != "misc_breakablemodel")
- continue;
- }
-
- v = (head.absmin + head.absmax) * 0.5;
- rating = vlen(v - eye);
- if (rating<autocvar_bot_ai_enemydetectionradius)
- if (bestrating > rating)
- if (bot_shouldattack(this, head))
- {
- traceline(eye, v, true, this);
- if (trace_ent == head || trace_fraction >= 1)
- {
- best = head;
- bestrating = rating;
- }
- }
- }
-
- if(!best && have_secondary_targets && !scan_secondary_targets)
- {
- scan_secondary_targets = true;
- // restart the loop
- head = head2;
- bestrating = 100000000;
- goto scan_targets;
- }
-
- // I want to do a second scan if no enemy was found or I don't have weapons
- // TODO: Perform the scan when using the rifle (requires changes on the rifle code)
- if(best || this.weapons) // || this.weapon == WEP_RIFLE.m_id
- break;
- if(scan_transparent)
- break;
-
- // Set flags to see through transparent objects
- this.dphitcontentsmask |= DPCONTENTS_OPAQUE;
-
- head = head2;
- scan_transparent = true;
- }
-
- // Restore hit flags
- this.dphitcontentsmask = hf;
-
- this.enemy = best;
- this.havocbot_stickenemy = true;
- if(best && best.classname == "misc_breakablemodel")
- this.havocbot_stickenemy = false;
-}
-
-float havocbot_chooseweapon_checkreload(entity this, int new_weapon)
-{
- // bots under this skill cannot find unloaded weapons to reload idly when not in combat,
- // so skip this for them, or they'll never get to reload their weapons at all.
- // this also allows bots under this skill to be more stupid, and reload more often during combat :)
- if(skill < 5)
- return false;
-
- // if this weapon is scheduled for reloading, don't switch to it during combat
- if (this.weapon_load[new_weapon] < 0)
- {
- bool other_weapon_available = false;
- FOREACH(Weapons, it != WEP_Null, LAMBDA(
- if(it.wr_checkammo1(it, this) + it.wr_checkammo2(it, this))
- other_weapon_available = true;
- ));
- if(other_weapon_available)
- return true;
- }
-
- return false;
-}
-
-void havocbot_chooseweapon(entity this)
-{
- int i;
-
- // ;)
- if(g_weaponarena_weapons == WEPSET(TUBA))
- {
- PS(this).m_switchweapon = WEP_TUBA;
- return;
- }
-
- // TODO: clean this up by moving it to weapon code
- if(this.enemy==NULL)
- {
- // If no weapon was chosen get the first available weapon
- if(PS(this).m_weapon==WEP_Null)
- FOREACH(Weapons, it != WEP_Null, LAMBDA(
- if(client_hasweapon(this, it, true, false))
- {
- PS(this).m_switchweapon = it;
- return;
- }
- ));
- return;
- }
-
- // Do not change weapon during the next second after a combo
- float f = time - this.lastcombotime;
- if(f < 1)
- return;
-
- float w;
- float distance; distance=bound(10,vlen(this.origin-this.enemy.origin)-200,10000);
-
- // Should it do a weapon combo?
- float af, ct, combo_time, combo;
-
- af = ATTACK_FINISHED(this, 0);
- ct = autocvar_bot_ai_weapon_combo_threshold;
-
- // Bots with no skill will be 4 times more slower than "godlike" bots when doing weapon combos
- // Ideally this 4 should be calculated as longest_weapon_refire / bot_ai_weapon_combo_threshold
- combo_time = time + ct + (ct * ((-0.3*(skill+this.bot_weaponskill))+3));
-
- combo = false;
-
- if(autocvar_bot_ai_weapon_combo)
- if(PS(this).m_weapon.m_id == this.lastfiredweapon)
- if(af > combo_time)
- {
- combo = true;
- this.lastcombotime = time;
- }
-
- distance *= pow(2, this.bot_rangepreference);
-
- // Custom weapon list based on distance to the enemy
- if(bot_custom_weapon){
-
- // Choose weapons for far distance
- if ( distance > bot_distance_far ) {
- for(i=0; i < Weapons_COUNT && bot_weapons_far[i] != -1 ; ++i){
- w = bot_weapons_far[i];
- if ( client_hasweapon(this, Weapons_from(w), true, false) )
- {
- if ((PS(this).m_weapon.m_id == w && combo) || havocbot_chooseweapon_checkreload(this, w))
- continue;
- PS(this).m_switchweapon = Weapons_from(w);
- return;
- }
- }
- }
-
- // Choose weapons for mid distance
- if ( distance > bot_distance_close) {
- for(i=0; i < Weapons_COUNT && bot_weapons_mid[i] != -1 ; ++i){
- w = bot_weapons_mid[i];
- if ( client_hasweapon(this, Weapons_from(w), true, false) )
- {
- if ((PS(this).m_weapon.m_id == w && combo) || havocbot_chooseweapon_checkreload(this, w))
- continue;
- PS(this).m_switchweapon = Weapons_from(w);
- return;
- }
- }
- }
-
- // Choose weapons for close distance
- for(i=0; i < Weapons_COUNT && bot_weapons_close[i] != -1 ; ++i){
- w = bot_weapons_close[i];
- if ( client_hasweapon(this, Weapons_from(w), true, false) )
- {
- if ((PS(this).m_weapon.m_id == w && combo) || havocbot_chooseweapon_checkreload(this, w))
- continue;
- PS(this).m_switchweapon = Weapons_from(w);
- return;
- }
- }
- }
-}
-
-void havocbot_aim(entity this)
-{
- vector myvel, enemyvel;
-// if(this.flags & FL_INWATER)
-// return;
- if (time < this.nextaim)
- return;
- this.nextaim = time + 0.1;
- myvel = this.velocity;
- if (!this.waterlevel)
- myvel.z = 0;
- if (this.enemy)
- {
- enemyvel = this.enemy.velocity;
- if (!this.enemy.waterlevel)
- enemyvel.z = 0;
- lag_additem(this, time + this.ping, 0, 0, this.enemy, this.origin, myvel, (this.enemy.absmin + this.enemy.absmax) * 0.5, enemyvel);
- }
- else
- lag_additem(this, time + this.ping, 0, 0, NULL, this.origin, myvel, ( this.goalcurrent.absmin + this.goalcurrent.absmax ) * 0.5, '0 0 0');
-}
-
-bool havocbot_moveto_refresh_route(entity this)
-{
- // Refresh path to goal if necessary
- entity wp;
- wp = this.havocbot_personal_waypoint;
- navigation_goalrating_start(this);
- navigation_routerating(this, wp, 10000, 10000);
- navigation_goalrating_end(this);
- return this.navigation_hasgoals;
-}
-
-float havocbot_moveto(entity this, vector pos)
-{
- entity wp;
-
- if(this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_GOING)
- {
- // Step 4: Move to waypoint
- if(this.havocbot_personal_waypoint==NULL)
- {
- LOG_TRACE("Error: ", this.netname, " trying to walk to a non existent personal waypoint\n");
- this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_GOING;
- return CMD_STATUS_ERROR;
- }
-
- if (!bot_strategytoken_taken)
- if(this.havocbot_personal_waypoint_searchtime<time)
- {
- bot_strategytoken_taken = true;
- if(havocbot_moveto_refresh_route(this))
- {
- LOG_TRACE(this.netname, " walking to its personal waypoint (after ", ftos(this.havocbot_personal_waypoint_failcounter), " failed attempts)\n");
- this.havocbot_personal_waypoint_searchtime = time + 10;
- this.havocbot_personal_waypoint_failcounter = 0;
- }
- else
- {
- this.havocbot_personal_waypoint_failcounter += 1;
- this.havocbot_personal_waypoint_searchtime = time + 2;
- if(this.havocbot_personal_waypoint_failcounter >= 30)
- {
- LOG_TRACE("Warning: can't walk to the personal waypoint located at ", vtos(this.havocbot_personal_waypoint.origin),"\n");
- this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_LINKING;
- remove(this.havocbot_personal_waypoint);
- return CMD_STATUS_ERROR;
- }
- else
- LOG_TRACE(this.netname, " can't walk to its personal waypoint (after ", ftos(this.havocbot_personal_waypoint_failcounter), " failed attempts), trying later\n");
- }
- }
-
- if(autocvar_bot_debug_goalstack)
- debuggoalstack(this);
-
- // Heading
- vector dir = ( ( this.goalcurrent.absmin + this.goalcurrent.absmax ) * 0.5 ) - (this.origin + this.view_ofs);
- dir.z = 0;
- bot_aimdir(this, dir, -1);
-
- // Go!
- havocbot_movetogoal(this);
-
- if(this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_REACHED)
- {
- // Step 5: Waypoint reached
- LOG_TRACE(this.netname, "'s personal waypoint reached\n");
- remove(this.havocbot_personal_waypoint);
- this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_REACHED;
- return CMD_STATUS_FINISHED;
- }
-
- return CMD_STATUS_EXECUTING;
- }
-
- // Step 2: Linking waypoint
- if(this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_LINKING)
- {
- // Wait until it is linked
- if(!this.havocbot_personal_waypoint.wplinked)
- {
- LOG_TRACE(this.netname, " waiting for personal waypoint to be linked\n");
- return CMD_STATUS_EXECUTING;
- }
-
- this.havocbot_personal_waypoint_searchtime = time; // so we set the route next frame
- this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_LINKING;
- this.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_GOING;
-
- // Step 3: Route to waypoint
- LOG_TRACE(this.netname, " walking to its personal waypoint\n");
-
- return CMD_STATUS_EXECUTING;
- }
-
- // Step 1: Spawning waypoint
- wp = waypoint_spawnpersonal(this, pos);
- if(wp==NULL)
- {
- LOG_TRACE("Error: Can't spawn personal waypoint at ",vtos(pos),"\n");
- return CMD_STATUS_ERROR;
- }
-
- this.havocbot_personal_waypoint = wp;
- this.havocbot_personal_waypoint_failcounter = 0;
- this.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_LINKING;
-
- // if pos is inside a teleport, then let's mark it as teleport waypoint
- FOREACH_ENTITY_CLASS("trigger_teleport", WarpZoneLib_BoxTouchesBrush(pos, pos, it, NULL),
- {
- wp.wpflags |= WAYPOINTFLAG_TELEPORT;
- this.lastteleporttime = 0;
- });
-
-/*
- if(wp.wpflags & WAYPOINTFLAG_TELEPORT)
- print("routing to a teleporter\n");
- else
- print("routing to a non-teleporter\n");
-*/
-
- return CMD_STATUS_EXECUTING;
-}
-
-float havocbot_resetgoal(entity this)
-{
- navigation_clearroute(this);
- return CMD_STATUS_FINISHED;
-}
-
-void havocbot_setupbot(entity this)
-{
- this.bot_ai = havocbot_ai;
- this.cmd_moveto = havocbot_moveto;
- this.cmd_resetgoal = havocbot_resetgoal;
-
- havocbot_chooserole(this);
-}
-
-vector havocbot_dodge(entity this)
-{
- // LordHavoc: disabled because this is too expensive
- return '0 0 0';
-#if 0
- entity head;
- vector dodge, v, n;
- float danger, bestdanger, vl, d;
- dodge = '0 0 0';
- bestdanger = -20;
- // check for dangerous objects near bot or approaching bot
- head = findchainfloat(bot_dodge, true);
- while(head)
- {
- if (head.owner != this)
- {
- vl = vlen(head.velocity);
- if (vl > autocvar_sv_maxspeed * 0.3)
- {
- n = normalize(head.velocity);
- v = this.origin - head.origin;
- d = v * n;
- if (d > (0 - head.bot_dodgerating))
- if (d < (vl * 0.2 + head.bot_dodgerating))
- {
- // calculate direction and distance from the flight path, by removing the forward axis
- v = v - (n * (v * n));
- danger = head.bot_dodgerating - vlen(v);
- if (bestdanger < danger)
- {
- bestdanger = danger;
- // dodge to the side of the object
- dodge = normalize(v);
- }
- }
- }
- else
- {
- danger = head.bot_dodgerating - vlen(head.origin - this.origin);
- if (bestdanger < danger)
- {
- bestdanger = danger;
- dodge = normalize(this.origin - head.origin);
- }
- }
- }
- head = head.chain;
- }
- return dodge;
-#endif
-}
+++ /dev/null
-#pragma once
-
-/*
- * Globals and Fields
- */
-
-.float havocbot_keyboardskill;
-.float facingwalltime, ignoregoaltime;
-.float lastfiredweapon;
-.float lastcombotime;
-.float havocbot_blockhead;
-
-.float havocbot_keyboardtime;
-.float havocbot_ducktime;
-.float bot_timelastseengoal;
-.float bot_canruntogoal;
-.float bot_chooseweapontime;
-.float rocketjumptime;
-.float nextaim;
-.float havocbot_personal_waypoint_searchtime;
-.float havocbot_personal_waypoint_failcounter;
-.float havocbot_chooseenemy_finished;
-.float havocbot_stickenemy;
-.float havocbot_role_timeout;
-
-.entity ignoregoal;
-.entity bot_lastseengoal;
-.entity havocbot_personal_waypoint;
-
-.vector havocbot_keyboard;
-
-/*
- * Functions
- */
-
-void havocbot_ai(entity this);
-void havocbot_aim(entity this);
-void havocbot_setupbot(entity this);
-void havocbot_movetogoal(entity this);
-void havocbot_chooserole(entity this);
-void havocbot_chooseenemy(entity this);
-void havocbot_chooseweapon(entity this);
-void havocbot_bunnyhop(entity this, vector dir);
-void havocbot_keyboard_movement(entity this, vector destorg);
-
-float havocbot_resetgoal(entity this);
-float havocbot_moveto(entity this, vector pos);
-float havocbot_moveto_refresh_route(entity this);
-
-vector havocbot_dodge(entity this);
-
-.void(entity this) havocbot_role;
-.void(entity this) havocbot_previous_role;
-
-void(entity this, float ratingscale, vector org, float sradius) havocbot_goalrating_items;
-void(entity this, float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers;
-
-/*
- * Imports
- */
-
-.entity draggedby;
-.float ladder_time;
-.entity ladder_entity;
+++ /dev/null
-#include "roles.qh"
-
-#include "havocbot.qh"
-
-#include "../bot.qh"
-#include "../navigation.qh"
-
-.float max_armorvalue;
-.float havocbot_role_timeout;
-
-.void(entity this) havocbot_previous_role;
-.void(entity this) havocbot_role;
-
-void havocbot_goalrating_items(entity this, float ratingscale, vector org, float sradius)
-{
- float rating, d, discard, friend_distance, enemy_distance;
- vector o;
- ratingscale = ratingscale * 0.0001; // items are rated around 10000 already
-
- FOREACH_ENTITY_FLOAT(bot_pickup, true,
- {
- o = (it.absmin + it.absmax) * 0.5;
- friend_distance = 10000; enemy_distance = 10000;
- rating = 0;
-
- if(!it.solid || vdist(o - org, >, sradius) || (it == this.ignoregoal && time < this.ignoregoaltime) )
- continue;
-
- // Check if the item can be picked up safely
- if(it.classname == "droppedweapon")
- {
- traceline(o, o + '0 0 -1500', true, NULL);
-
- d = pointcontents(trace_endpos + '0 0 1');
- if(d & CONTENT_WATER || d & CONTENT_SLIME || d & CONTENT_LAVA)
- continue;
- if(tracebox_hits_trigger_hurt(it.origin, it.mins, it.maxs, trace_endpos))
- continue;
- }
- else
- {
- // Ignore items under water
- traceline(it.origin + it.maxs, it.origin + it.maxs, MOVE_NORMAL, it);
- if(trace_dpstartcontents & DPCONTENTS_LIQUIDSMASK)
- continue;
- }
-
- if(teamplay)
- {
- discard = false;
-
- entity picker = it;
- FOREACH_CLIENT(IS_PLAYER(it) && it != this && !IS_DEAD(it),
- {
- d = vlen(it.origin - o); // distance between player and item
-
- if ( it.team == this.team )
- {
- if ( !IS_REAL_CLIENT(it) || discard )
- continue;
-
- if( d > friend_distance)
- continue;
-
- friend_distance = d;
-
- discard = true;
-
- if( picker.health && it.health > this.health )
- continue;
-
- if( picker.armorvalue && it.armorvalue > this.armorvalue)
- continue;
-
- if( picker.weapons )
- if( picker.weapons & ~it.weapons )
- continue;
-
- if (picker.ammo_shells && it.ammo_shells > this.ammo_shells)
- continue;
-
- if (picker.ammo_nails && it.ammo_nails > this.ammo_nails)
- continue;
-
- if (picker.ammo_rockets && it.ammo_rockets > this.ammo_rockets)
- continue;
-
- if (picker.ammo_cells && it.ammo_cells > this.ammo_cells)
- continue;
-
- if (picker.ammo_plasma && it.ammo_plasma > this.ammo_plasma)
- continue;
-
- discard = false;
- }
- else
- {
- // If enemy only track distances
- // TODO: track only if visible ?
- if( d < enemy_distance )
- enemy_distance = d;
- }
- });
-
- // Rate the item only if no one needs it, or if an enemy is closer to it
- if ( (enemy_distance < friend_distance && vdist(o - org, <, enemy_distance)) ||
- (friend_distance > autocvar_bot_ai_friends_aware_pickup_radius ) || !discard )
- rating = it.bot_pickupevalfunc(this, it);
-
- }
- else
- rating = it.bot_pickupevalfunc(this, it);
-
- if(rating > 0)
- navigation_routerating(this, it, rating * ratingscale, 2000);
- });
-}
-
-void havocbot_goalrating_controlpoints(entity this, float ratingscale, vector org, float sradius)
-{
- FOREACH_ENTITY_CLASS("dom_controlpoint", vdist((((it.absmin + it.absmax) * 0.5) - org), <, sradius),
- {
- if(it.cnt > -1) // this is just being fought
- navigation_routerating(this, it, ratingscale, 5000);
- else if(it.goalentity.cnt == 0) // unclaimed
- navigation_routerating(this, it, ratingscale * 0.5, 5000);
- else if(it.goalentity.team != this.team) // other team's point
- navigation_routerating(this, it, ratingscale * 0.2, 5000);
- });
-}
-
-void havocbot_goalrating_enemyplayers(entity this, float ratingscale, vector org, float sradius)
-{
- if (autocvar_bot_nofire)
- return;
-
- // don't chase players if we're under water
- if(this.waterlevel>WATERLEVEL_WETFEET)
- return;
-
- int t;
-
- FOREACH_CLIENT(IS_PLAYER(it) && bot_shouldattack(this, it), LAMBDA(
- // TODO: Merge this logic with the bot_shouldattack function
- if(vdist(it.origin - org, <, 100) || vdist(it.origin - org, >, sradius))
- continue;
-
- // rate only visible enemies
- /*
- traceline(this.origin + this.view_ofs, it.origin, MOVE_NOMONSTERS, this);
- if (trace_fraction < 1 || trace_ent != it)
- continue;
- */
-
- if((it.flags & FL_INWATER) || (it.flags & FL_PARTIALGROUND))
- continue;
-
- // not falling
- if((IS_ONGROUND(it)) == 0)
- {
- traceline(it.origin, it.origin + '0 0 -1500', true, NULL);
- t = pointcontents(trace_endpos + '0 0 1');
- if(t != CONTENT_SOLID )
- if(t & CONTENT_WATER || t & CONTENT_SLIME || t & CONTENT_LAVA)
- continue;
- if(tracebox_hits_trigger_hurt(it.origin, it.mins, it.maxs, trace_endpos))
- continue;
- }
-
- // TODO: rate waypoints near the targetted player at that moment, instead of the player itthis
- // adding a player as a goal seems to be quite dangerous, especially on space maps
- // remove hack in navigation_poptouchedgoals() after performing this change
-
- t = (this.health + this.armorvalue ) / (it.health + it.armorvalue );
- navigation_routerating(this, it, t * ratingscale, 2000);
- ));
-}
-
-// legacy bot role for standard gamemodes
-// go to best items
-void havocbot_role_generic(entity this)
-{
- if(IS_DEAD(this))
- return;
-
- if (this.bot_strategytime < time)
- {
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
- navigation_goalrating_start(this);
- havocbot_goalrating_items(this, 10000, this.origin, 10000);
- havocbot_goalrating_enemyplayers(this, 20000, this.origin, 10000);
- //havocbot_goalrating_waypoints(1, this.origin, 1000);
- navigation_goalrating_end(this);
- }
-}
-
-void havocbot_chooserole_generic(entity this)
-{
- this.havocbot_role = havocbot_role_generic;
-}
-
-void havocbot_chooserole(entity this)
-{
- LOG_TRACE("choosing a role...\n");
- this.bot_strategytime = 0;
- if(!MUTATOR_CALLHOOK(HavocBot_ChooseRole, this))
- havocbot_chooserole_generic(this);
-}
+++ /dev/null
-#pragma once
-void havocbot_goalrating_controlpoints(entity this, float ratingscale, vector org, float sradius);
+++ /dev/null
-#pragma once
-
-void bot_clearqueue(entity bot);
+++ /dev/null
-#include "navigation.qh"
-
-#include "bot.qh"
-#include "waypoints.qh"
-
-#include <common/t_items.qh>
-
-#include <common/items/all.qh>
-
-#include <common/constants.qh>
-#include <common/triggers/trigger/jumppads.qh>
-
-.float speed;
-
-// rough simulation of walking from one point to another to test if a path
-// can be traveled, used for waypoint linking and havocbot
-
-bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float movemode)
-{
- vector org;
- vector move;
- vector dir;
- float dist;
- float totaldist;
- float stepdist;
- float yaw;
- float ignorehazards;
- float swimming;
-
- if(autocvar_bot_debug_tracewalk)
- {
- debugresetnodes();
- debugnode(e, start);
- }
-
- move = end - start;
- move.z = 0;
- org = start;
- dist = totaldist = vlen(move);
- dir = normalize(move);
- stepdist = 32;
- ignorehazards = false;
- swimming = false;
-
- // Analyze starting point
- traceline(start, start, MOVE_NORMAL, e);
- if (trace_dpstartcontents & (DPCONTENTS_SLIME | DPCONTENTS_LAVA))
- ignorehazards = true;
- else
- {
- traceline( start, start + '0 0 -65536', MOVE_NORMAL, e);
- if (trace_dpstartcontents & (DPCONTENTS_SLIME | DPCONTENTS_LAVA))
- {
- ignorehazards = true;
- swimming = true;
- }
- }
- tracebox(start, m1, m2, start, MOVE_NOMONSTERS, e);
- if (trace_startsolid)
- {
- // Bad start
- if(autocvar_bot_debug_tracewalk)
- debugnodestatus(start, DEBUG_NODE_FAIL);
-
- //print("tracewalk: ", vtos(start), " is a bad start\n");
- return false;
- }
-
- // Movement loop
- yaw = vectoyaw(move);
- move = end - org;
- for (;;)
- {
- if (boxesoverlap(end, end, org + m1 + '-1 -1 -1', org + m2 + '1 1 1'))
- {
- // Succeeded
- if(autocvar_bot_debug_tracewalk)
- debugnodestatus(org, DEBUG_NODE_SUCCESS);
-
- //print("tracewalk: ", vtos(start), " can reach ", vtos(end), "\n");
- return true;
- }
- if(autocvar_bot_debug_tracewalk)
- debugnode(e, org);
-
- if (dist <= 0)
- break;
- if (stepdist > dist)
- stepdist = dist;
- dist = dist - stepdist;
- traceline(org, org, MOVE_NORMAL, e);
- if (!ignorehazards)
- {
- if (trace_dpstartcontents & (DPCONTENTS_SLIME | DPCONTENTS_LAVA))
- {
- // hazards blocking path
- if(autocvar_bot_debug_tracewalk)
- debugnodestatus(org, DEBUG_NODE_FAIL);
-
- //print("tracewalk: ", vtos(start), " hits a hazard when trying to reach ", vtos(end), "\n");
- return false;
- }
- }
- if (trace_dpstartcontents & DPCONTENTS_LIQUIDSMASK)
- {
- move = normalize(end - org);
- tracebox(org, m1, m2, org + move * stepdist, movemode, e);
-
- if(autocvar_bot_debug_tracewalk)
- debugnode(e, trace_endpos);
-
- if (trace_fraction < 1)
- {
- swimming = true;
- org = trace_endpos - normalize(org - trace_endpos) * stepdist;
- for (; org.z < end.z + e.maxs.z; org.z += stepdist)
- {
- if(autocvar_bot_debug_tracewalk)
- debugnode(e, org);
-
- if(pointcontents(org) == CONTENT_EMPTY)
- break;
- }
-
- if(pointcontents(org + '0 0 1') != CONTENT_EMPTY)
- {
- if(autocvar_bot_debug_tracewalk)
- debugnodestatus(org, DEBUG_NODE_FAIL);
-
- return false;
- //print("tracewalk: ", vtos(start), " failed under water\n");
- }
- continue;
-
- }
- else
- org = trace_endpos;
- }
- else
- {
- move = dir * stepdist + org;
- tracebox(org, m1, m2, move, movemode, e);
-
- if(autocvar_bot_debug_tracewalk)
- debugnode(e, trace_endpos);
-
- // hit something
- if (trace_fraction < 1)
- {
- // check if we can walk over this obstacle, possibly by jumpstepping
- tracebox(org + stepheightvec, m1, m2, move + stepheightvec, movemode, e);
- if (trace_fraction < 1 || trace_startsolid)
- {
- tracebox(org + jumpstepheightvec, m1, m2, move + jumpstepheightvec, movemode, e);
- if (trace_fraction < 1 || trace_startsolid)
- {
- if(autocvar_bot_debug_tracewalk)
- debugnodestatus(trace_endpos, DEBUG_NODE_WARNING);
-
- // check for doors
- traceline( org, move, movemode, e);
- if ( trace_ent.classname == "door_rotating" || trace_ent.classname == "door")
- {
- vector nextmove;
- move = trace_endpos;
- while(trace_ent.classname == "door_rotating" || trace_ent.classname == "door")
- {
- nextmove = move + (dir * stepdist);
- traceline( move, nextmove, movemode, e);
- move = nextmove;
- }
- }
- else
- {
- if(autocvar_bot_debug_tracewalk)
- debugnodestatus(trace_endpos, DEBUG_NODE_FAIL);
-
- //print("tracewalk: ", vtos(start), " hit something when trying to reach ", vtos(end), "\n");
- //te_explosion(trace_endpos);
- //print(ftos(e.dphitcontentsmask), "\n");
- return false; // failed
- }
- }
- else
- move = trace_endpos;
- }
- else
- move = trace_endpos;
- }
- else
- move = trace_endpos;
-
- // trace down from stepheight as far as possible and move there,
- // if this starts in solid we try again without the stepup, and
- // if that also fails we assume it is a wall
- // (this is the same logic as the Quake walkmove function used)
- tracebox(move, m1, m2, move + '0 0 -65536', movemode, e);
-
- // moved successfully
- if(swimming)
- {
- float c;
- c = pointcontents(org + '0 0 1');
- if (!(c == CONTENT_WATER || c == CONTENT_LAVA || c == CONTENT_SLIME))
- swimming = false;
- else
- continue;
- }
-
- org = trace_endpos;
- }
- }
-
- //print("tracewalk: ", vtos(start), " did not arrive at ", vtos(end), " but at ", vtos(org), "\n");
-
- // moved but didn't arrive at the intended destination
- if(autocvar_bot_debug_tracewalk)
- debugnodestatus(org, DEBUG_NODE_FAIL);
-
- return false;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// goal stack
-/////////////////////////////////////////////////////////////////////////////
-
-// completely empty the goal stack, used when deciding where to go
-void navigation_clearroute(entity this)
-{
- //print("bot ", etos(this), " clear\n");
- this.navigation_hasgoals = false;
- this.goalcurrent = NULL;
- this.goalstack01 = NULL;
- this.goalstack02 = NULL;
- this.goalstack03 = NULL;
- this.goalstack04 = NULL;
- this.goalstack05 = NULL;
- this.goalstack06 = NULL;
- this.goalstack07 = NULL;
- this.goalstack08 = NULL;
- this.goalstack09 = NULL;
- this.goalstack10 = NULL;
- this.goalstack11 = NULL;
- this.goalstack12 = NULL;
- this.goalstack13 = NULL;
- this.goalstack14 = NULL;
- this.goalstack15 = NULL;
- this.goalstack16 = NULL;
- this.goalstack17 = NULL;
- this.goalstack18 = NULL;
- this.goalstack19 = NULL;
- this.goalstack20 = NULL;
- this.goalstack21 = NULL;
- this.goalstack22 = NULL;
- this.goalstack23 = NULL;
- this.goalstack24 = NULL;
- this.goalstack25 = NULL;
- this.goalstack26 = NULL;
- this.goalstack27 = NULL;
- this.goalstack28 = NULL;
- this.goalstack29 = NULL;
- this.goalstack30 = NULL;
- this.goalstack31 = NULL;
-}
-
-// add a new goal at the beginning of the stack
-// (in other words: add a new prerequisite before going to the later goals)
-// NOTE: when a waypoint is added, the WP gets pushed first, then the
-// next-closest WP on the shortest path to the WP
-// That means, if the stack overflows, the bot will know how to do the FIRST 32
-// steps to the goal, and then recalculate the path.
-void navigation_pushroute(entity this, entity e)
-{
- //print("bot ", etos(this), " push ", etos(e), "\n");
- this.goalstack31 = this.goalstack30;
- this.goalstack30 = this.goalstack29;
- this.goalstack29 = this.goalstack28;
- this.goalstack28 = this.goalstack27;
- this.goalstack27 = this.goalstack26;
- this.goalstack26 = this.goalstack25;
- this.goalstack25 = this.goalstack24;
- this.goalstack24 = this.goalstack23;
- this.goalstack23 = this.goalstack22;
- this.goalstack22 = this.goalstack21;
- this.goalstack21 = this.goalstack20;
- this.goalstack20 = this.goalstack19;
- this.goalstack19 = this.goalstack18;
- this.goalstack18 = this.goalstack17;
- this.goalstack17 = this.goalstack16;
- this.goalstack16 = this.goalstack15;
- this.goalstack15 = this.goalstack14;
- this.goalstack14 = this.goalstack13;
- this.goalstack13 = this.goalstack12;
- this.goalstack12 = this.goalstack11;
- this.goalstack11 = this.goalstack10;
- this.goalstack10 = this.goalstack09;
- this.goalstack09 = this.goalstack08;
- this.goalstack08 = this.goalstack07;
- this.goalstack07 = this.goalstack06;
- this.goalstack06 = this.goalstack05;
- this.goalstack05 = this.goalstack04;
- this.goalstack04 = this.goalstack03;
- this.goalstack03 = this.goalstack02;
- this.goalstack02 = this.goalstack01;
- this.goalstack01 = this.goalcurrent;
- this.goalcurrent = e;
-}
-
-// remove first goal from stack
-// (in other words: remove a prerequisite for reaching the later goals)
-// (used when a spawnfunc_waypoint is reached)
-void navigation_poproute(entity this)
-{
- //print("bot ", etos(this), " pop\n");
- this.goalcurrent = this.goalstack01;
- this.goalstack01 = this.goalstack02;
- this.goalstack02 = this.goalstack03;
- this.goalstack03 = this.goalstack04;
- this.goalstack04 = this.goalstack05;
- this.goalstack05 = this.goalstack06;
- this.goalstack06 = this.goalstack07;
- this.goalstack07 = this.goalstack08;
- this.goalstack08 = this.goalstack09;
- this.goalstack09 = this.goalstack10;
- this.goalstack10 = this.goalstack11;
- this.goalstack11 = this.goalstack12;
- this.goalstack12 = this.goalstack13;
- this.goalstack13 = this.goalstack14;
- this.goalstack14 = this.goalstack15;
- this.goalstack15 = this.goalstack16;
- this.goalstack16 = this.goalstack17;
- this.goalstack17 = this.goalstack18;
- this.goalstack18 = this.goalstack19;
- this.goalstack19 = this.goalstack20;
- this.goalstack20 = this.goalstack21;
- this.goalstack21 = this.goalstack22;
- this.goalstack22 = this.goalstack23;
- this.goalstack23 = this.goalstack24;
- this.goalstack24 = this.goalstack25;
- this.goalstack25 = this.goalstack26;
- this.goalstack26 = this.goalstack27;
- this.goalstack27 = this.goalstack28;
- this.goalstack28 = this.goalstack29;
- this.goalstack29 = this.goalstack30;
- this.goalstack30 = this.goalstack31;
- this.goalstack31 = NULL;
-}
-
-float navigation_waypoint_will_link(vector v, vector org, entity ent, float walkfromwp, float bestdist)
-{
- float dist;
- dist = vlen(v - org);
- if (bestdist > dist)
- {
- traceline(v, org, true, ent);
- if (trace_fraction == 1)
- {
- if (walkfromwp)
- {
- if (tracewalk(ent, v, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), org, bot_navigation_movemode))
- return true;
- }
- else
- {
- if (tracewalk(ent, org, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), v, bot_navigation_movemode))
- return true;
- }
- }
- }
- return false;
-}
-
-// find the spawnfunc_waypoint near a dynamic goal such as a dropped weapon
-entity navigation_findnearestwaypoint_withdist_except(entity ent, float walkfromwp, float bestdist, entity except)
-{
- vector pm1 = ent.origin + ent.mins;
- vector pm2 = ent.origin + ent.maxs;
-
- // do two scans, because box test is cheaper
- IL_EACH(g_waypoints, it != ent && it != except,
- {
- if(boxesoverlap(pm1, pm2, it.absmin, it.absmax))
- return it;
- });
-
- vector org = ent.origin + 0.5 * (ent.mins + ent.maxs);
- org.z = ent.origin.z + ent.mins.z - STAT(PL_MIN, NULL).z; // player height
- // TODO possibly make other code have the same support for bboxes
- if(ent.tag_entity)
- org = org + ent.tag_entity.origin;
- if (navigation_testtracewalk)
- te_plasmaburn(org);
-
- entity best = NULL;
- vector v;
-
- // box check failed, try walk
- IL_EACH(g_waypoints, it != ent,
- {
- if(it.wpisbox)
- {
- vector wm1 = it.origin + it.mins;
- vector wm2 = it.origin + it.maxs;
- v.x = bound(wm1_x, org.x, wm2_x);
- v.y = bound(wm1_y, org.y, wm2_y);
- v.z = bound(wm1_z, org.z, wm2_z);
- }
- else
- v = it.origin;
- if(navigation_waypoint_will_link(v, org, ent, walkfromwp, bestdist))
- {
- bestdist = vlen(v - org);
- best = it;
- }
- });
- return best;
-}
-entity navigation_findnearestwaypoint(entity ent, float walkfromwp)
-{
- entity wp = navigation_findnearestwaypoint_withdist_except(ent, walkfromwp, 1050, NULL);
- if (autocvar_g_waypointeditor_auto)
- {
- entity wp2 = navigation_findnearestwaypoint_withdist_except(ent, walkfromwp, 1050, wp);
- if (wp && !wp2)
- wp.wpflags |= WAYPOINTFLAG_PROTECTED;
- }
- return wp;
-}
-
-// finds the waypoints near the bot initiating a navigation query
-float navigation_markroutes_nearestwaypoints(entity this, float maxdist)
-{
- vector v, m1, m2;
-// navigation_testtracewalk = true;
- int c = 0;
- IL_EACH(g_waypoints, !it.wpconsidered,
- {
- if (it.wpisbox)
- {
- m1 = it.origin + it.mins;
- m2 = it.origin + it.maxs;
- v = this.origin;
- v.x = bound(m1_x, v.x, m2_x);
- v.y = bound(m1_y, v.y, m2_y);
- v.z = bound(m1_z, v.z, m2_z);
- }
- else
- v = it.origin;
- vector diff = v - this.origin;
- diff.z = max(0, diff.z);
- if(vdist(diff, <, maxdist))
- {
- it.wpconsidered = true;
- if (tracewalk(this, this.origin, this.mins, this.maxs, v, bot_navigation_movemode))
- {
- it.wpnearestpoint = v;
- it.wpcost = vlen(v - this.origin) + it.dmg;
- it.wpfire = 1;
- it.enemy = NULL;
- c = c + 1;
- }
- }
- });
- //navigation_testtracewalk = false;
- return c;
-}
-
-// updates a path link if a spawnfunc_waypoint link is better than the current one
-void navigation_markroutes_checkwaypoint(entity w, entity wp, float cost2, vector p)
-{
- vector m1;
- vector m2;
- vector v;
- if (wp.wpisbox)
- {
- m1 = wp.absmin;
- m2 = wp.absmax;
- v.x = bound(m1_x, p.x, m2_x);
- v.y = bound(m1_y, p.y, m2_y);
- v.z = bound(m1_z, p.z, m2_z);
- }
- else
- v = wp.origin;
- cost2 = cost2 + vlen(v - p);
- if (wp.wpcost > cost2)
- {
- wp.wpcost = cost2;
- wp.enemy = w;
- wp.wpfire = 1;
- wp.wpnearestpoint = v;
- }
-}
-
-// queries the entire spawnfunc_waypoint network for pathes leading away from the bot
-void navigation_markroutes(entity this, entity fixed_source_waypoint)
-{
- float cost, cost2;
- vector p;
-
- IL_EACH(g_waypoints, true,
- {
- it.wpconsidered = false;
- it.wpnearestpoint = '0 0 0';
- it.wpcost = 10000000;
- it.wpfire = 0;
- it.enemy = NULL;
- });
-
- if(fixed_source_waypoint)
- {
- fixed_source_waypoint.wpconsidered = true;
- fixed_source_waypoint.wpnearestpoint = fixed_source_waypoint.origin + 0.5 * (fixed_source_waypoint.mins + fixed_source_waypoint.maxs);
- fixed_source_waypoint.wpcost = fixed_source_waypoint.dmg;
- fixed_source_waypoint.wpfire = 1;
- fixed_source_waypoint.enemy = NULL;
- }
- else
- {
- // try a short range search for the nearest waypoints, and expand the search repeatedly if none are found
- // as this search is expensive we will use lower values if the bot is on the air
- float increment, maxdistance;
- if(IS_ONGROUND(this))
- {
- increment = 750;
- maxdistance = 50000;
- }
- else
- {
- increment = 500;
- maxdistance = 1500;
- }
-
- for(int j = increment; !navigation_markroutes_nearestwaypoints(this, j) && j < maxdistance; j += increment);
- }
-
- bool searching = true;
- while (searching)
- {
- searching = false;
- IL_EACH(g_waypoints, it.wpfire,
- {
- searching = true;
- it.wpfire = 0;
- cost = it.wpcost;
- p = it.wpnearestpoint;
- entity wp;
- wp = it.wp00;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp00mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp01;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp01mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp02;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp02mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp03;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp03mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp04;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp04mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp05;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp05mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp06;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp06mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp07;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp07mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp08;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp08mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp09;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp09mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp10;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp10mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp11;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp11mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp12;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp12mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp13;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp13mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp14;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp14mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp15;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp15mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp16;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp16mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp17;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp17mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp18;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp18mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp19;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp19mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp20;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp20mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp21;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp21mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp22;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp22mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp23;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp23mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp24;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp24mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp25;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp25mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp26;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp26mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp27;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp27mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp28;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp28mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp29;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp29mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp30;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp30mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- wp = it.wp31;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp31mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
- }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
- });
- }
-}
-
-// queries the entire spawnfunc_waypoint network for pathes leading to the bot
-void navigation_markroutes_inverted(entity fixed_source_waypoint)
-{
- float cost, cost2;
- vector p;
- IL_EACH(g_waypoints, true,
- {
- it.wpconsidered = false;
- it.wpnearestpoint = '0 0 0';
- it.wpcost = 10000000;
- it.wpfire = 0;
- it.enemy = NULL;
- });
-
- if(fixed_source_waypoint)
- {
- fixed_source_waypoint.wpconsidered = true;
- fixed_source_waypoint.wpnearestpoint = fixed_source_waypoint.origin + 0.5 * (fixed_source_waypoint.mins + fixed_source_waypoint.maxs);
- fixed_source_waypoint.wpcost = fixed_source_waypoint.dmg; // the cost to get from X to fixed_source_waypoint
- fixed_source_waypoint.wpfire = 1;
- fixed_source_waypoint.enemy = NULL;
- }
- else
- {
- error("need to start with a waypoint\n");
- }
-
- bool searching = true;
- while (searching)
- {
- searching = false;
- IL_EACH(g_waypoints, it.wpfire,
- {
- searching = true;
- it.wpfire = 0;
- cost = it.wpcost; // cost to walk from it to home
- p = it.wpnearestpoint;
- entity wp = it;
- IL_EACH(g_waypoints, true,
- {
- if(wp != it.wp00) if(wp != it.wp01) if(wp != it.wp02) if(wp != it.wp03)
- if(wp != it.wp04) if(wp != it.wp05) if(wp != it.wp06) if(wp != it.wp07)
- if(wp != it.wp08) if(wp != it.wp09) if(wp != it.wp10) if(wp != it.wp11)
- if(wp != it.wp12) if(wp != it.wp13) if(wp != it.wp14) if(wp != it.wp15)
- if(wp != it.wp16) if(wp != it.wp17) if(wp != it.wp18) if(wp != it.wp19)
- if(wp != it.wp20) if(wp != it.wp21) if(wp != it.wp22) if(wp != it.wp23)
- if(wp != it.wp24) if(wp != it.wp25) if(wp != it.wp26) if(wp != it.wp27)
- if(wp != it.wp28) if(wp != it.wp29) if(wp != it.wp30) if(wp != it.wp31)
- continue;
- cost2 = cost + it.dmg;
- navigation_markroutes_checkwaypoint(wp, it, cost2, p);
- });
- });
- }
-}
-
-// updates the best goal according to a weighted calculation of travel cost and item value of a new proposed item
-void navigation_routerating(entity this, entity e, float f, float rangebias)
-{
- entity nwp;
- vector o;
- if (!e)
- return;
-
- if(e.blacklisted)
- return;
-
- o = (e.absmin + e.absmax) * 0.5;
-
- //print("routerating ", etos(e), " = ", ftos(f), " - ", ftos(rangebias), "\n");
-
- // Evaluate path using jetpack
- if(g_jetpack)
- if(this.items & IT_JETPACK)
- if(autocvar_bot_ai_navigation_jetpack)
- if(vdist(this.origin - o, >, autocvar_bot_ai_navigation_jetpack_mindistance))
- {
- vector pointa, pointb;
-
- LOG_DEBUG("jetpack ai: evaluating path for ", e.classname, "\n");
-
- // Point A
- traceline(this.origin, this.origin + '0 0 65535', MOVE_NORMAL, this);
- pointa = trace_endpos - '0 0 1';
-
- // Point B
- traceline(o, o + '0 0 65535', MOVE_NORMAL, e);
- pointb = trace_endpos - '0 0 1';
-
- // Can I see these two points from the sky?
- traceline(pointa, pointb, MOVE_NORMAL, this);
-
- if(trace_fraction==1)
- {
- LOG_DEBUG("jetpack ai: can bridge these two points\n");
-
- // Lower the altitude of these points as much as possible
- float zdistance, xydistance, cost, t, fuel;
- vector down, npa, npb;
-
- down = '0 0 -1' * (STAT(PL_MAX, NULL).z - STAT(PL_MIN, NULL).z) * 10;
-
- do{
- npa = pointa + down;
- npb = pointb + down;
-
- if(npa.z<=this.absmax.z)
- break;
-
- if(npb.z<=e.absmax.z)
- break;
-
- traceline(npa, npb, MOVE_NORMAL, this);
- if(trace_fraction==1)
- {
- pointa = npa;
- pointb = npb;
- }
- }
- while(trace_fraction == 1);
-
-
- // Rough estimation of fuel consumption
- // (ignores acceleration and current xyz velocity)
- xydistance = vlen(pointa - pointb);
- zdistance = fabs(pointa.z - this.origin.z);
-
- t = zdistance / autocvar_g_jetpack_maxspeed_up;
- t += xydistance / autocvar_g_jetpack_maxspeed_side;
- fuel = t * autocvar_g_jetpack_fuel * 0.8;
-
- LOG_DEBUG(strcat("jetpack ai: required fuel ", ftos(fuel), " this.ammo_fuel ", ftos(this.ammo_fuel), "\n"));
-
- // enough fuel ?
- if(this.ammo_fuel>fuel)
- {
- // Estimate cost
- // (as onground costs calculation is mostly based on distances, here we do the same establishing some relationship
- // - between air and ground speeds)
-
- cost = xydistance / (autocvar_g_jetpack_maxspeed_side/autocvar_sv_maxspeed);
- cost += zdistance / (autocvar_g_jetpack_maxspeed_up/autocvar_sv_maxspeed);
- cost *= 1.5;
-
- // Compare against other goals
- f = f * rangebias / (rangebias + cost);
-
- if (navigation_bestrating < f)
- {
- LOG_DEBUG(strcat("jetpack path: added goal ", e.classname, " (with rating ", ftos(f), ")\n"));
- navigation_bestrating = f;
- navigation_bestgoal = e;
- this.navigation_jetpack_goal = e;
- this.navigation_jetpack_point = pointb;
- }
- return;
- }
- }
- }
-
- //te_wizspike(e.origin);
- //bprint(etos(e));
- //bprint("\n");
- // update the cached spawnfunc_waypoint link on a dynamic item entity
- if(e.classname == "waypoint" && !(e.wpflags & WAYPOINTFLAG_PERSONAL))
- {
- nwp = e;
- }
- else
- {
- float search;
-
- search = true;
-
- if(e.flags & FL_ITEM)
- {
- if (!(e.flags & FL_WEAPON))
- if(e.nearestwaypoint)
- search = false;
- }
- else if (e.flags & FL_WEAPON)
- {
- if(e.classname != "droppedweapon")
- if(e.nearestwaypoint)
- search = false;
- }
-
- if(search)
- if (time > e.nearestwaypointtimeout)
- {
- nwp = navigation_findnearestwaypoint(e, true);
- if(nwp)
- e.nearestwaypoint = nwp;
- else
- {
- LOG_DEBUG(strcat("FAILED to find a nearest waypoint to '", e.classname, "' #", etos(e), "\n"));
-
- if(e.flags & FL_ITEM)
- e.blacklisted = true;
- else if (e.flags & FL_WEAPON)
- {
- if(e.classname != "droppedweapon")
- e.blacklisted = true;
- }
-
- if(e.blacklisted)
- {
- LOG_DEBUG(strcat("The entity '", e.classname, "' is going to be excluded from path finding during this match\n"));
- return;
- }
- }
-
- // TODO: Cleaner solution, probably handling this timeout from ctf.qc
- if(e.classname=="item_flag_team")
- e.nearestwaypointtimeout = time + 2;
- else
- e.nearestwaypointtimeout = time + random() * 3 + 5;
- }
- nwp = e.nearestwaypoint;
- }
-
- LOG_DEBUG(strcat("-- checking ", e.classname, " (with cost ", ftos(nwp.wpcost), ")\n"));
- if (nwp)
- if (nwp.wpcost < 10000000)
- {
- //te_wizspike(nwp.wpnearestpoint);
- LOG_DEBUG(strcat(e.classname, " ", ftos(f), "/(1+", ftos((nwp.wpcost + vlen(e.origin - nwp.wpnearestpoint))), "/", ftos(rangebias), ") = "));
- f = f * rangebias / (rangebias + (nwp.wpcost + vlen(o - nwp.wpnearestpoint)));
- LOG_DEBUG(strcat("considering ", e.classname, " (with rating ", ftos(f), ")\n"));
- if (navigation_bestrating < f)
- {
- LOG_DEBUG(strcat("ground path: added goal ", e.classname, " (with rating ", ftos(f), ")\n"));
- navigation_bestrating = f;
- navigation_bestgoal = e;
- }
- }
-}
-
-// adds an item to the the goal stack with the path to a given item
-bool navigation_routetogoal(entity this, entity e, vector startposition)
-{
- this.goalentity = e;
-
- // if there is no goal, just exit
- if (!e)
- return false;
-
- this.navigation_hasgoals = true;
-
- // put the entity on the goal stack
- //print("routetogoal ", etos(e), "\n");
- navigation_pushroute(this, e);
-
- if(g_jetpack)
- if(e==this.navigation_jetpack_goal)
- return true;
-
- // if it can reach the goal there is nothing more to do
- if (tracewalk(this, startposition, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), (e.absmin + e.absmax) * 0.5, bot_navigation_movemode))
- return true;
-
- // see if there are waypoints describing a path to the item
- if(e.classname != "waypoint" || (e.wpflags & WAYPOINTFLAG_PERSONAL))
- e = e.nearestwaypoint;
- else
- e = e.enemy; // we already have added it, so...
-
- if(e == NULL)
- return false;
-
- for (;;)
- {
- // add the spawnfunc_waypoint to the path
- navigation_pushroute(this, e);
- e = e.enemy;
-
- if(e==NULL)
- break;
- }
-
- return false;
-}
-
-// removes any currently touching waypoints from the goal stack
-// (this is how bots detect if they reached a goal)
-void navigation_poptouchedgoals(entity this)
-{
- vector org, m1, m2;
- org = this.origin;
- m1 = org + this.mins;
- m2 = org + this.maxs;
-
- if(this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT)
- {
- if(this.lastteleporttime>0)
- if(time-this.lastteleporttime<(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL)?2:0.15)
- {
- if(this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_GOING)
- if(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL && this.goalcurrent.owner==this)
- {
- this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_GOING;
- this.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_REACHED;
- }
- navigation_poproute(this);
- return;
- }
- }
-
- // If for some reason the bot is closer to the next goal, pop the current one
- if(this.goalstack01)
- if(vlen2(this.goalcurrent.origin - this.origin) > vlen2(this.goalstack01.origin - this.origin))
- if(checkpvs(this.origin + this.view_ofs, this.goalstack01))
- if(tracewalk(this, this.origin, this.mins, this.maxs, (this.goalstack01.absmin + this.goalstack01.absmax) * 0.5, bot_navigation_movemode))
- {
- LOG_DEBUG(strcat("path optimized for ", this.netname, ", removed a goal from the queue\n"));
- navigation_poproute(this);
- // TODO this may also be a nice idea to do "early" (e.g. by
- // manipulating the vlen() comparisons) to shorten paths in
- // general - this would make bots walk more "on rails" than
- // "zigzagging" which they currently do with sufficiently
- // random-like waypoints, and thus can make a nice bot
- // personality property
- }
-
- // HACK: remove players/bots as goals, they can lead a bot to unexpected places (cliffs, lava, etc)
- // TODO: rate waypoints near the targetted player at that moment, instead of the player itthis
- if(IS_PLAYER(this.goalcurrent))
- navigation_poproute(this);
-
- // aid for detecting jump pads better (distance based check fails sometimes)
- if(this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT && this.jumppadcount > 0 )
- navigation_poproute(this);
-
- // Loose goal touching check when running
- if(this.aistatus & AI_STATUS_RUNNING)
- if(this.speed >= autocvar_sv_maxspeed) // if -really- running
- if(this.goalcurrent.classname=="waypoint")
- {
- if(vdist(this.origin - this.goalcurrent.origin, <, 150))
- {
- traceline(this.origin + this.view_ofs , this.goalcurrent.origin, true, NULL);
- if(trace_fraction==1)
- {
- // Detect personal waypoints
- if(this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_GOING)
- if(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL && this.goalcurrent.owner==this)
- {
- this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_GOING;
- this.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_REACHED;
- }
-
- navigation_poproute(this);
- }
- }
- }
-
- while (this.goalcurrent && boxesoverlap(m1, m2, this.goalcurrent.absmin, this.goalcurrent.absmax))
- {
- // Detect personal waypoints
- if(this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_GOING)
- if(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL && this.goalcurrent.owner==this)
- {
- this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_GOING;
- this.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_REACHED;
- }
-
- navigation_poproute(this);
- }
-}
-
-// begin a goal selection session (queries spawnfunc_waypoint network)
-void navigation_goalrating_start(entity this)
-{
- if(this.aistatus & AI_STATUS_STUCK)
- return;
-
- this.navigation_jetpack_goal = NULL;
- navigation_bestrating = -1;
- this.navigation_hasgoals = false;
- navigation_clearroute(this);
- navigation_bestgoal = NULL;
- navigation_markroutes(this, NULL);
-}
-
-// ends a goal selection session (updates goal stack to the best goal)
-void navigation_goalrating_end(entity this)
-{
- if(this.aistatus & AI_STATUS_STUCK)
- return;
-
- navigation_routetogoal(this, navigation_bestgoal, this.origin);
- LOG_DEBUG(strcat("best goal ", this.goalcurrent.classname , "\n"));
-
- // If the bot got stuck then try to reach the farthest waypoint
- if (!this.navigation_hasgoals)
- if (autocvar_bot_wander_enable)
- {
- if (!(this.aistatus & AI_STATUS_STUCK))
- {
- LOG_DEBUG(strcat(this.netname, " cannot walk to any goal\n"));
- this.aistatus |= AI_STATUS_STUCK;
- }
-
- this.navigation_hasgoals = false; // Reset this value
- }
-}
-
-void botframe_updatedangerousobjects(float maxupdate)
-{
- vector m1, m2, v, o;
- float c, d, danger;
- c = 0;
- IL_EACH(g_waypoints, true,
- {
- danger = 0;
- m1 = it.mins;
- m2 = it.maxs;
- FOREACH_ENTITY_FLOAT(bot_dodge, true,
- {
- v = it.origin;
- v.x = bound(m1_x, v.x, m2_x);
- v.y = bound(m1_y, v.y, m2_y);
- v.z = bound(m1_z, v.z, m2_z);
- o = (it.absmin + it.absmax) * 0.5;
- d = it.bot_dodgerating - vlen(o - v);
- if (d > 0)
- {
- traceline(o, v, true, NULL);
- if (trace_fraction == 1)
- danger = danger + d;
- }
- });
- it.dmg = danger;
- c = c + 1;
- if (c >= maxupdate)
- break;
- });
-}
-
-void navigation_unstuck(entity this)
-{
- float search_radius = 1000;
-
- if (!autocvar_bot_wander_enable)
- return;
-
- if (!bot_waypoint_queue_owner)
- {
- LOG_DEBUG(strcat(this.netname, " sutck, taking over the waypoints queue\n"));
- bot_waypoint_queue_owner = this;
- bot_waypoint_queue_bestgoal = NULL;
- bot_waypoint_queue_bestgoalrating = 0;
- }
-
- if(bot_waypoint_queue_owner!=this)
- return;
-
- if (bot_waypoint_queue_goal)
- {
- // evaluate the next goal on the queue
- float d = vlen(this.origin - bot_waypoint_queue_goal.origin);
- LOG_DEBUG(strcat(this.netname, " evaluating ", bot_waypoint_queue_goal.classname, " with distance ", ftos(d), "\n"));
- if(tracewalk(bot_waypoint_queue_goal, this.origin, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), bot_waypoint_queue_goal.origin, bot_navigation_movemode))
- {
- if( d > bot_waypoint_queue_bestgoalrating)
- {
- bot_waypoint_queue_bestgoalrating = d;
- bot_waypoint_queue_bestgoal = bot_waypoint_queue_goal;
- }
- }
- bot_waypoint_queue_goal = bot_waypoint_queue_goal.bot_waypoint_queue_nextgoal;
-
- if (!bot_waypoint_queue_goal)
- {
- if (bot_waypoint_queue_bestgoal)
- {
- LOG_DEBUG(strcat(this.netname, " stuck, reachable waypoint found, heading to it\n"));
- navigation_routetogoal(this, bot_waypoint_queue_bestgoal, this.origin);
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
- this.aistatus &= ~AI_STATUS_STUCK;
- }
- else
- {
- LOG_DEBUG(strcat(this.netname, " stuck, cannot walk to any waypoint at all\n"));
- }
-
- bot_waypoint_queue_owner = NULL;
- }
- }
- else
- {
- if(bot_strategytoken!=this)
- return;
-
- // build a new queue
- LOG_DEBUG(strcat(this.netname, " stuck, scanning reachable waypoints within ", ftos(search_radius)," qu\n"));
-
- entity first = NULL;
-
- FOREACH_ENTITY_RADIUS(this.origin, search_radius, it.classname == "waypoint" && !(it.wpflags & WAYPOINTFLAG_GENERATED),
- {
- if(bot_waypoint_queue_goal)
- bot_waypoint_queue_goal.bot_waypoint_queue_nextgoal = it;
- else
- first = it;
-
- bot_waypoint_queue_goal = it;
- bot_waypoint_queue_goal.bot_waypoint_queue_nextgoal = NULL;
- });
-
- if (first)
- bot_waypoint_queue_goal = first;
- else
- {
- LOG_DEBUG(strcat(this.netname, " stuck, cannot walk to any waypoint at all\n"));
- bot_waypoint_queue_owner = NULL;
- }
- }
-}
-
-// Support for debugging tracewalk visually
-
-void debugresetnodes()
-{
- debuglastnode = '0 0 0';
-}
-
-void debugnode(entity this, vector node)
-{
- if (!IS_PLAYER(this))
- return;
-
- if(debuglastnode=='0 0 0')
- {
- debuglastnode = node;
- return;
- }
-
- te_lightning2(NULL, node, debuglastnode);
- debuglastnode = node;
-}
-
-void debugnodestatus(vector position, float status)
-{
- vector c;
-
- switch (status)
- {
- case DEBUG_NODE_SUCCESS:
- c = '0 15 0';
- break;
- case DEBUG_NODE_WARNING:
- c = '15 15 0';
- break;
- case DEBUG_NODE_FAIL:
- c = '15 0 0';
- break;
- default:
- c = '15 15 15';
- }
-
- te_customflash(position, 40, 2, c);
-}
-
-// Support for debugging the goal stack visually
-
-.float goalcounter;
-.vector lastposition;
-
-// Debug the goal stack visually
-void debuggoalstack(entity this)
-{
- entity goal;
- vector org, go;
-
- if(this.goalcounter==0)goal=this.goalcurrent;
- else if(this.goalcounter==1)goal=this.goalstack01;
- else if(this.goalcounter==2)goal=this.goalstack02;
- else if(this.goalcounter==3)goal=this.goalstack03;
- else if(this.goalcounter==4)goal=this.goalstack04;
- else if(this.goalcounter==5)goal=this.goalstack05;
- else if(this.goalcounter==6)goal=this.goalstack06;
- else if(this.goalcounter==7)goal=this.goalstack07;
- else if(this.goalcounter==8)goal=this.goalstack08;
- else if(this.goalcounter==9)goal=this.goalstack09;
- else if(this.goalcounter==10)goal=this.goalstack10;
- else if(this.goalcounter==11)goal=this.goalstack11;
- else if(this.goalcounter==12)goal=this.goalstack12;
- else if(this.goalcounter==13)goal=this.goalstack13;
- else if(this.goalcounter==14)goal=this.goalstack14;
- else if(this.goalcounter==15)goal=this.goalstack15;
- else if(this.goalcounter==16)goal=this.goalstack16;
- else if(this.goalcounter==17)goal=this.goalstack17;
- else if(this.goalcounter==18)goal=this.goalstack18;
- else if(this.goalcounter==19)goal=this.goalstack19;
- else if(this.goalcounter==20)goal=this.goalstack20;
- else if(this.goalcounter==21)goal=this.goalstack21;
- else if(this.goalcounter==22)goal=this.goalstack22;
- else if(this.goalcounter==23)goal=this.goalstack23;
- else if(this.goalcounter==24)goal=this.goalstack24;
- else if(this.goalcounter==25)goal=this.goalstack25;
- else if(this.goalcounter==26)goal=this.goalstack26;
- else if(this.goalcounter==27)goal=this.goalstack27;
- else if(this.goalcounter==28)goal=this.goalstack28;
- else if(this.goalcounter==29)goal=this.goalstack29;
- else if(this.goalcounter==30)goal=this.goalstack30;
- else if(this.goalcounter==31)goal=this.goalstack31;
- else goal=NULL;
-
- if(goal==NULL)
- {
- this.goalcounter = 0;
- this.lastposition='0 0 0';
- return;
- }
-
- if(this.lastposition=='0 0 0')
- org = this.origin;
- else
- org = this.lastposition;
-
-
- go = ( goal.absmin + goal.absmax ) * 0.5;
- te_lightning2(NULL, org, go);
- this.lastposition = go;
-
- this.goalcounter++;
-}
+++ /dev/null
-#pragma once
-/*
- * Globals and Fields
- */
-
-float navigation_bestrating;
-float bot_navigation_movemode;
-float navigation_testtracewalk;
-
-vector jumpstepheightvec;
-vector stepheightvec;
-
-entity navigation_bestgoal;
-
-// stack of current goals (the last one of which may be an item or other
-// desirable object, the rest are typically waypoints to reach it)
-.entity goalcurrent, goalstack01, goalstack02, goalstack03;
-.entity goalstack04, goalstack05, goalstack06, goalstack07;
-.entity goalstack08, goalstack09, goalstack10, goalstack11;
-.entity goalstack12, goalstack13, goalstack14, goalstack15;
-.entity goalstack16, goalstack17, goalstack18, goalstack19;
-.entity goalstack20, goalstack21, goalstack22, goalstack23;
-.entity goalstack24, goalstack25, goalstack26, goalstack27;
-.entity goalstack28, goalstack29, goalstack30, goalstack31;
-.entity nearestwaypoint;
-
-.float nearestwaypointtimeout;
-.float navigation_hasgoals;
-.float lastteleporttime;
-
-.float blacklisted;
-
-.entity navigation_jetpack_goal;
-.vector navigation_jetpack_point;
-
-const float DEBUG_NODE_SUCCESS = 1;
-const float DEBUG_NODE_WARNING = 2;
-const float DEBUG_NODE_FAIL = 3;
-vector debuglastnode;
-
-entity bot_waypoint_queue_owner; // Owner of the temporary list of goals
-entity bot_waypoint_queue_goal; // Head of the temporary list of goals
-.entity bot_waypoint_queue_nextgoal;
-entity bot_waypoint_queue_bestgoal;
-float bot_waypoint_queue_bestgoalrating;
-
-/*
- * Functions
- */
-
-void debugresetnodes();
-void debugnode(entity this, vector node);
-void debugnodestatus(vector position, float status);
-
-void debuggoalstack(entity this);
-
-float tracewalk(entity e, vector start, vector m1, vector m2, vector end, float movemode);
-
-float navigation_markroutes_nearestwaypoints(entity this, float maxdist);
-float navigation_routetogoal(entity this, entity e, vector startposition);
-
-void navigation_clearroute(entity this);
-void navigation_pushroute(entity this, entity e);
-void navigation_poproute(entity this);
-void navigation_markroutes_checkwaypoint(entity w, entity wp, float cost2, vector p);
-void navigation_markroutes(entity this, entity fixed_source_waypoint);
-void navigation_markroutes_inverted(entity fixed_source_waypoint);
-void navigation_routerating(entity this, entity e, float f, float rangebias);
-void navigation_poptouchedgoals(entity this);
-void navigation_goalrating_start(entity this);
-void navigation_goalrating_end(entity this);
-void navigation_unstuck(entity this);
-
-void botframe_updatedangerousobjects(float maxupdate);
-
-entity navigation_findnearestwaypoint(entity ent, float walkfromwp);
-float navigation_waypoint_will_link(vector v, vector org, entity ent, float walkfromwp, float bestdist);
+++ /dev/null
-#include "scripting.qh"
-
-#include <common/state.qh>
-#include <common/physics/player.qh>
-
-#include "bot.qh"
-
-.int state;
-
-.float bot_cmdqueuebuf_allocated;
-.float bot_cmdqueuebuf;
-.float bot_cmdqueuebuf_start;
-.float bot_cmdqueuebuf_end;
-
-void bot_clearqueue(entity bot)
-{
- if(!bot.bot_cmdqueuebuf_allocated)
- return;
- buf_del(bot.bot_cmdqueuebuf);
- bot.bot_cmdqueuebuf_allocated = false;
- LOG_TRACE("bot ", bot.netname, " queue cleared\n");
-}
-
-void bot_queuecommand(entity bot, string cmdstring)
-{
- if(!bot.bot_cmdqueuebuf_allocated)
- {
- bot.bot_cmdqueuebuf = buf_create();
- bot.bot_cmdqueuebuf_allocated = true;
- bot.bot_cmdqueuebuf_start = 0;
- bot.bot_cmdqueuebuf_end = 0;
- }
-
- bufstr_set(bot.bot_cmdqueuebuf, bot.bot_cmdqueuebuf_end, cmdstring);
-
- // if the command was a "sound" command, precache the sound NOW
- // this prevents lagging!
- {
- float sp;
- string parm;
- string cmdstr;
-
- sp = strstrofs(cmdstring, " ", 0);
- if(sp >= 0)
- {
- parm = substring(cmdstring, sp + 1, -1);
- cmdstr = substring(cmdstring, 0, sp);
- if(cmdstr == "sound")
- {
- // find the LAST word
- for (;;)
- {
- sp = strstrofs(parm, " ", 0);
- if(sp < 0)
- break;
- parm = substring(parm, sp + 1, -1);
- }
- precache_sound(parm);
- }
- }
- }
-
- bot.bot_cmdqueuebuf_end += 1;
-}
-
-void bot_dequeuecommand(entity bot, float idx)
-{
- if(!bot.bot_cmdqueuebuf_allocated)
- error("dequeuecommand but no queue allocated");
- if(idx < bot.bot_cmdqueuebuf_start)
- error("dequeueing a command in the past");
- if(idx >= bot.bot_cmdqueuebuf_end)
- error("dequeueing a command in the future");
- bufstr_set(bot.bot_cmdqueuebuf, idx, "");
- if(idx == bot.bot_cmdqueuebuf_start)
- bot.bot_cmdqueuebuf_start += 1;
- if(bot.bot_cmdqueuebuf_start >= bot.bot_cmdqueuebuf_end)
- bot_clearqueue(bot);
-}
-
-string bot_readcommand(entity bot, float idx)
-{
- if(!bot.bot_cmdqueuebuf_allocated)
- error("readcommand but no queue allocated");
- if(idx < bot.bot_cmdqueuebuf_start)
- error("reading a command in the past");
- if(idx >= bot.bot_cmdqueuebuf_end)
- error("reading a command in the future");
- return bufstr_get(bot.bot_cmdqueuebuf, idx);
-}
-
-bool bot_havecommand(entity this, int idx)
-{
- if(!this.bot_cmdqueuebuf_allocated)
- return false;
- if(idx < this.bot_cmdqueuebuf_start)
- return false;
- if(idx >= this.bot_cmdqueuebuf_end)
- return false;
- return true;
-}
-
-const int MAX_BOT_PLACES = 4;
-.float bot_places_count;
-.entity bot_places[MAX_BOT_PLACES];
-.string bot_placenames[MAX_BOT_PLACES];
-entity bot_getplace(entity this, string placename)
-{
- entity e;
- if(substring(placename, 0, 1) == "@")
- {
- int i, p;
- placename = substring(placename, 1, -1);
- string s, s2;
- for(i = 0; i < this.bot_places_count; ++i)
- if(this.(bot_placenames[i]) == placename)
- return this.(bot_places[i]);
- // now: i == this.bot_places_count
- s = s2 = cvar_string(placename);
- p = strstrofs(s2, " ", 0);
- if(p >= 0)
- {
- s = substring(s2, 0, p);
- //print("places: ", placename, " -> ", cvar_string(placename), "\n");
- cvar_set(placename, strcat(substring(s2, p+1, -1), " ", s));
- //print("places: ", placename, " := ", cvar_string(placename), "\n");
- }
- e = find(NULL, targetname, s);
- if(!e)
- LOG_INFO("invalid place ", s, "\n");
- if(i < MAX_BOT_PLACES)
- {
- this.(bot_placenames[i]) = strzone(placename);
- this.(bot_places[i]) = e;
- this.bot_places_count += 1;
- }
- return e;
- }
- else
- {
- e = find(NULL, targetname, placename);
- if(!e)
- LOG_INFO("invalid place ", placename, "\n");
- return e;
- }
-}
-
-
-// Initialize global commands list
-// NOTE: New commands should be initialized here
-void bot_commands_init()
-{
- bot_cmd_string[BOT_CMD_NULL] = "";
- bot_cmd_parm_type[BOT_CMD_NULL] = BOT_CMD_PARAMETER_NONE;
-
- bot_cmd_string[BOT_CMD_PAUSE] = "pause";
- bot_cmd_parm_type[BOT_CMD_PAUSE] = BOT_CMD_PARAMETER_NONE;
-
- bot_cmd_string[BOT_CMD_CONTINUE] = "continue";
- bot_cmd_parm_type[BOT_CMD_CONTINUE] = BOT_CMD_PARAMETER_NONE;
-
- bot_cmd_string[BOT_CMD_WAIT] = "wait";
- bot_cmd_parm_type[BOT_CMD_WAIT] = BOT_CMD_PARAMETER_FLOAT;
-
- bot_cmd_string[BOT_CMD_TURN] = "turn";
- bot_cmd_parm_type[BOT_CMD_TURN] = BOT_CMD_PARAMETER_FLOAT;
-
- bot_cmd_string[BOT_CMD_MOVETO] = "moveto";
- bot_cmd_parm_type[BOT_CMD_MOVETO] = BOT_CMD_PARAMETER_VECTOR;
-
- bot_cmd_string[BOT_CMD_MOVETOTARGET] = "movetotarget";
- bot_cmd_parm_type[BOT_CMD_MOVETOTARGET] = BOT_CMD_PARAMETER_STRING;
-
- bot_cmd_string[BOT_CMD_RESETGOAL] = "resetgoal";
- bot_cmd_parm_type[BOT_CMD_RESETGOAL] = BOT_CMD_PARAMETER_NONE;
-
- bot_cmd_string[BOT_CMD_CC] = "cc";
- bot_cmd_parm_type[BOT_CMD_CC] = BOT_CMD_PARAMETER_STRING;
-
- bot_cmd_string[BOT_CMD_IF] = "if";
- bot_cmd_parm_type[BOT_CMD_IF] = BOT_CMD_PARAMETER_STRING;
-
- bot_cmd_string[BOT_CMD_ELSE] = "else";
- bot_cmd_parm_type[BOT_CMD_ELSE] = BOT_CMD_PARAMETER_NONE;
-
- bot_cmd_string[BOT_CMD_FI] = "fi";
- bot_cmd_parm_type[BOT_CMD_FI] = BOT_CMD_PARAMETER_NONE;
-
- bot_cmd_string[BOT_CMD_RESETAIM] = "resetaim";
- bot_cmd_parm_type[BOT_CMD_RESETAIM] = BOT_CMD_PARAMETER_NONE;
-
- bot_cmd_string[BOT_CMD_AIM] = "aim";
- bot_cmd_parm_type[BOT_CMD_AIM] = BOT_CMD_PARAMETER_STRING;
-
- bot_cmd_string[BOT_CMD_AIMTARGET] = "aimtarget";
- bot_cmd_parm_type[BOT_CMD_AIMTARGET] = BOT_CMD_PARAMETER_STRING;
-
- bot_cmd_string[BOT_CMD_PRESSKEY] = "presskey";
- bot_cmd_parm_type[BOT_CMD_PRESSKEY] = BOT_CMD_PARAMETER_STRING;
-
- bot_cmd_string[BOT_CMD_RELEASEKEY] = "releasekey";
- bot_cmd_parm_type[BOT_CMD_RELEASEKEY] = BOT_CMD_PARAMETER_STRING;
-
- bot_cmd_string[BOT_CMD_SELECTWEAPON] = "selectweapon";
- bot_cmd_parm_type[BOT_CMD_SELECTWEAPON] = BOT_CMD_PARAMETER_FLOAT;
-
- bot_cmd_string[BOT_CMD_IMPULSE] = "impulse";
- bot_cmd_parm_type[BOT_CMD_IMPULSE] = BOT_CMD_PARAMETER_FLOAT;
-
- bot_cmd_string[BOT_CMD_WAIT_UNTIL] = "wait_until";
- bot_cmd_parm_type[BOT_CMD_WAIT_UNTIL] = BOT_CMD_PARAMETER_FLOAT;
-
- bot_cmd_string[BOT_CMD_BARRIER] = "barrier";
- bot_cmd_parm_type[BOT_CMD_BARRIER] = BOT_CMD_PARAMETER_NONE;
-
- bot_cmd_string[BOT_CMD_CONSOLE] = "console";
- bot_cmd_parm_type[BOT_CMD_CONSOLE] = BOT_CMD_PARAMETER_STRING;
-
- bot_cmd_string[BOT_CMD_SOUND] = "sound";
- bot_cmd_parm_type[BOT_CMD_SOUND] = BOT_CMD_PARAMETER_STRING;
-
- bot_cmd_string[BOT_CMD_DEBUG_ASSERT_CANFIRE] = "debug_assert_canfire";
- bot_cmd_parm_type[BOT_CMD_DEBUG_ASSERT_CANFIRE] = BOT_CMD_PARAMETER_FLOAT;
-
- bot_cmds_initialized = true;
-}
-
-// Returns first bot with matching name
-entity find_bot_by_name(string name)
-{
- entity bot;
-
- bot = findchainflags(flags, FL_CLIENT);
- while (bot)
- {
- if(IS_BOT_CLIENT(bot))
- if(bot.netname==name)
- return bot;
-
- bot = bot.chain;
- }
-
- return NULL;
-}
-
-// Returns a bot by number on list
-entity find_bot_by_number(float number)
-{
- entity bot;
- float c = 0;
-
- if(!number)
- return NULL;
-
- bot = findchainflags(flags, FL_CLIENT); // TODO: doesn't findchainflags loop backwards through entities?
- while (bot)
- {
- if(IS_BOT_CLIENT(bot))
- {
- if(++c==number)
- return bot;
- }
- bot = bot.chain;
- }
-
- return NULL;
-}
-
-float bot_decodecommand(string cmdstring)
-{
- float cmd_parm_type;
- float sp;
- string parm;
-
- sp = strstrofs(cmdstring, " ", 0);
- if(sp < 0)
- {
- parm = "";
- }
- else
- {
- parm = substring(cmdstring, sp + 1, -1);
- cmdstring = substring(cmdstring, 0, sp);
- }
-
- if(!bot_cmds_initialized)
- bot_commands_init();
-
- int i;
- for(i=1;i<BOT_CMD_COUNTER;++i)
- {
- if(bot_cmd_string[i]!=cmdstring)
- continue;
-
- cmd_parm_type = bot_cmd_parm_type[i];
-
- if(cmd_parm_type!=BOT_CMD_PARAMETER_NONE&&parm=="")
- {
- LOG_INFO("ERROR: A parameter is required for this command\n");
- return 0;
- }
-
- // Load command into queue
- bot_cmd.bot_cmd_type = i;
-
- // Attach parameter
- switch(cmd_parm_type)
- {
- case BOT_CMD_PARAMETER_FLOAT:
- bot_cmd.bot_cmd_parm_float = stof(parm);
- break;
- case BOT_CMD_PARAMETER_STRING:
- if(bot_cmd.bot_cmd_parm_string)
- strunzone(bot_cmd.bot_cmd_parm_string);
- bot_cmd.bot_cmd_parm_string = strzone(parm);
- break;
- case BOT_CMD_PARAMETER_VECTOR:
- bot_cmd.bot_cmd_parm_vector = stov(parm);
- break;
- default:
- break;
- }
- return 1;
- }
- LOG_INFO("ERROR: No such command '", cmdstring, "'\n");
- return 0;
-}
-
-void bot_cmdhelp(string scmd)
-{
- int i, ntype;
- string stype;
-
- if(!bot_cmds_initialized)
- bot_commands_init();
-
- for(i=1;i<BOT_CMD_COUNTER;++i)
- {
- if(bot_cmd_string[i]!=scmd)
- continue;
-
- ntype = bot_cmd_parm_type[i];
-
- switch(ntype)
- {
- case BOT_CMD_PARAMETER_FLOAT:
- stype = "float number";
- break;
- case BOT_CMD_PARAMETER_STRING:
- stype = "string";
- break;
- case BOT_CMD_PARAMETER_VECTOR:
- stype = "vector";
- break;
- default:
- stype = "none";
- break;
- }
-
- LOG_INFO(strcat("Command: ",bot_cmd_string[i],"\nParameter: <",stype,"> \n"));
-
- LOG_INFO("Description: ");
- switch(i)
- {
- case BOT_CMD_PAUSE:
- LOG_INFO("Stops the bot completely. Any command other than 'continue' will be ignored.");
- break;
- case BOT_CMD_CONTINUE:
- LOG_INFO("Disable paused status");
- break;
- case BOT_CMD_WAIT:
- LOG_INFO("Pause command parsing and bot ai for N seconds. Pressed key will remain pressed");
- break;
- case BOT_CMD_WAIT_UNTIL:
- LOG_INFO("Pause command parsing and bot ai until time is N from the last barrier. Pressed key will remain pressed");
- break;
- case BOT_CMD_BARRIER:
- LOG_INFO("Waits till all bots that have a command queue reach this command. Pressed key will remain pressed");
- break;
- case BOT_CMD_TURN:
- LOG_INFO("Look to the right or left N degrees. For turning to the left use positive numbers.");
- break;
- case BOT_CMD_MOVETO:
- LOG_INFO("Walk to an specific coordinate on the map. Usage: moveto \"x y z\"");
- break;
- case BOT_CMD_MOVETOTARGET:
- LOG_INFO("Walk to the specific target on the map");
- break;
- case BOT_CMD_RESETGOAL:
- LOG_INFO("Resets the goal stack");
- break;
- case BOT_CMD_CC:
- LOG_INFO("Execute client command. Examples: cc \"say something\"; cc god; cc \"name newnickname\"; cc kill;");
- break;
- case BOT_CMD_IF:
- LOG_INFO("Perform simple conditional execution.\n");
- LOG_INFO("Syntax: \n");
- LOG_INFO(" sv_cmd .. if \"condition\"\n");
- LOG_INFO(" sv_cmd .. <instruction if true>\n");
- LOG_INFO(" sv_cmd .. <instruction if true>\n");
- LOG_INFO(" sv_cmd .. else\n");
- LOG_INFO(" sv_cmd .. <instruction if false>\n");
- LOG_INFO(" sv_cmd .. <instruction if false>\n");
- LOG_INFO(" sv_cmd .. fi\n");
- LOG_INFO("Conditions: a=b, a>b, a<b, a\t\t(spaces not allowed)\n");
- LOG_INFO(" Values in conditions can be numbers, cvars in the form cvar.cvar_string or special fields\n");
- LOG_INFO("Fields: health, speed, flagcarrier\n");
- LOG_INFO("Examples: if health>50; if health>cvar.g_balance_laser_primary_damage; if flagcarrier;");
- break;
- case BOT_CMD_RESETAIM:
- LOG_INFO("Points the aim to the coordinates x,y 0,0");
- break;
- case BOT_CMD_AIM:
- LOG_INFO("Move the aim x/y (horizontal/vertical) degrees relatives to the bot\n");
- LOG_INFO("There is a 3rd optional parameter telling in how many seconds the aim has to reach the new position\n");
- LOG_INFO("Examples: aim \"90 0\" // Turn 90 degrees inmediately (positive numbers move to the left/up)\n");
- LOG_INFO(" aim \"0 90 2\" // Will gradually look to the sky in the next two seconds");
- break;
- case BOT_CMD_AIMTARGET:
- LOG_INFO("Points the aim to given target");
- break;
- case BOT_CMD_PRESSKEY:
- LOG_INFO("Press one of the following keys: forward, backward, left, right, jump, crouch, attack1, attack2, use\n");
- LOG_INFO("Multiple keys can be pressed at time (with many presskey calls) and it will remain pressed until the command \"releasekey\" is called");
- LOG_INFO("Note: The script will not return the control to the bot ai until all keys are released");
- break;
- case BOT_CMD_RELEASEKEY:
- LOG_INFO("Release previoulsy used keys. Use the parameter \"all\" to release all keys");
- break;
- case BOT_CMD_SOUND:
- LOG_INFO("play sound file at bot location");
- break;
- case BOT_CMD_DEBUG_ASSERT_CANFIRE:
- LOG_INFO("verify the state of the weapon entity");
- break;
- default:
- LOG_INFO("This command has no description yet.");
- break;
- }
- LOG_INFO("\n");
- }
-}
-
-void bot_list_commands()
-{
- int i;
- string ptype;
-
- if(!bot_cmds_initialized)
- bot_commands_init();
-
- LOG_INFO("List of all available commands:\n");
- LOG_INFO(" Command - Parameter Type\n");
-
- for(i=1;i<BOT_CMD_COUNTER;++i)
- {
- switch(bot_cmd_parm_type[i])
- {
- case BOT_CMD_PARAMETER_FLOAT:
- ptype = "float number";
- break;
- case BOT_CMD_PARAMETER_STRING:
- ptype = "string";
- break;
- case BOT_CMD_PARAMETER_VECTOR:
- ptype = "vector";
- break;
- default:
- ptype = "none";
- break;
- }
- LOG_INFO(strcat(" ",bot_cmd_string[i]," - <",ptype,"> \n"));
- }
-}
-
-// Commands code
-.int bot_exec_status;
-
-float bot_cmd_cc(entity this)
-{
- SV_ParseClientCommand(this, bot_cmd.bot_cmd_parm_string);
- return CMD_STATUS_FINISHED;
-}
-
-float bot_cmd_impulse(entity this)
-{
- this.impulse = bot_cmd.bot_cmd_parm_float;
- return CMD_STATUS_FINISHED;
-}
-
-float bot_cmd_continue(entity this)
-{
- this.bot_exec_status &= ~BOT_EXEC_STATUS_PAUSED;
- return CMD_STATUS_FINISHED;
-}
-
-.float bot_cmd_wait_time;
-float bot_cmd_wait(entity this)
-{
- if(this.bot_exec_status & BOT_EXEC_STATUS_WAITING)
- {
- if(time>=this.bot_cmd_wait_time)
- {
- this.bot_exec_status &= ~BOT_EXEC_STATUS_WAITING;
- return CMD_STATUS_FINISHED;
- }
- else
- return CMD_STATUS_EXECUTING;
- }
-
- this.bot_cmd_wait_time = time + bot_cmd.bot_cmd_parm_float;
- this.bot_exec_status |= BOT_EXEC_STATUS_WAITING;
- return CMD_STATUS_EXECUTING;
-}
-
-float bot_cmd_wait_until(entity this)
-{
- if(time < bot_cmd.bot_cmd_parm_float + bot_barriertime)
- {
- this.bot_exec_status |= BOT_EXEC_STATUS_WAITING;
- return CMD_STATUS_EXECUTING;
- }
- this.bot_exec_status &= ~BOT_EXEC_STATUS_WAITING;
- return CMD_STATUS_FINISHED;
-}
-
-float bot_cmd_barrier(entity this)
-{
- // 0 = no barrier, 1 = waiting, 2 = waiting finished
-
- if(this.bot_barrier == 0) // initialization
- {
- this.bot_barrier = 1;
-
- //this.colormod = '4 4 0';
- }
-
- if(this.bot_barrier == 1) // find other bots
- {
- FOREACH_CLIENT(it.isbot, LAMBDA(
- if(it.bot_cmdqueuebuf_allocated)
- if(it.bot_barrier != 1)
- return CMD_STATUS_EXECUTING; // not all are at the barrier yet
- ));
-
- // all bots hit the barrier!
-
- // acknowledge barrier
- FOREACH_CLIENT(it.isbot, LAMBDA(it.bot_barrier = 2));
-
- bot_barriertime = time;
- }
-
- // if we get here, the barrier is finished
- // so end it...
- this.bot_barrier = 0;
- //this.colormod = '0 0 0';
-
- return CMD_STATUS_FINISHED;
-}
-
-float bot_cmd_turn(entity this)
-{
- this.v_angle_y = this.v_angle.y + bot_cmd.bot_cmd_parm_float;
- this.v_angle_y = this.v_angle.y - floor(this.v_angle.y / 360) * 360;
- return CMD_STATUS_FINISHED;
-}
-
-float bot_cmd_select_weapon(entity this)
-{
- float id = bot_cmd.bot_cmd_parm_float;
-
- if(id < WEP_FIRST || id > WEP_LAST)
- return CMD_STATUS_ERROR;
-
- if(client_hasweapon(this, Weapons_from(id), true, false))
- PS(this).m_switchweapon = Weapons_from(id);
- else
- return CMD_STATUS_ERROR;
-
- return CMD_STATUS_FINISHED;
-}
-
-.int bot_cmd_condition_status;
-
-const int CMD_CONDITION_NONE = 0;
-const int CMD_CONDITION_true = 1;
-const int CMD_CONDITION_false = 2;
-const int CMD_CONDITION_true_BLOCK = 4;
-const int CMD_CONDITION_false_BLOCK = 8;
-
-float bot_cmd_eval(entity this, string expr)
-{
- // Search for numbers
- if(strstrofs("0123456789", substring(expr, 0, 1), 0) >= 0)
- {
- return stof(expr);
- }
-
- // Search for cvars
- if(substring(expr, 0, 5)=="cvar.")
- {
- return cvar(substring(expr, 5, strlen(expr)));
- }
-
- // Search for fields
- switch(expr)
- {
- case "health":
- return this.health;
- case "speed":
- return vlen(this.velocity);
- case "flagcarrier":
- return ((this.flagcarried!=NULL));
- }
-
- LOG_INFO(strcat("ERROR: Unable to convert the expression '",expr,"' into a numeric value\n"));
- return 0;
-}
-
-float bot_cmd_if(entity this)
-{
- string expr, val_a, val_b;
- float cmpofs;
-
- if(this.bot_cmd_condition_status != CMD_CONDITION_NONE)
- {
- // Only one "if" block is allowed at time
- LOG_INFO("ERROR: Only one conditional block can be processed at time");
- bot_clearqueue(this);
- return CMD_STATUS_ERROR;
- }
-
- this.bot_cmd_condition_status |= CMD_CONDITION_true_BLOCK;
-
- // search for operators
- expr = bot_cmd.bot_cmd_parm_string;
-
- cmpofs = strstrofs(expr,"=",0);
-
- if(cmpofs>0)
- {
- val_a = substring(expr,0,cmpofs);
- val_b = substring(expr,cmpofs+1,strlen(expr));
-
- if(bot_cmd_eval(this, val_a)==bot_cmd_eval(this, val_b))
- this.bot_cmd_condition_status |= CMD_CONDITION_true;
- else
- this.bot_cmd_condition_status |= CMD_CONDITION_false;
-
- return CMD_STATUS_FINISHED;
- }
-
- cmpofs = strstrofs(expr,">",0);
-
- if(cmpofs>0)
- {
- val_a = substring(expr,0,cmpofs);
- val_b = substring(expr,cmpofs+1,strlen(expr));
-
- if(bot_cmd_eval(this, val_a)>bot_cmd_eval(this, val_b))
- this.bot_cmd_condition_status |= CMD_CONDITION_true;
- else
- this.bot_cmd_condition_status |= CMD_CONDITION_false;
-
- return CMD_STATUS_FINISHED;
- }
-
- cmpofs = strstrofs(expr,"<",0);
-
- if(cmpofs>0)
- {
- val_a = substring(expr,0,cmpofs);
- val_b = substring(expr,cmpofs+1,strlen(expr));
-
- if(bot_cmd_eval(this, val_a)<bot_cmd_eval(this, val_b))
- this.bot_cmd_condition_status |= CMD_CONDITION_true;
- else
- this.bot_cmd_condition_status |= CMD_CONDITION_false;
-
- return CMD_STATUS_FINISHED;
- }
-
- if(bot_cmd_eval(this, expr))
- this.bot_cmd_condition_status |= CMD_CONDITION_true;
- else
- this.bot_cmd_condition_status |= CMD_CONDITION_false;
-
- return CMD_STATUS_FINISHED;
-}
-
-float bot_cmd_else(entity this)
-{
- this.bot_cmd_condition_status &= ~CMD_CONDITION_true_BLOCK;
- this.bot_cmd_condition_status |= CMD_CONDITION_false_BLOCK;
- return CMD_STATUS_FINISHED;
-}
-
-float bot_cmd_fi(entity this)
-{
- this.bot_cmd_condition_status = CMD_CONDITION_NONE;
- return CMD_STATUS_FINISHED;
-}
-
-float bot_cmd_resetaim(entity this)
-{
- this.v_angle = '0 0 0';
- return CMD_STATUS_FINISHED;
-}
-
-.float bot_cmd_aim_begintime;
-.float bot_cmd_aim_endtime;
-.vector bot_cmd_aim_begin;
-.vector bot_cmd_aim_end;
-
-float bot_cmd_aim(entity this)
-{
- // Current direction
- if(this.bot_cmd_aim_endtime)
- {
- float progress;
-
- progress = min(1 - (this.bot_cmd_aim_endtime - time) / (this.bot_cmd_aim_endtime - this.bot_cmd_aim_begintime),1);
- this.v_angle = this.bot_cmd_aim_begin + ((this.bot_cmd_aim_end - this.bot_cmd_aim_begin) * progress);
-
- if(time>=this.bot_cmd_aim_endtime)
- {
- this.bot_cmd_aim_endtime = 0;
- return CMD_STATUS_FINISHED;
- }
- else
- return CMD_STATUS_EXECUTING;
- }
-
- // New aiming direction
- string parms;
- float tokens, step;
-
- parms = bot_cmd.bot_cmd_parm_string;
-
- tokens = tokenizebyseparator(parms, " ");
-
- if(tokens<2||tokens>3)
- return CMD_STATUS_ERROR;
-
- step = (tokens == 3) ? stof(argv(2)) : 0;
-
- if(step == 0)
- {
- this.v_angle_x -= stof(argv(1));
- this.v_angle_y += stof(argv(0));
- return CMD_STATUS_FINISHED;
- }
-
- this.bot_cmd_aim_begin = this.v_angle;
-
- this.bot_cmd_aim_end_x = this.v_angle.x - stof(argv(1));
- this.bot_cmd_aim_end_y = this.v_angle.y + stof(argv(0));
- this.bot_cmd_aim_end_z = 0;
-
- this.bot_cmd_aim_begintime = time;
- this.bot_cmd_aim_endtime = time + step;
-
- return CMD_STATUS_EXECUTING;
-}
-
-float bot_cmd_aimtarget(entity this)
-{
- if(this.bot_cmd_aim_endtime)
- {
- return bot_cmd_aim(this);
- }
-
- entity e;
- string parms;
- vector v;
- float tokens, step;
-
- parms = bot_cmd.bot_cmd_parm_string;
-
- tokens = tokenizebyseparator(parms, " ");
-
- e = bot_getplace(this, argv(0));
- if(!e)
- return CMD_STATUS_ERROR;
-
- v = e.origin + (e.mins + e.maxs) * 0.5;
-
- if(tokens==1)
- {
- this.v_angle = vectoangles(v - (this.origin + this.view_ofs));
- this.v_angle_x = -this.v_angle.x;
- return CMD_STATUS_FINISHED;
- }
-
- if(tokens<1||tokens>2)
- return CMD_STATUS_ERROR;
-
- step = stof(argv(1));
-
- this.bot_cmd_aim_begin = this.v_angle;
- this.bot_cmd_aim_end = vectoangles(v - (this.origin + this.view_ofs));
- this.bot_cmd_aim_end_x = -this.bot_cmd_aim_end.x;
-
- this.bot_cmd_aim_begintime = time;
- this.bot_cmd_aim_endtime = time + step;
-
- return CMD_STATUS_EXECUTING;
-}
-
-.int bot_cmd_keys;
-
-const int BOT_CMD_KEY_NONE = 0;
-const int BOT_CMD_KEY_FORWARD = BIT(0);
-const int BOT_CMD_KEY_BACKWARD = BIT(1);
-const int BOT_CMD_KEY_RIGHT = BIT(2);
-const int BOT_CMD_KEY_LEFT = BIT(3);
-const int BOT_CMD_KEY_JUMP = BIT(4);
-const int BOT_CMD_KEY_ATTACK1 = BIT(5);
-const int BOT_CMD_KEY_ATTACK2 = BIT(6);
-const int BOT_CMD_KEY_USE = BIT(7);
-const int BOT_CMD_KEY_HOOK = BIT(8);
-const int BOT_CMD_KEY_CROUCH = BIT(9);
-const int BOT_CMD_KEY_CHAT = BIT(10);
-
-bool bot_presskeys(entity this)
-{
- this.movement = '0 0 0';
- PHYS_INPUT_BUTTON_JUMP(this) = false;
- PHYS_INPUT_BUTTON_CROUCH(this) = false;
- PHYS_INPUT_BUTTON_ATCK(this) = false;
- PHYS_INPUT_BUTTON_ATCK2(this) = false;
- PHYS_INPUT_BUTTON_USE(this) = false;
- PHYS_INPUT_BUTTON_HOOK(this) = false;
- PHYS_INPUT_BUTTON_CHAT(this) = false;
-
- if(this.bot_cmd_keys == BOT_CMD_KEY_NONE)
- return false;
-
- if(this.bot_cmd_keys & BOT_CMD_KEY_FORWARD)
- this.movement_x = autocvar_sv_maxspeed;
- else if(this.bot_cmd_keys & BOT_CMD_KEY_BACKWARD)
- this.movement_x = -autocvar_sv_maxspeed;
-
- if(this.bot_cmd_keys & BOT_CMD_KEY_RIGHT)
- this.movement_y = autocvar_sv_maxspeed;
- else if(this.bot_cmd_keys & BOT_CMD_KEY_LEFT)
- this.movement_y = -autocvar_sv_maxspeed;
-
- if(this.bot_cmd_keys & BOT_CMD_KEY_JUMP)
- PHYS_INPUT_BUTTON_JUMP(this) = true;
-
- if(this.bot_cmd_keys & BOT_CMD_KEY_CROUCH)
- PHYS_INPUT_BUTTON_CROUCH(this) = true;
-
- if(this.bot_cmd_keys & BOT_CMD_KEY_ATTACK1)
- PHYS_INPUT_BUTTON_ATCK(this) = true;
-
- if(this.bot_cmd_keys & BOT_CMD_KEY_ATTACK2)
- PHYS_INPUT_BUTTON_ATCK2(this) = true;
-
- if(this.bot_cmd_keys & BOT_CMD_KEY_USE)
- PHYS_INPUT_BUTTON_USE(this) = true;
-
- if(this.bot_cmd_keys & BOT_CMD_KEY_HOOK)
- PHYS_INPUT_BUTTON_HOOK(this) = true;
-
- if(this.bot_cmd_keys & BOT_CMD_KEY_CHAT)
- PHYS_INPUT_BUTTON_CHAT(this) = true;
-
- return true;
-}
-
-
-float bot_cmd_keypress_handler(entity this, string key, float enabled)
-{
- switch(key)
- {
- case "all":
- if(enabled)
- this.bot_cmd_keys = power2of(20) - 1; // >:)
- else
- this.bot_cmd_keys = BOT_CMD_KEY_NONE;
- case "forward":
- if(enabled)
- {
- this.bot_cmd_keys |= BOT_CMD_KEY_FORWARD;
- this.bot_cmd_keys &= ~BOT_CMD_KEY_BACKWARD;
- }
- else
- this.bot_cmd_keys &= ~BOT_CMD_KEY_FORWARD;
- break;
- case "backward":
- if(enabled)
- {
- this.bot_cmd_keys |= BOT_CMD_KEY_BACKWARD;
- this.bot_cmd_keys &= ~BOT_CMD_KEY_FORWARD;
- }
- else
- this.bot_cmd_keys &= ~BOT_CMD_KEY_BACKWARD;
- break;
- case "left":
- if(enabled)
- {
- this.bot_cmd_keys |= BOT_CMD_KEY_LEFT;
- this.bot_cmd_keys &= ~BOT_CMD_KEY_RIGHT;
- }
- else
- this.bot_cmd_keys &= ~BOT_CMD_KEY_LEFT;
- break;
- case "right":
- if(enabled)
- {
- this.bot_cmd_keys |= BOT_CMD_KEY_RIGHT;
- this.bot_cmd_keys &= ~BOT_CMD_KEY_LEFT;
- }
- else
- this.bot_cmd_keys &= ~BOT_CMD_KEY_RIGHT;
- break;
- case "jump":
- if(enabled)
- this.bot_cmd_keys |= BOT_CMD_KEY_JUMP;
- else
- this.bot_cmd_keys &= ~BOT_CMD_KEY_JUMP;
- break;
- case "crouch":
- if(enabled)
- this.bot_cmd_keys |= BOT_CMD_KEY_CROUCH;
- else
- this.bot_cmd_keys &= ~BOT_CMD_KEY_CROUCH;
- break;
- case "attack1":
- if(enabled)
- this.bot_cmd_keys |= BOT_CMD_KEY_ATTACK1;
- else
- this.bot_cmd_keys &= ~BOT_CMD_KEY_ATTACK1;
- break;
- case "attack2":
- if(enabled)
- this.bot_cmd_keys |= BOT_CMD_KEY_ATTACK2;
- else
- this.bot_cmd_keys &= ~BOT_CMD_KEY_ATTACK2;
- break;
- case "use":
- if(enabled)
- this.bot_cmd_keys |= BOT_CMD_KEY_USE;
- else
- this.bot_cmd_keys &= ~BOT_CMD_KEY_USE;
- break;
- case "hook":
- if(enabled)
- this.bot_cmd_keys |= BOT_CMD_KEY_HOOK;
- else
- this.bot_cmd_keys &= ~BOT_CMD_KEY_HOOK;
- break;
- case "chat":
- if(enabled)
- this.bot_cmd_keys |= BOT_CMD_KEY_CHAT;
- else
- this.bot_cmd_keys &= ~BOT_CMD_KEY_CHAT;
- break;
- default:
- break;
- }
-
- return CMD_STATUS_FINISHED;
-}
-
-float bot_cmd_presskey(entity this)
-{
- string key;
-
- key = bot_cmd.bot_cmd_parm_string;
-
- bot_cmd_keypress_handler(this, key,true);
-
- return CMD_STATUS_FINISHED;
-}
-
-float bot_cmd_releasekey(entity this)
-{
- string key;
-
- key = bot_cmd.bot_cmd_parm_string;
-
- return bot_cmd_keypress_handler(this, key,false);
-}
-
-float bot_cmd_pause(entity this)
-{
- PHYS_INPUT_BUTTON_DRAG(this) = false;
- PHYS_INPUT_BUTTON_USE(this) = false;
- PHYS_INPUT_BUTTON_ATCK(this) = false;
- PHYS_INPUT_BUTTON_JUMP(this) = false;
- PHYS_INPUT_BUTTON_HOOK(this) = false;
- PHYS_INPUT_BUTTON_CHAT(this) = false;
- PHYS_INPUT_BUTTON_ATCK2(this) = false;
- PHYS_INPUT_BUTTON_CROUCH(this) = false;
-
- this.movement = '0 0 0';
- this.bot_cmd_keys = BOT_CMD_KEY_NONE;
-
- this.bot_exec_status |= BOT_EXEC_STATUS_PAUSED;
- return CMD_STATUS_FINISHED;
-}
-
-float bot_cmd_moveto(entity this)
-{
- return this.cmd_moveto(this, bot_cmd.bot_cmd_parm_vector);
-}
-
-float bot_cmd_movetotarget(entity this)
-{
- entity e;
- e = bot_getplace(this, bot_cmd.bot_cmd_parm_string);
- if(!e)
- return CMD_STATUS_ERROR;
- return this.cmd_moveto(this, e.origin + (e.mins + e.maxs) * 0.5);
-}
-
-float bot_cmd_resetgoal(entity this)
-{
- return this.cmd_resetgoal(this);
-}
-
-
-float bot_cmd_sound(entity this)
-{
- string f;
- f = bot_cmd.bot_cmd_parm_string;
-
- float n = tokenizebyseparator(f, " ");
-
- string sample = f;
- float chan = CH_WEAPON_B;
- float vol = VOL_BASE;
- float atten = ATTEN_MIN;
-
- if(n >= 1)
- sample = argv(n - 1);
- if(n >= 2)
- chan = stof(argv(0));
- if(n >= 3)
- vol = stof(argv(1));
- if(n >= 4)
- atten = stof(argv(2));
-
- precache_sound(f);
- _sound(this, chan, sample, vol, atten);
-
- return CMD_STATUS_FINISHED;
-}
-
-.entity tuba_note;
-float bot_cmd_debug_assert_canfire(entity this)
-{
- float f = bot_cmd.bot_cmd_parm_float;
-
- int slot = 0;
- .entity weaponentity = weaponentities[slot];
- if(this.(weaponentity).state != WS_READY)
- {
- if(f)
- {
- this.colormod = '0 8 8';
- LOG_INFO("Bot ", this.netname, " using ", this.weaponname, " wants to fire, inhibited by weaponentity state\n");
- }
- }
- else if(ATTACK_FINISHED(this, slot) > time)
- {
- if(f)
- {
- this.colormod = '8 0 8';
- LOG_INFO("Bot ", this.netname, " using ", this.weaponname, " wants to fire, inhibited by ATTACK_FINISHED (", ftos(ATTACK_FINISHED(this, slot) - time), " seconds left)\n");
- }
- }
- else if(this.tuba_note)
- {
- if(f)
- {
- this.colormod = '8 0 0';
- LOG_INFO("Bot ", this.netname, " using ", this.weaponname, " wants to fire, bot still has an active tuba note\n");
- }
- }
- else
- {
- if(!f)
- {
- this.colormod = '8 8 0';
- LOG_INFO("Bot ", this.netname, " using ", this.weaponname, " thinks it has fired, but apparently did not; ATTACK_FINISHED says ", ftos(ATTACK_FINISHED(this, slot) - time), " seconds left\n");
- }
- }
-
- return CMD_STATUS_FINISHED;
-}
-
-//
-
-void bot_command_executed(entity this, bool rm)
-{
- entity cmd;
-
- cmd = bot_cmd;
-
- if(rm)
- bot_dequeuecommand(this, this.bot_cmd_execution_index);
-
- this.bot_cmd_execution_index++;
-}
-
-void bot_setcurrentcommand(entity this)
-{
- bot_cmd = NULL;
-
- if(!this.bot_cmd_current)
- {
- this.bot_cmd_current = new_pure(bot_cmd);
- this.bot_cmd_current.is_bot_cmd = true;
- }
-
- bot_cmd = this.bot_cmd_current;
- if(bot_cmd.bot_cmd_index != this.bot_cmd_execution_index || this.bot_cmd_execution_index == 0)
- {
- if(bot_havecommand(this, this.bot_cmd_execution_index))
- {
- string cmdstring;
- cmdstring = bot_readcommand(this, this.bot_cmd_execution_index);
- if(bot_decodecommand(cmdstring))
- {
- bot_cmd.owner = this;
- bot_cmd.bot_cmd_index = this.bot_cmd_execution_index;
- }
- else
- {
- // Invalid command, remove from queue
- bot_cmd = NULL;
- bot_dequeuecommand(this, this.bot_cmd_execution_index);
- this.bot_cmd_execution_index++;
- }
- }
- else
- bot_cmd = NULL;
- }
-}
-
-void bot_resetqueues()
-{
- FOREACH_CLIENT(it.isbot, LAMBDA(
- it.bot_cmd_execution_index = 0;
- bot_clearqueue(it);
- // also, cancel all barriers
- it.bot_barrier = 0;
- for(int i = 0; i < it.bot_places_count; ++i)
- {
- strunzone(it.(bot_placenames[i]));
- it.(bot_placenames[i]) = string_null;
- }
- it.bot_places_count = 0;
- ));
-
- bot_barriertime = time;
-}
-
-// Here we map commands to functions and deal with complex interactions between commands and execution states
-// NOTE: Of course you need to include your commands here too :)
-float bot_execute_commands_once(entity this)
-{
- float status, ispressingkey;
-
- // Find command
- bot_setcurrentcommand(this);
-
- // if we have no bot command, better return
- // old logic kept pressing previously pressed keys, but that has problems
- // (namely, it means you cannot make a bot "normal" ever again)
- // to keep a bot walking for a while, use the "wait" bot command
- if(bot_cmd == NULL)
- return false;
-
- // Ignore all commands except continue when the bot is paused
- if(this.bot_exec_status & BOT_EXEC_STATUS_PAUSED)
- if(bot_cmd.bot_cmd_type!=BOT_CMD_CONTINUE)
- {
- if(bot_cmd.bot_cmd_type!=BOT_CMD_NULL)
- {
- bot_command_executed(this, true);
- LOG_INFO( "WARNING: Commands are ignored while the bot is paused. Use the command 'continue' instead.\n");
- }
- return 1;
- }
-
- // Keep pressing keys raised by the "presskey" command
- ispressingkey = boolean(bot_presskeys(this));
-
- // Handle conditions
- if (!(bot_cmd.bot_cmd_type==BOT_CMD_FI||bot_cmd.bot_cmd_type==BOT_CMD_ELSE))
- if(this.bot_cmd_condition_status & CMD_CONDITION_true && this.bot_cmd_condition_status & CMD_CONDITION_false_BLOCK)
- {
- bot_command_executed(this, true);
- return -1;
- }
- else if(this.bot_cmd_condition_status & CMD_CONDITION_false && this.bot_cmd_condition_status & CMD_CONDITION_true_BLOCK)
- {
- bot_command_executed(this, true);
- return -1;
- }
-
- // Map commands to functions
- switch(bot_cmd.bot_cmd_type)
- {
- case BOT_CMD_NULL:
- return ispressingkey;
- //break;
- case BOT_CMD_PAUSE:
- status = bot_cmd_pause(this);
- break;
- case BOT_CMD_CONTINUE:
- status = bot_cmd_continue(this);
- break;
- case BOT_CMD_WAIT:
- status = bot_cmd_wait(this);
- break;
- case BOT_CMD_WAIT_UNTIL:
- status = bot_cmd_wait_until(this);
- break;
- case BOT_CMD_TURN:
- status = bot_cmd_turn(this);
- break;
- case BOT_CMD_MOVETO:
- status = bot_cmd_moveto(this);
- break;
- case BOT_CMD_MOVETOTARGET:
- status = bot_cmd_movetotarget(this);
- break;
- case BOT_CMD_RESETGOAL:
- status = bot_cmd_resetgoal(this);
- break;
- case BOT_CMD_CC:
- status = bot_cmd_cc(this);
- break;
- case BOT_CMD_IF:
- status = bot_cmd_if(this);
- break;
- case BOT_CMD_ELSE:
- status = bot_cmd_else(this);
- break;
- case BOT_CMD_FI:
- status = bot_cmd_fi(this);
- break;
- case BOT_CMD_RESETAIM:
- status = bot_cmd_resetaim(this);
- break;
- case BOT_CMD_AIM:
- status = bot_cmd_aim(this);
- break;
- case BOT_CMD_AIMTARGET:
- status = bot_cmd_aimtarget(this);
- break;
- case BOT_CMD_PRESSKEY:
- status = bot_cmd_presskey(this);
- break;
- case BOT_CMD_RELEASEKEY:
- status = bot_cmd_releasekey(this);
- break;
- case BOT_CMD_SELECTWEAPON:
- status = bot_cmd_select_weapon(this);
- break;
- case BOT_CMD_IMPULSE:
- status = bot_cmd_impulse(this);
- break;
- case BOT_CMD_BARRIER:
- status = bot_cmd_barrier(this);
- break;
- case BOT_CMD_CONSOLE:
- localcmd(strcat(bot_cmd.bot_cmd_parm_string, "\n"));
- status = CMD_STATUS_FINISHED;
- break;
- case BOT_CMD_SOUND:
- status = bot_cmd_sound(this);
- break;
- case BOT_CMD_DEBUG_ASSERT_CANFIRE:
- status = bot_cmd_debug_assert_canfire(this);
- break;
- default:
- LOG_INFO(strcat("ERROR: Invalid command on queue with id '",ftos(bot_cmd.bot_cmd_type),"'\n"));
- return 0;
- }
-
- if (status==CMD_STATUS_ERROR)
- LOG_INFO(strcat("ERROR: The command '",bot_cmd_string[bot_cmd.bot_cmd_type],"' returned an error status\n"));
-
- // Move execution pointer
- if(status==CMD_STATUS_EXECUTING)
- {
- return 1;
- }
- else
- {
- if(autocvar_g_debug_bot_commands)
- {
- string parms;
-
- switch(bot_cmd_parm_type[bot_cmd.bot_cmd_type])
- {
- case BOT_CMD_PARAMETER_FLOAT:
- parms = ftos(bot_cmd.bot_cmd_parm_float);
- break;
- case BOT_CMD_PARAMETER_STRING:
- parms = bot_cmd.bot_cmd_parm_string;
- break;
- case BOT_CMD_PARAMETER_VECTOR:
- parms = vtos(bot_cmd.bot_cmd_parm_vector);
- break;
- default:
- parms = "";
- break;
- }
- clientcommand(this,strcat("say ^7", bot_cmd_string[bot_cmd.bot_cmd_type]," ",parms,"\n"));
- }
-
- bot_command_executed(this, true);
- }
-
- if(status == CMD_STATUS_FINISHED)
- return -1;
-
- return CMD_STATUS_ERROR;
-}
-
-// This function should be (the only) called directly from the bot ai loop
-int bot_execute_commands(entity this)
-{
- int f;
- do
- {
- f = bot_execute_commands_once(this);
- }
- while(f < 0);
- return f;
-}
+++ /dev/null
-#pragma once
-
-#define BOT_EXEC_STATUS_IDLE 0
-#define BOT_EXEC_STATUS_PAUSED 1
-#define BOT_EXEC_STATUS_WAITING 2
-
-#define CMD_STATUS_EXECUTING 0
-#define CMD_STATUS_FINISHED 1
-#define CMD_STATUS_ERROR 2
-
-
-// NOTE: New commands should be added here. Do not forget to update BOT_CMD_COUNTER
-const int BOT_CMD_NULL = 0;
-const int BOT_CMD_PAUSE = 1;
-const int BOT_CMD_CONTINUE = 2;
-const int BOT_CMD_WAIT = 3;
-const int BOT_CMD_TURN = 4;
-const int BOT_CMD_MOVETO = 5;
-const int BOT_CMD_RESETGOAL = 6; // Not implemented yet
-const int BOT_CMD_CC = 7;
-const int BOT_CMD_IF = 8;
-const int BOT_CMD_ELSE = 9;
-const int BOT_CMD_FI = 10;
-const int BOT_CMD_RESETAIM = 11;
-const int BOT_CMD_AIM = 12;
-const int BOT_CMD_PRESSKEY = 13;
-const int BOT_CMD_RELEASEKEY = 14;
-const int BOT_CMD_SELECTWEAPON = 15;
-const int BOT_CMD_IMPULSE = 16;
-const int BOT_CMD_WAIT_UNTIL = 17;
-const int BOT_CMD_MOVETOTARGET = 18;
-const int BOT_CMD_AIMTARGET = 19;
-const int BOT_CMD_BARRIER = 20;
-const int BOT_CMD_CONSOLE = 21;
-const int BOT_CMD_SOUND = 22;
-const int BOT_CMD_DEBUG_ASSERT_CANFIRE = 23;
-const int BOT_CMD_WHILE = 24; // TODO: Not implemented yet
-const int BOT_CMD_WEND = 25; // TODO: Not implemented yet
-const int BOT_CMD_CHASE = 26; // TODO: Not implemented yet
-
-const int BOT_CMD_COUNTER = 24; // Update this value if you add/remove a command
-
-// NOTE: Following commands should be implemented on the bot ai
-// If a new command should be handled by the target ai(s) please declare it here
-.float(entity, vector) cmd_moveto;
-.float(entity) cmd_resetgoal;
-
-//
-const int BOT_CMD_PARAMETER_NONE = 0;
-const int BOT_CMD_PARAMETER_FLOAT = 1;
-const int BOT_CMD_PARAMETER_STRING = 2;
-const int BOT_CMD_PARAMETER_VECTOR = 3;
-
-float bot_cmds_initialized;
-int bot_cmd_parm_type[BOT_CMD_COUNTER];
-string bot_cmd_string[BOT_CMD_COUNTER];
-
-// Bots command queue
-entity bot_cmd; // global current command
-.entity bot_cmd_current; // current command of this bot
-
-.float is_bot_cmd; // Tells if the entity is a bot command
-.float bot_cmd_index; // Position of the command in the queue
-.int bot_cmd_type; // If of command (see the BOT_CMD_* defines)
-.float bot_cmd_parm_float; // Field to store a float parameter
-.string bot_cmd_parm_string; // Field to store a string parameter
-.vector bot_cmd_parm_vector; // Field to store a vector parameter
-
-float bot_barriertime;
-.float bot_barrier;
-
-.float bot_cmd_execution_index; // Position in the queue of the command to be executed
-
-
-void bot_resetqueues();
-void bot_queuecommand(entity bot, string cmdstring);
-void bot_cmdhelp(string scmd);
-void bot_list_commands();
-float bot_execute_commands(entity this);
-entity find_bot_by_name(string name);
-entity find_bot_by_number(float number);
+++ /dev/null
-#include "waypoints.qh"
-
-#include "bot.qh"
-#include "navigation.qh"
-
-#include <common/state.qh>
-
-#include "../antilag.qh"
-
-#include <common/constants.qh>
-
-#include <lib/warpzone/common.qh>
-#include <lib/warpzone/util_server.qh>
-
-// create a new spawnfunc_waypoint and automatically link it to other waypoints, and link
-// them back to it as well
-// (suitable for spawnfunc_waypoint editor)
-entity waypoint_spawn(vector m1, vector m2, float f)
-{
- if(!(f & WAYPOINTFLAG_PERSONAL))
- {
- IL_EACH(g_waypoints, boxesoverlap(m1, m2, it.absmin, it.absmax),
- {
- return it;
- });
- }
-
- entity w = new(waypoint);
- IL_PUSH(g_waypoints, w);
- w.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
- w.wpflags = f;
- w.solid = SOLID_TRIGGER;
- setorigin(w, (m1 + m2) * 0.5);
- setsize(w, m1 - w.origin, m2 - w.origin);
- if (vlen(w.size) > 0)
- w.wpisbox = true;
-
- if(!w.wpisbox)
- {
- setsize(w, STAT(PL_MIN, NULL) - '1 1 0', STAT(PL_MAX, NULL) + '1 1 0');
- if(!move_out_of_solid(w))
- {
- if(!(f & WAYPOINTFLAG_GENERATED))
- {
- LOG_TRACE("Killed a waypoint that was stuck in solid at ", vtos(w.origin), "\n");
- remove(w);
- return NULL;
- }
- else
- {
- if(autocvar_developer)
- {
- LOG_INFO("A generated waypoint is stuck in solid at ", vtos(w.origin), "\n");
- backtrace("Waypoint stuck");
- }
- }
- }
- setsize(w, '0 0 0', '0 0 0');
- }
-
- waypoint_clearlinks(w);
- //waypoint_schedulerelink(w);
-
- if (autocvar_g_waypointeditor)
- {
- m1 = w.mins;
- m2 = w.maxs;
- setmodel(w, MDL_WAYPOINT); w.effects = EF_LOWPRECISION;
- setsize(w, m1, m2);
- if (w.wpflags & WAYPOINTFLAG_ITEM)
- w.colormod = '1 0 0';
- else if (w.wpflags & WAYPOINTFLAG_GENERATED)
- w.colormod = '1 1 0';
- else
- w.colormod = '1 1 1';
- }
- else
- w.model = "";
-
- return w;
-}
-
-// add a new link to the spawnfunc_waypoint, replacing the furthest link it already has
-void waypoint_addlink(entity from, entity to)
-{
- float c;
-
- if (from == to)
- return;
- if (from.wpflags & WAYPOINTFLAG_NORELINK)
- return;
-
- if (from.wp00 == to) return;if (from.wp01 == to) return;if (from.wp02 == to) return;if (from.wp03 == to) return;
- if (from.wp04 == to) return;if (from.wp05 == to) return;if (from.wp06 == to) return;if (from.wp07 == to) return;
- if (from.wp08 == to) return;if (from.wp09 == to) return;if (from.wp10 == to) return;if (from.wp11 == to) return;
- if (from.wp12 == to) return;if (from.wp13 == to) return;if (from.wp14 == to) return;if (from.wp15 == to) return;
- if (from.wp16 == to) return;if (from.wp17 == to) return;if (from.wp18 == to) return;if (from.wp19 == to) return;
- if (from.wp20 == to) return;if (from.wp21 == to) return;if (from.wp22 == to) return;if (from.wp23 == to) return;
- if (from.wp24 == to) return;if (from.wp25 == to) return;if (from.wp26 == to) return;if (from.wp27 == to) return;
- if (from.wp28 == to) return;if (from.wp29 == to) return;if (from.wp30 == to) return;if (from.wp31 == to) return;
-
- if (to.wpisbox || from.wpisbox)
- {
- // if either is a box we have to find the nearest points on them to
- // calculate the distance properly
- vector v1, v2, m1, m2;
- v1 = from.origin;
- m1 = to.absmin;
- m2 = to.absmax;
- v1_x = bound(m1_x, v1_x, m2_x);
- v1_y = bound(m1_y, v1_y, m2_y);
- v1_z = bound(m1_z, v1_z, m2_z);
- v2 = to.origin;
- m1 = from.absmin;
- m2 = from.absmax;
- v2_x = bound(m1_x, v2_x, m2_x);
- v2_y = bound(m1_y, v2_y, m2_y);
- v2_z = bound(m1_z, v2_z, m2_z);
- v2 = to.origin;
- c = vlen(v2 - v1);
- }
- else
- c = vlen(to.origin - from.origin);
-
- if (from.wp31mincost < c) return;
- if (from.wp30mincost < c) {from.wp31 = to;from.wp31mincost = c;return;} from.wp31 = from.wp30;from.wp31mincost = from.wp30mincost;
- if (from.wp29mincost < c) {from.wp30 = to;from.wp30mincost = c;return;} from.wp30 = from.wp29;from.wp30mincost = from.wp29mincost;
- if (from.wp28mincost < c) {from.wp29 = to;from.wp29mincost = c;return;} from.wp29 = from.wp28;from.wp29mincost = from.wp28mincost;
- if (from.wp27mincost < c) {from.wp28 = to;from.wp28mincost = c;return;} from.wp28 = from.wp27;from.wp28mincost = from.wp27mincost;
- if (from.wp26mincost < c) {from.wp27 = to;from.wp27mincost = c;return;} from.wp27 = from.wp26;from.wp27mincost = from.wp26mincost;
- if (from.wp25mincost < c) {from.wp26 = to;from.wp26mincost = c;return;} from.wp26 = from.wp25;from.wp26mincost = from.wp25mincost;
- if (from.wp24mincost < c) {from.wp25 = to;from.wp25mincost = c;return;} from.wp25 = from.wp24;from.wp25mincost = from.wp24mincost;
- if (from.wp23mincost < c) {from.wp24 = to;from.wp24mincost = c;return;} from.wp24 = from.wp23;from.wp24mincost = from.wp23mincost;
- if (from.wp22mincost < c) {from.wp23 = to;from.wp23mincost = c;return;} from.wp23 = from.wp22;from.wp23mincost = from.wp22mincost;
- if (from.wp21mincost < c) {from.wp22 = to;from.wp22mincost = c;return;} from.wp22 = from.wp21;from.wp22mincost = from.wp21mincost;
- if (from.wp20mincost < c) {from.wp21 = to;from.wp21mincost = c;return;} from.wp21 = from.wp20;from.wp21mincost = from.wp20mincost;
- if (from.wp19mincost < c) {from.wp20 = to;from.wp20mincost = c;return;} from.wp20 = from.wp19;from.wp20mincost = from.wp19mincost;
- if (from.wp18mincost < c) {from.wp19 = to;from.wp19mincost = c;return;} from.wp19 = from.wp18;from.wp19mincost = from.wp18mincost;
- if (from.wp17mincost < c) {from.wp18 = to;from.wp18mincost = c;return;} from.wp18 = from.wp17;from.wp18mincost = from.wp17mincost;
- if (from.wp16mincost < c) {from.wp17 = to;from.wp17mincost = c;return;} from.wp17 = from.wp16;from.wp17mincost = from.wp16mincost;
- if (from.wp15mincost < c) {from.wp16 = to;from.wp16mincost = c;return;} from.wp16 = from.wp15;from.wp16mincost = from.wp15mincost;
- if (from.wp14mincost < c) {from.wp15 = to;from.wp15mincost = c;return;} from.wp15 = from.wp14;from.wp15mincost = from.wp14mincost;
- if (from.wp13mincost < c) {from.wp14 = to;from.wp14mincost = c;return;} from.wp14 = from.wp13;from.wp14mincost = from.wp13mincost;
- if (from.wp12mincost < c) {from.wp13 = to;from.wp13mincost = c;return;} from.wp13 = from.wp12;from.wp13mincost = from.wp12mincost;
- if (from.wp11mincost < c) {from.wp12 = to;from.wp12mincost = c;return;} from.wp12 = from.wp11;from.wp12mincost = from.wp11mincost;
- if (from.wp10mincost < c) {from.wp11 = to;from.wp11mincost = c;return;} from.wp11 = from.wp10;from.wp11mincost = from.wp10mincost;
- if (from.wp09mincost < c) {from.wp10 = to;from.wp10mincost = c;return;} from.wp10 = from.wp09;from.wp10mincost = from.wp09mincost;
- if (from.wp08mincost < c) {from.wp09 = to;from.wp09mincost = c;return;} from.wp09 = from.wp08;from.wp09mincost = from.wp08mincost;
- if (from.wp07mincost < c) {from.wp08 = to;from.wp08mincost = c;return;} from.wp08 = from.wp07;from.wp08mincost = from.wp07mincost;
- if (from.wp06mincost < c) {from.wp07 = to;from.wp07mincost = c;return;} from.wp07 = from.wp06;from.wp07mincost = from.wp06mincost;
- if (from.wp05mincost < c) {from.wp06 = to;from.wp06mincost = c;return;} from.wp06 = from.wp05;from.wp06mincost = from.wp05mincost;
- if (from.wp04mincost < c) {from.wp05 = to;from.wp05mincost = c;return;} from.wp05 = from.wp04;from.wp05mincost = from.wp04mincost;
- if (from.wp03mincost < c) {from.wp04 = to;from.wp04mincost = c;return;} from.wp04 = from.wp03;from.wp04mincost = from.wp03mincost;
- if (from.wp02mincost < c) {from.wp03 = to;from.wp03mincost = c;return;} from.wp03 = from.wp02;from.wp03mincost = from.wp02mincost;
- if (from.wp01mincost < c) {from.wp02 = to;from.wp02mincost = c;return;} from.wp02 = from.wp01;from.wp02mincost = from.wp01mincost;
- if (from.wp00mincost < c) {from.wp01 = to;from.wp01mincost = c;return;} from.wp01 = from.wp00;from.wp01mincost = from.wp00mincost;
- from.wp00 = to;from.wp00mincost = c;return;
-}
-
-// relink this spawnfunc_waypoint
-// (precompile a list of all reachable waypoints from this spawnfunc_waypoint)
-// (SLOW!)
-void waypoint_think(entity this)
-{
- vector sv, sm1, sm2, ev, em1, em2, dv;
-
- bot_calculate_stepheightvec();
-
- bot_navigation_movemode = ((autocvar_bot_navigation_ignoreplayers) ? MOVE_NOMONSTERS : MOVE_NORMAL);
-
- //dprint("waypoint_think wpisbox = ", ftos(this.wpisbox), "\n");
- sm1 = this.origin + this.mins;
- sm2 = this.origin + this.maxs;
- IL_EACH(g_waypoints, true,
- {
- if (boxesoverlap(this.absmin, this.absmax, it.absmin, it.absmax))
- {
- waypoint_addlink(this, it);
- waypoint_addlink(it, this);
- }
- else
- {
- ++relink_total;
- if(!checkpvs(this.origin, it))
- {
- ++relink_pvsculled;
- continue;
- }
- sv = it.origin;
- sv.x = bound(sm1_x, sv.x, sm2_x);
- sv.y = bound(sm1_y, sv.y, sm2_y);
- sv.z = bound(sm1_z, sv.z, sm2_z);
- ev = this.origin;
- em1 = it.origin + it.mins;
- em2 = it.origin + it.maxs;
- ev.x = bound(em1_x, ev.x, em2_x);
- ev.y = bound(em1_y, ev.y, em2_y);
- ev.z = bound(em1_z, ev.z, em2_z);
- dv = ev - sv;
- dv.z = 0;
- if(vdist(dv, >=, 1050)) // max search distance in XY
- {
- ++relink_lengthculled;
- continue;
- }
- navigation_testtracewalk = 0;
- if (!this.wpisbox)
- {
- tracebox(sv - STAT(PL_MIN, NULL).z * '0 0 1', STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), sv, false, this);
- if (!trace_startsolid)
- {
- //dprint("sv deviation", vtos(trace_endpos - sv), "\n");
- sv = trace_endpos + '0 0 1';
- }
- }
- if (!it.wpisbox)
- {
- tracebox(ev - STAT(PL_MIN, NULL).z * '0 0 1', STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), ev, false, it);
- if (!trace_startsolid)
- {
- //dprint("ev deviation", vtos(trace_endpos - ev), "\n");
- ev = trace_endpos + '0 0 1';
- }
- }
- //traceline(this.origin, it.origin, false, NULL);
- //if (trace_fraction == 1)
- if (!this.wpisbox && tracewalk(this, sv, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), ev, MOVE_NOMONSTERS))
- waypoint_addlink(this, it);
- else
- relink_walkculled += 0.5;
- if (!it.wpisbox && tracewalk(it, ev, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), sv, MOVE_NOMONSTERS))
- waypoint_addlink(it, this);
- else
- relink_walkculled += 0.5;
- }
- });
- navigation_testtracewalk = 0;
- this.wplinked = true;
-}
-
-void waypoint_clearlinks(entity wp)
-{
- // clear links to other waypoints
- float f;
- f = 10000000;
- wp.wp00 = wp.wp01 = wp.wp02 = wp.wp03 = wp.wp04 = wp.wp05 = wp.wp06 = wp.wp07 = NULL;
- wp.wp08 = wp.wp09 = wp.wp10 = wp.wp11 = wp.wp12 = wp.wp13 = wp.wp14 = wp.wp15 = NULL;
- wp.wp16 = wp.wp17 = wp.wp18 = wp.wp19 = wp.wp20 = wp.wp21 = wp.wp22 = wp.wp23 = NULL;
- wp.wp24 = wp.wp25 = wp.wp26 = wp.wp27 = wp.wp28 = wp.wp29 = wp.wp30 = wp.wp31 = NULL;
-
- wp.wp00mincost = wp.wp01mincost = wp.wp02mincost = wp.wp03mincost = wp.wp04mincost = wp.wp05mincost = wp.wp06mincost = wp.wp07mincost = f;
- wp.wp08mincost = wp.wp09mincost = wp.wp10mincost = wp.wp11mincost = wp.wp12mincost = wp.wp13mincost = wp.wp14mincost = wp.wp15mincost = f;
- wp.wp16mincost = wp.wp17mincost = wp.wp18mincost = wp.wp19mincost = wp.wp20mincost = wp.wp21mincost = wp.wp22mincost = wp.wp23mincost = f;
- wp.wp24mincost = wp.wp25mincost = wp.wp26mincost = wp.wp27mincost = wp.wp28mincost = wp.wp29mincost = wp.wp30mincost = wp.wp31mincost = f;
-
- wp.wplinked = false;
-}
-
-// tell a spawnfunc_waypoint to relink
-void waypoint_schedulerelink(entity wp)
-{
- if (wp == NULL)
- return;
- // TODO: add some sort of visible box in edit mode for box waypoints
- if (autocvar_g_waypointeditor)
- {
- vector m1, m2;
- m1 = wp.mins;
- m2 = wp.maxs;
- setmodel(wp, MDL_WAYPOINT); wp.effects = EF_LOWPRECISION;
- setsize(wp, m1, m2);
- if (wp.wpflags & WAYPOINTFLAG_ITEM)
- wp.colormod = '1 0 0';
- else if (wp.wpflags & WAYPOINTFLAG_GENERATED)
- wp.colormod = '1 1 0';
- else
- wp.colormod = '1 1 1';
- }
- else
- wp.model = "";
- wp.wpisbox = vlen(wp.size) > 0;
- wp.enemy = NULL;
- if (!(wp.wpflags & WAYPOINTFLAG_PERSONAL))
- wp.owner = NULL;
- if (!(wp.wpflags & WAYPOINTFLAG_NORELINK))
- waypoint_clearlinks(wp);
- // schedule an actual relink on next frame
- setthink(wp, waypoint_think);
- wp.nextthink = time;
- wp.effects = EF_LOWPRECISION;
-}
-
-// spawnfunc_waypoint map entity
-spawnfunc(waypoint)
-{
- IL_PUSH(g_waypoints, this);
-
- setorigin(this, this.origin);
- // schedule a relink after other waypoints have had a chance to spawn
- waypoint_clearlinks(this);
- //waypoint_schedulerelink(this);
-}
-
-// remove a spawnfunc_waypoint, and schedule all neighbors to relink
-void waypoint_remove(entity e)
-{
- // tell all linked waypoints that they need to relink
- waypoint_schedulerelink(e.wp00);
- waypoint_schedulerelink(e.wp01);
- waypoint_schedulerelink(e.wp02);
- waypoint_schedulerelink(e.wp03);
- waypoint_schedulerelink(e.wp04);
- waypoint_schedulerelink(e.wp05);
- waypoint_schedulerelink(e.wp06);
- waypoint_schedulerelink(e.wp07);
- waypoint_schedulerelink(e.wp08);
- waypoint_schedulerelink(e.wp09);
- waypoint_schedulerelink(e.wp10);
- waypoint_schedulerelink(e.wp11);
- waypoint_schedulerelink(e.wp12);
- waypoint_schedulerelink(e.wp13);
- waypoint_schedulerelink(e.wp14);
- waypoint_schedulerelink(e.wp15);
- waypoint_schedulerelink(e.wp16);
- waypoint_schedulerelink(e.wp17);
- waypoint_schedulerelink(e.wp18);
- waypoint_schedulerelink(e.wp19);
- waypoint_schedulerelink(e.wp20);
- waypoint_schedulerelink(e.wp21);
- waypoint_schedulerelink(e.wp22);
- waypoint_schedulerelink(e.wp23);
- waypoint_schedulerelink(e.wp24);
- waypoint_schedulerelink(e.wp25);
- waypoint_schedulerelink(e.wp26);
- waypoint_schedulerelink(e.wp27);
- waypoint_schedulerelink(e.wp28);
- waypoint_schedulerelink(e.wp29);
- waypoint_schedulerelink(e.wp30);
- waypoint_schedulerelink(e.wp31);
- // and now remove the spawnfunc_waypoint
- remove(e);
-}
-
-// empties the map of waypoints
-void waypoint_removeall()
-{
- IL_EACH(g_waypoints, true,
- {
- remove(it);
- });
-}
-
-// tell all waypoints to relink
-// (is this useful at all?)
-void waypoint_schedulerelinkall()
-{
- relink_total = relink_walkculled = relink_pvsculled = relink_lengthculled = 0;
- IL_EACH(g_waypoints, true,
- {
- waypoint_schedulerelink(it);
- });
-}
-
-// Load waypoint links from file
-float waypoint_load_links()
-{
- string filename, s;
- float file, tokens, c = 0, found;
- entity wp_from = NULL, wp_to;
- vector wp_to_pos, wp_from_pos;
- filename = strcat("maps/", mapname);
- filename = strcat(filename, ".waypoints.cache");
- file = fopen(filename, FILE_READ);
-
- if (file < 0)
- {
- LOG_TRACE("waypoint links load from ");
- LOG_TRACE(filename);
- LOG_TRACE(" failed\n");
- return false;
- }
-
- while ((s = fgets(file)))
- {
- tokens = tokenizebyseparator(s, "*");
-
- if (tokens!=2)
- {
- // bad file format
- fclose(file);
- return false;
- }
-
- wp_from_pos = stov(argv(0));
- wp_to_pos = stov(argv(1));
-
- // Search "from" waypoint
- if(!wp_from || wp_from.origin!=wp_from_pos)
- {
- wp_from = findradius(wp_from_pos, 1);
- found = false;
- while(wp_from)
- {
- if(vdist(wp_from.origin - wp_from_pos, <, 1))
- if(wp_from.classname == "waypoint")
- {
- found = true;
- break;
- }
- wp_from = wp_from.chain;
- }
-
- if(!found)
- {
- LOG_TRACE("waypoint_load_links: couldn't find 'from' waypoint at ", vtos(wp_from.origin),"\n");
- continue;
- }
-
- }
-
- // Search "to" waypoint
- wp_to = findradius(wp_to_pos, 1);
- found = false;
- while(wp_to)
- {
- if(vdist(wp_to.origin - wp_to_pos, <, 1))
- if(wp_to.classname == "waypoint")
- {
- found = true;
- break;
- }
- wp_to = wp_to.chain;
- }
-
- if(!found)
- {
- LOG_TRACE("waypoint_load_links: couldn't find 'to' waypoint at ", vtos(wp_to.origin),"\n");
- continue;
- }
-
- ++c;
- waypoint_addlink(wp_from, wp_to);
- }
-
- fclose(file);
-
- LOG_TRACE("loaded ", ftos(c), " waypoint links from maps/", mapname, ".waypoints.cache\n");
-
- botframe_cachedwaypointlinks = true;
- return true;
-}
-
-void waypoint_load_links_hardwired()
-{
- string filename, s;
- float file, tokens, c = 0, found;
- entity wp_from = NULL, wp_to;
- vector wp_to_pos, wp_from_pos;
- filename = strcat("maps/", mapname);
- filename = strcat(filename, ".waypoints.hardwired");
- file = fopen(filename, FILE_READ);
-
- botframe_loadedforcedlinks = true;
-
- if (file < 0)
- {
- LOG_TRACE("waypoint links load from ", filename, " failed\n");
- return;
- }
-
- while ((s = fgets(file)))
- {
- if(substring(s, 0, 2)=="//")
- continue;
-
- if(substring(s, 0, 1)=="#")
- continue;
-
- tokens = tokenizebyseparator(s, "*");
-
- if (tokens!=2)
- continue;
-
- wp_from_pos = stov(argv(0));
- wp_to_pos = stov(argv(1));
-
- // Search "from" waypoint
- if(!wp_from || wp_from.origin!=wp_from_pos)
- {
- wp_from = findradius(wp_from_pos, 5);
- found = false;
- while(wp_from)
- {
- if(vdist(wp_from.origin - wp_from_pos, <, 5))
- if(wp_from.classname == "waypoint")
- {
- found = true;
- break;
- }
- wp_from = wp_from.chain;
- }
-
- if(!found)
- {
- LOG_INFO(strcat("NOTICE: Can not find waypoint at ", vtos(wp_from_pos), ". Path skipped\n"));
- continue;
- }
- }
-
- // Search "to" waypoint
- wp_to = findradius(wp_to_pos, 5);
- found = false;
- while(wp_to)
- {
- if(vdist(wp_to.origin - wp_to_pos, <, 5))
- if(wp_to.classname == "waypoint")
- {
- found = true;
- break;
- }
- wp_to = wp_to.chain;
- }
-
- if(!found)
- {
- LOG_INFO(strcat("NOTICE: Can not find waypoint at ", vtos(wp_to_pos), ". Path skipped\n"));
- continue;
- }
-
- ++c;
- waypoint_addlink(wp_from, wp_to);
- wp_from.wphardwired = true;
- wp_to.wphardwired = true;
- }
-
- fclose(file);
-
- LOG_TRACE("loaded ", ftos(c), " waypoint links from maps/", mapname, ".waypoints.hardwired\n");
-}
-
-entity waypoint_get_link(entity w, float i)
-{
- switch(i)
- {
- case 0:return w.wp00;
- case 1:return w.wp01;
- case 2:return w.wp02;
- case 3:return w.wp03;
- case 4:return w.wp04;
- case 5:return w.wp05;
- case 6:return w.wp06;
- case 7:return w.wp07;
- case 8:return w.wp08;
- case 9:return w.wp09;
- case 10:return w.wp10;
- case 11:return w.wp11;
- case 12:return w.wp12;
- case 13:return w.wp13;
- case 14:return w.wp14;
- case 15:return w.wp15;
- case 16:return w.wp16;
- case 17:return w.wp17;
- case 18:return w.wp18;
- case 19:return w.wp19;
- case 20:return w.wp20;
- case 21:return w.wp21;
- case 22:return w.wp22;
- case 23:return w.wp23;
- case 24:return w.wp24;
- case 25:return w.wp25;
- case 26:return w.wp26;
- case 27:return w.wp27;
- case 28:return w.wp28;
- case 29:return w.wp29;
- case 30:return w.wp30;
- case 31:return w.wp31;
- default:return NULL;
- }
-}
-
-// Save all waypoint links to a file
-void waypoint_save_links()
-{
- string filename = sprintf("maps/%s.waypoints.cache", mapname);
- int file = fopen(filename, FILE_WRITE);
- if (file < 0)
- {
- LOG_INFOF("waypoint link save to %s failed\n", filename);
- return;
- }
-
- int c = 0;
- IL_EACH(g_waypoints, true,
- {
- for(int j = 0; j < 32; ++j)
- {
- entity link = waypoint_get_link(it, j);
- if(link)
- {
- string s = strcat(vtos(it.origin), "*", vtos(link.origin), "\n");
- fputs(file, s);
- ++c;
- }
- }
- });
- fclose(file);
- botframe_cachedwaypointlinks = true;
-
- LOG_INFOF("saved %d waypoint links to maps/%s.waypoints.cache\n", c, mapname);
-}
-
-// save waypoints to gamedir/data/maps/mapname.waypoints
-void waypoint_saveall()
-{
- string filename = sprintf("maps/%s.waypoints", mapname);
- int file = fopen(filename, FILE_WRITE);
- if (file < 0)
- {
- waypoint_save_links(); // save anyway?
- botframe_loadedforcedlinks = false;
-
- LOG_INFOF("waypoint links: save to %s failed\n", filename);
- return;
- }
-
- int c = 0;
- IL_EACH(g_waypoints, true,
- {
- if(it.wpflags & WAYPOINTFLAG_GENERATED)
- continue;
-
- for(int j = 0; j < 32; ++j)
- {
- string s;
- s = strcat(vtos(it.origin + it.mins), "\n");
- s = strcat(s, vtos(it.origin + it.maxs));
- s = strcat(s, "\n");
- s = strcat(s, ftos(it.wpflags));
- s = strcat(s, "\n");
- fputs(file, s);
- ++c;
- }
- });
- fclose(file);
- waypoint_save_links();
- botframe_loadedforcedlinks = false;
-
- LOG_INFOF("saved %d waypoints to maps/%s.waypoints\n", c, mapname);
-}
-
-// load waypoints from file
-float waypoint_loadall()
-{
- string filename, s;
- float file, cwp, cwb, fl;
- vector m1, m2;
- cwp = 0;
- cwb = 0;
- filename = strcat("maps/", mapname);
- filename = strcat(filename, ".waypoints");
- file = fopen(filename, FILE_READ);
- if (file >= 0)
- {
- while ((s = fgets(file)))
- {
- m1 = stov(s);
- s = fgets(file);
- if (!s)
- break;
- m2 = stov(s);
- s = fgets(file);
- if (!s)
- break;
- fl = stof(s);
- waypoint_spawn(m1, m2, fl);
- if (m1 == m2)
- cwp = cwp + 1;
- else
- cwb = cwb + 1;
- }
- fclose(file);
- LOG_TRACE("loaded ", ftos(cwp), " waypoints and ", ftos(cwb), " wayboxes from maps/", mapname, ".waypoints\n");
- }
- else
- {
- LOG_TRACE("waypoint load from ", filename, " failed\n");
- }
- return cwp + cwb;
-}
-
-vector waypoint_fixorigin(vector position)
-{
- tracebox(position + '0 0 1' * (1 - STAT(PL_MIN, NULL).z), STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), position + '0 0 -512', MOVE_NOMONSTERS, NULL);
- if(trace_fraction < 1)
- position = trace_endpos;
- //traceline(position, position + '0 0 -512', MOVE_NOMONSTERS, NULL);
- //print("position is ", ftos(trace_endpos_z - position_z), " above solid\n");
- return position;
-}
-
-void waypoint_spawnforitem_force(entity e, vector org)
-{
- // Fix the waypoint altitude if necessary
- org = waypoint_fixorigin(org);
-
- // don't spawn an item spawnfunc_waypoint if it already exists
- IL_EACH(g_waypoints, true,
- {
- if(it.wpisbox)
- {
- if(boxesoverlap(org, org, it.absmin, it.absmax))
- {
- e.nearestwaypoint = it;
- return;
- }
- }
- else
- {
- if(vdist(it.origin - org, <, 16))
- {
- e.nearestwaypoint = it;
- return;
- }
- }
- });
-
- e.nearestwaypoint = waypoint_spawn(org, org, WAYPOINTFLAG_GENERATED | WAYPOINTFLAG_ITEM);
-}
-
-void waypoint_spawnforitem(entity e)
-{
- if(!bot_waypoints_for_items)
- return;
-
- waypoint_spawnforitem_force(e, e.origin);
-}
-
-void waypoint_spawnforteleporter_boxes(entity e, vector org1, vector org2, vector destination1, vector destination2, float timetaken)
-{
- entity w;
- entity dw;
- w = waypoint_spawn(org1, org2, WAYPOINTFLAG_GENERATED | WAYPOINTFLAG_TELEPORT | WAYPOINTFLAG_NORELINK);
- dw = waypoint_spawn(destination1, destination2, WAYPOINTFLAG_GENERATED);
- // one way link to the destination
- w.wp00 = dw;
- w.wp00mincost = timetaken; // this is just for jump pads
- // the teleporter's nearest spawnfunc_waypoint is this one
- // (teleporters are not goals, so this is probably useless)
- e.nearestwaypoint = w;
- e.nearestwaypointtimeout = time + 1000000000;
-}
-
-void waypoint_spawnforteleporter_v(entity e, vector org, vector destination, float timetaken)
-{
- org = waypoint_fixorigin(org);
- destination = waypoint_fixorigin(destination);
- waypoint_spawnforteleporter_boxes(e, org, org, destination, destination, timetaken);
-}
-
-void waypoint_spawnforteleporter(entity e, vector destination, float timetaken)
-{
- destination = waypoint_fixorigin(destination);
- waypoint_spawnforteleporter_boxes(e, e.absmin, e.absmax, destination, destination, timetaken);
-}
-
-entity waypoint_spawnpersonal(entity this, vector position)
-{
- entity w;
-
- // drop the waypoint to a proper location:
- // first move it up by a player height
- // then move it down to hit the floor with player bbox size
- position = waypoint_fixorigin(position);
-
- w = waypoint_spawn(position, position, WAYPOINTFLAG_GENERATED | WAYPOINTFLAG_PERSONAL);
- w.nearestwaypoint = NULL;
- w.nearestwaypointtimeout = 0;
- w.owner = this;
-
- waypoint_schedulerelink(w);
-
- return w;
-}
-
-void botframe_showwaypointlinks()
-{
- if (time < botframe_waypointeditorlightningtime)
- return;
- botframe_waypointeditorlightningtime = time + 0.5;
- FOREACH_CLIENT(IS_PLAYER(it) && !it.isbot,
- {
- if(IS_ONGROUND(it) || it.waterlevel > WATERLEVEL_NONE)
- {
- //navigation_testtracewalk = true;
- entity head = navigation_findnearestwaypoint(it, false);
- // print("currently selected WP is ", etos(head), "\n");
- //navigation_testtracewalk = false;
- if (head)
- {
- entity w;
- w = head ;if (w) te_lightning2(NULL, w.origin, it.origin);
- w = head.wp00;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp01;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp02;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp03;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp04;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp05;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp06;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp07;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp08;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp09;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp10;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp11;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp12;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp13;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp14;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp15;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp16;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp17;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp18;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp19;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp20;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp21;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp22;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp23;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp24;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp25;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp26;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp27;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp28;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp29;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp30;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp31;if (w) te_lightning2(NULL, w.origin, head.origin);
- }
- }
- });
-}
-
-float botframe_autowaypoints_fixdown(vector v)
-{
- tracebox(v, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), v + '0 0 -64', MOVE_NOMONSTERS, NULL);
- if(trace_fraction >= 1)
- return 0;
- return 1;
-}
-
-float botframe_autowaypoints_createwp(vector v, entity p, .entity fld, float f)
-{
- IL_EACH(g_waypoints, boxesoverlap(v - '32 32 32', v + '32 32 32', it.absmin, it.absmax),
- {
- // if a matching spawnfunc_waypoint already exists, don't add a duplicate
- return 0;
- });
-
- waypoint_schedulerelink(p.(fld) = waypoint_spawn(v, v, f));
- return 1;
-}
-
-// return value:
-// 1 = WP created
-// 0 = no action needed
-// -1 = temp fail, try from world too
-// -2 = permanent fail, do not retry
-float botframe_autowaypoints_fix_from(entity p, float walkfromwp, entity wp, .entity fld)
-{
- // make it possible to go from p to wp, if we can
- // if wp is NULL, nearest is chosen
-
- entity w;
- vector porg;
- float t, tmin, tmax;
- vector o;
- vector save;
-
- if(!botframe_autowaypoints_fixdown(p.origin))
- return -2;
- porg = trace_endpos;
-
- if(wp)
- {
- // if any WP w fulfills wp -> w -> porg and w is closer than wp, then switch from wp to w
-
- // if wp -> porg, then OK
- float maxdist;
- if(navigation_waypoint_will_link(wp.origin, porg, p, walkfromwp, 1050))
- {
- // we may find a better one
- maxdist = vlen(wp.origin - porg);
- }
- else
- {
- // accept any "good"
- maxdist = 2100;
- }
-
- float bestdist = maxdist;
- IL_EACH(g_waypoints, it != wp && !(it.wpflags & WAYPOINTFLAG_NORELINK),
- {
- float d = vlen(wp.origin - it.origin) + vlen(it.origin - porg);
- if(d < bestdist)
- if(navigation_waypoint_will_link(wp.origin, it.origin, p, walkfromwp, 1050))
- if(navigation_waypoint_will_link(it.origin, porg, p, walkfromwp, 1050))
- {
- bestdist = d;
- p.(fld) = it;
- }
- });
- if(bestdist < maxdist)
- {
- LOG_INFO("update chain to new nearest WP ", etos(p.(fld)), "\n");
- return 0;
- }
-
- if(bestdist < 2100)
- {
- // we know maxdist < 2100
- // so wp -> porg is still valid
- // all is good
- p.(fld) = wp;
- return 0;
- }
-
- // otherwise, no existing WP can fix our issues
- }
- else
- {
- save = p.origin;
- setorigin(p, porg);
- w = navigation_findnearestwaypoint(p, walkfromwp);
- setorigin(p, save);
- if(w)
- {
- p.(fld) = w;
- return 0;
- }
- }
-
- tmin = 0;
- tmax = 1;
- for (;;)
- {
- if(tmax - tmin < 0.001)
- {
- // did not get a good candidate
- return -1;
- }
-
- t = (tmin + tmax) * 0.5;
- o = antilag_takebackorigin(p, CS(p), time - t);
- if(!botframe_autowaypoints_fixdown(o))
- return -2;
- o = trace_endpos;
-
- if(wp)
- {
- if(!navigation_waypoint_will_link(wp.origin, o, p, walkfromwp, 1050))
- {
- // we cannot walk from wp.origin to o
- // get closer to tmax
- tmin = t;
- continue;
- }
- }
- else
- {
- save = p.origin;
- setorigin(p, o);
- w = navigation_findnearestwaypoint(p, walkfromwp);
- setorigin(p, save);
- if(!w)
- {
- // we cannot walk from any WP to o
- // get closer to tmax
- tmin = t;
- continue;
- }
- }
-
- // if we get here, o is valid regarding waypoints
- // check if o is connected right to the player
- // we break if it succeeds, as that means o is a good waypoint location
- if(navigation_waypoint_will_link(o, porg, p, walkfromwp, 1050))
- break;
-
- // o is no good, we need to get closer to the player
- tmax = t;
- }
-
- LOG_INFO("spawning a waypoint for connecting to ", etos(wp), "\n");
- botframe_autowaypoints_createwp(o, p, fld, 0);
- return 1;
-}
-
-// automatically create missing waypoints
-.entity botframe_autowaypoints_lastwp0, botframe_autowaypoints_lastwp1;
-void botframe_autowaypoints_fix(entity p, float walkfromwp, .entity fld)
-{
- float r = botframe_autowaypoints_fix_from(p, walkfromwp, p.(fld), fld);
- if(r != -1)
- return;
- r = botframe_autowaypoints_fix_from(p, walkfromwp, NULL, fld);
- if(r != -1)
- return;
-
- LOG_INFO("emergency: got no good nearby WP to build a link from, starting a new chain\n");
- if(!botframe_autowaypoints_fixdown(p.origin))
- return; // shouldn't happen, caught above
- botframe_autowaypoints_createwp(trace_endpos, p, fld, WAYPOINTFLAG_PROTECTED);
-}
-
-void botframe_deleteuselesswaypoints()
-{
- FOREACH_ENTITY_FLOAT(bot_pickup, true,
- {
- // NOTE: this protects waypoints if they're the ONLY nearest
- // waypoint. That's the intention.
- navigation_findnearestwaypoint(it, false); // Walk TO item.
- navigation_findnearestwaypoint(it, true); // Walk FROM item.
- });
- IL_EACH(g_waypoints, true,
- {
- it.wpflags |= WAYPOINTFLAG_DEAD_END;
- it.wpflags &= ~WAYPOINTFLAG_USEFUL;
- // WP is useful if:
- if (it.wpflags & WAYPOINTFLAG_ITEM)
- it.wpflags |= WAYPOINTFLAG_USEFUL;
- if (it.wpflags & WAYPOINTFLAG_TELEPORT)
- it.wpflags |= WAYPOINTFLAG_USEFUL;
- if (it.wpflags & WAYPOINTFLAG_PROTECTED)
- it.wpflags |= WAYPOINTFLAG_USEFUL;
- // b) WP is closest WP for an item/spawnpoint/other entity
- // This has been done above by protecting these WPs.
- });
- // c) There are w1, w, w2 so that w1 -> w, w -> w2 and not w1 -> w2.
- IL_EACH(g_waypoints, !(it.wpflags & WAYPOINTFLAG_PERSONAL),
- {
- for (int m = 0; m < 32; ++m)
- {
- entity w = waypoint_get_link(it, m);
- if (!w)
- break;
- if (w.wpflags & WAYPOINTFLAG_PERSONAL)
- continue;
- if (w.wpflags & WAYPOINTFLAG_USEFUL)
- continue;
- for (int j = 0; j < 32; ++j)
- {
- entity w2 = waypoint_get_link(w, j);
- if (!w2)
- break;
- if (it == w2)
- continue;
- if (w2.wpflags & WAYPOINTFLAG_PERSONAL)
- continue;
- // If we got here, it != w2 exist with it -> w
- // and w -> w2. That means the waypoint is not
- // a dead end.
- w.wpflags &= ~WAYPOINTFLAG_DEAD_END;
- for (int k = 0; k < 32; ++k)
- {
- if (waypoint_get_link(it, k) == w2)
- continue;
- // IF WE GET HERE, w is proven useful
- // to get from it to w2!
- w.wpflags |= WAYPOINTFLAG_USEFUL;
- goto next;
- }
- }
-LABEL(next)
- }
- });
- // d) The waypoint is a dead end. Dead end waypoints must be kept as
- // they are needed to complete routes while autowaypointing.
-
- IL_EACH(g_waypoints, !(it.wpflags & (WAYPOINTFLAG_USEFUL | WAYPOINTFLAG_DEAD_END)),
- {
- LOG_INFOF("Removed a waypoint at %v. Try again for more!\n", it.origin);
- te_explosion(it.origin);
- waypoint_remove(it);
- break;
- });
-
- IL_EACH(g_waypoints, true,
- {
- it.wpflags &= ~(WAYPOINTFLAG_USEFUL | WAYPOINTFLAG_DEAD_END); // temp flag
- });
-}
-
-void botframe_autowaypoints()
-{
- FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && !IS_DEAD(it), LAMBDA(
- // going back is broken, so only fix waypoints to walk TO the player
- //botframe_autowaypoints_fix(p, false, botframe_autowaypoints_lastwp0);
- botframe_autowaypoints_fix(it, true, botframe_autowaypoints_lastwp1);
- //te_explosion(p.botframe_autowaypoints_lastwp0.origin);
- ));
-
- if (autocvar_g_waypointeditor_auto >= 2) {
- botframe_deleteuselesswaypoints();
- }
-}
-
+++ /dev/null
-#pragma once
-/*
- * Globals and Fields
- */
-
-const int WAYPOINTFLAG_GENERATED = BIT(23);
-const int WAYPOINTFLAG_ITEM = BIT(22);
-const int WAYPOINTFLAG_TELEPORT = BIT(21);
-const int WAYPOINTFLAG_NORELINK = BIT(20);
-const int WAYPOINTFLAG_PERSONAL = BIT(19);
-const int WAYPOINTFLAG_PROTECTED = BIT(18); // Useless WP detection never kills these.
-const int WAYPOINTFLAG_USEFUL = BIT(17); // Useless WP detection temporary flag.
-const int WAYPOINTFLAG_DEAD_END = BIT(16); // Useless WP detection temporary flag.
-
-// fields you can query using prvm_global server to get some statistics about waypoint linking culling
-float relink_total, relink_walkculled, relink_pvsculled, relink_lengthculled;
-
-float botframe_waypointeditorlightningtime;
-float botframe_loadedforcedlinks;
-float botframe_cachedwaypointlinks;
-
-.entity wp00, wp01, wp02, wp03, wp04, wp05, wp06, wp07, wp08, wp09, wp10, wp11, wp12, wp13, wp14, wp15;
-.entity wp16, wp17, wp18, wp19, wp20, wp21, wp22, wp23, wp24, wp25, wp26, wp27, wp28, wp29, wp30, wp31;
-
-// itemscore = (howmuchmoreIwant / howmuchIcanwant) / itemdistance
-.float wp00mincost, wp01mincost, wp02mincost, wp03mincost, wp04mincost, wp05mincost, wp06mincost, wp07mincost;
-.float wp08mincost, wp09mincost, wp10mincost, wp11mincost, wp12mincost, wp13mincost, wp14mincost, wp15mincost;
-.float wp16mincost, wp17mincost, wp18mincost, wp19mincost, wp20mincost, wp21mincost, wp22mincost, wp23mincost;
-.float wp24mincost, wp25mincost, wp26mincost, wp27mincost, wp28mincost, wp29mincost, wp30mincost, wp31mincost;
-
-.float wpfire, wpcost, wpconsidered, wpisbox, wplinked, wphardwired;
-.int wpflags;
-
-.vector wpnearestpoint;
-
-/*
- * Functions
- */
-
-spawnfunc(waypoint);
-void waypoint_addlink(entity from, entity to);
-void waypoint_think(entity this);
-void waypoint_clearlinks(entity wp);
-void waypoint_schedulerelink(entity wp);
-
-void waypoint_remove(entity e);
-void waypoint_removeall();
-void waypoint_schedulerelinkall();
-void waypoint_load_links_hardwired();
-void waypoint_save_links();
-void waypoint_saveall();
-
-void waypoint_spawnforitem_force(entity e, vector org);
-void waypoint_spawnforitem(entity e);
-void waypoint_spawnforteleporter(entity e, vector destination, float timetaken);
-void waypoint_spawnforteleporter_v(entity e, vector org, vector destination, float timetaken);
-void botframe_showwaypointlinks();
-
-float waypoint_loadall();
-float waypoint_load_links();
-
-entity waypoint_spawn(vector m1, vector m2, float f);
-entity waypoint_spawnpersonal(entity this, vector position);
-
-vector waypoint_fixorigin(vector position);
-
-void botframe_autowaypoints();
if(campaign_won && campaign_entries < 2)
{
// last map won!
- LOG_DEBUG("^2test run: campaign looks GOOD\n");
+ LOG_DEBUG("^2test run: campaign looks GOOD");
localcmd("togglemenu 1\n");
CampaignFile_Unload();
return;
sprint(this, "Emergency teleport used info_autoscreenshot location\n");
setorigin(this, e.origin);
this.angles = e.angles;
- remove(e);
+ delete(e);
// should we? this.angles_x = -this.angles_x;
this.fixangle = true;
this.velocity = '0 0 0';
e2 = spawn();
setorigin(e2, e.origin);
RadiusDamage(e2, this, 1000, 0, 128, NULL, NULL, 500, DEATH_CHEAT.m_id, e);
- remove(e2);
+ delete(e2);
LOG_INFO("404 Sportsmanship not found.\n");
DID_CHEAT();
// arguments:
// effectname
effectnum = _particleeffectnum(argv(1));
- W_SetupShot(this, false, false, SND_Null, CH_WEAPON_A, 0);
+ W_SetupShot(this, weaponentities[0], false, false, SND_Null, CH_WEAPON_A, 0);
traceline(w_shotorg, w_shotorg + w_shotdir * MAX_SHOT_DISTANCE, MOVE_NORMAL, this);
__trailparticles(this, effectnum, w_shotorg, trace_endpos);
DID_CHEAT();
// arguments:
// modelname mode
f = stof(argv(2));
- W_SetupShot(this, false, false, SND_Null, CH_WEAPON_A, 0);
+ W_SetupShot(this, weaponentities[0], false, false, SND_Null, CH_WEAPON_A, 0);
traceline(w_shotorg, w_shotorg + w_shotdir * 2048, MOVE_NORMAL, this);
if((trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT) || trace_fraction == 1)
{
tracebox(e.origin, e.mins, e.maxs, e.origin, MOVE_NORMAL, e);
if(trace_startsolid)
{
- remove(e);
+ delete(e);
sprint(this, "cannot make stuff there (no space)\n");
}
else
RandomSelection_Add(e, 0, string_null, 1, 1 / vlen(e.origin + (e.mins + e.maxs) * 0.5 - trace_endpos));
if(RandomSelection_chosen_ent)
{
- remove(RandomSelection_chosen_ent.killindicator.killindicator);
- remove(RandomSelection_chosen_ent.killindicator);
+ delete(RandomSelection_chosen_ent.killindicator.killindicator);
+ delete(RandomSelection_chosen_ent.killindicator);
if(RandomSelection_chosen_ent.aiment)
- remove(RandomSelection_chosen_ent.aiment);
+ delete(RandomSelection_chosen_ent.aiment);
if(RandomSelection_chosen_ent.enemy)
- remove(RandomSelection_chosen_ent.enemy);
- remove(RandomSelection_chosen_ent);
+ delete(RandomSelection_chosen_ent.enemy);
+ delete(RandomSelection_chosen_ent);
}
DID_CHEAT();
break;
case "drag_clear":
IS_CHEAT(this, 0, argc, 0);
for(entity e = NULL; (e = find(e, classname, "dragbox_box")); )
- remove(e);
+ delete(e);
for(entity e = NULL; (e = find(e, classname, "dragbox_corner_1")); )
- remove(e);
+ delete(e);
for(entity e = NULL; (e = find(e, classname, "dragbox_corner_2")); )
- remove(e);
+ delete(e);
for(entity e = NULL; (e = find(e, classname, "dragpoint")); )
- remove(e);
+ delete(e);
for(entity e = NULL; (e = find(e, classname, "drag_digit")); )
- remove(e);
+ delete(e);
DID_CHEAT();
break;
case "god":
entity e = spawn();
e.target = argv(1);
SUB_UseTargets(e, this, NULL);
- remove(e);
+ delete(e);
DID_CHEAT();
break;
case "killtarget":
entity e2 = spawn();
e2.killtarget = argv(1);
SUB_UseTargets(e2, this, NULL);
- remove(e2);
+ delete(e2);
DID_CHEAT();
break;
case "teleporttotarget":
if(!wasfreed(ent))
{
Simple_TeleportPlayer(ent, this);
- remove(ent);
+ delete(ent);
DID_CHEAT();
}
break;
#include "campaign.qh"
#include "command/common.qh"
-#include "bot/bot.qh"
-#include "bot/navigation.qh"
+#include "bot/api.qh"
#include "../common/ent_cs.qh"
#include <common/state.qh>
WriteHeader(MSG_BROADCAST, TE_CSQC_TEAMNAGGER);
}
+int CountSpectators(entity player, entity to)
+{
+ if(!player) { return 0; } // not sure how, but best to be safe
+
+ int spec_count = 0;
+
+ FOREACH_CLIENT(IS_REAL_CLIENT(it) && IS_SPEC(it) && it != to && it.enemy == player,
+ {
+ spec_count++;
+ });
+
+ return spec_count;
+}
+
+void WriteSpectators(entity player, entity to)
+{
+ if(!player) { return; } // not sure how, but best to be safe
+
+ FOREACH_CLIENT(IS_REAL_CLIENT(it) && IS_SPEC(it) && it != to && it.enemy == player,
+ {
+ WriteByte(MSG_ENTITY, num_for_edict(it));
+ });
+}
+
bool ClientData_Send(entity this, entity to, int sf)
{
assert(to == this.owner, return false);
if (to.spectatee_status) sf |= 2; // spectator ent number follows
if (e.zoomstate) sf |= 4; // zoomed
if (e.porto_v_angle_held) sf |= 8; // angles held
+ if (autocvar_sv_showspectators) sf |= 16; // show spectators
WriteHeader(MSG_ENTITY, ENT_CLIENT_CLIENTDATA);
WriteByte(MSG_ENTITY, sf);
WriteAngle(MSG_ENTITY, e.v_angle.x);
WriteAngle(MSG_ENTITY, e.v_angle.y);
}
+
+ if(sf & 16)
+ {
+ float specs = CountSpectators(e, to);
+ WriteByte(MSG_ENTITY, specs);
+ WriteSpectators(e, to);
+ }
+
return true;
}
void ClientData_Detach(entity this)
{
- remove(this.clientdata);
+ delete(this.clientdata);
this.clientdata = NULL;
}
// needed for player sounds
this.model = "";
FixPlayermodel(this);
- }
+ }
setmodel(this, MDL_Null);
setsize(this, STAT(PL_CROUCH_MIN, NULL), STAT(PL_CROUCH_MAX, NULL));
this.view_ofs = '0 0 0';
RemoveGrapplingHook(this);
Portal_ClearAll(this);
Unfreeze(this);
+ SetSpectatee(this, NULL);
if (this.alivetime)
{
this.oldvelocity = this.velocity;
this.fire_endtime = -1;
this.event_damage = func_null;
+
+ STAT(ACTIVEWEAPON, this) = WEP_Null.m_id;
+ STAT(SWITCHINGWEAPON, this) = WEP_Null.m_id;
+ STAT(SWITCHWEAPON, this) = WEP_Null.m_id;
}
int player_getspecies(entity this)
PutObserverInServer(this);
} else if (IS_PLAYER(this)) {
if (this.vehicle) vehicles_exit(this.vehicle, VHEF_RELEASE);
-
+
PlayerState_attach(this);
accuracy_resend(this);
if (autocvar_spawn_debug)
{
sprint(this, strcat("spawnpoint origin: ", vtos(spot.origin), "\n"));
- remove(spot); // usefull for checking if there are spawnpoints, that let drop through the floor
+ delete(spot); // usefull for checking if there are spawnpoints, that let drop through the floor
}
PS(this).m_switchweapon = w_getbestweapon(this);
}
if(this.killindicator && !wasfreed(this.killindicator))
- remove(this.killindicator);
+ delete(this.killindicator);
this.killindicator = NULL;
if (gameover)
{
this.owner.killindicator = NULL;
- remove(this);
+ delete(this);
return;
}
if (this.owner.alpha < 0 && !this.owner.vehicle)
{
this.owner.killindicator = NULL;
- remove(this);
+ delete(this);
return;
}
Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_DISCONNECT, this.netname);
+ SetSpectatee(this, NULL);
+
MUTATOR_CALLHOOK(ClientDisconnect, this);
ClientState_detach(this);
this.flags &= ~FL_CLIENT;
- if (this.chatbubbleentity) remove(this.chatbubbleentity);
- if (this.killindicator) remove(this.killindicator);
+ if (this.chatbubbleentity) delete(this.chatbubbleentity);
+ if (this.killindicator) delete(this.killindicator);
WaypointSprite_PlayerGone(this);
if (this.netname_previous) strunzone(this.netname_previous);
if (this.clientstatus) strunzone(this.clientstatus);
if (this.weaponorder_byimpulse) strunzone(this.weaponorder_byimpulse);
- if (this.personal) remove(this.personal);
+ if (this.personal) delete(this.personal);
this.playerid = 0;
ReadyCount();
{
if(this.owner) // but why can that ever be NULL?
this.owner.chatbubbleentity = NULL;
- remove(this);
+ delete(this);
return;
}
if(!IS_PLAYER(this.enemy))
return false;
+ ClientData_Touch(this.enemy);
+
msg_entity = this;
WriteByte(MSG_ONE, SVC_SETVIEW);
WriteEntity(MSG_ONE, this.enemy);
// WEAPONTODO
// these are required to fix the spectator bug with arc
- if(old_spectatee && old_spectatee.arc_beam) { old_spectatee.arc_beam.SendFlags |= ARC_SF_SETTINGS; }
- if(this.enemy && this.enemy.arc_beam) { this.enemy.arc_beam.SendFlags |= ARC_SF_SETTINGS; }
+ if(old_spectatee)
+ {
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ if(old_spectatee.(weaponentity).arc_beam)
+ old_spectatee.(weaponentity).arc_beam.SendFlags |= ARC_SF_SETTINGS;
+ }
+ }
+ if(this.enemy)
+ {
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ if(this.enemy.(weaponentity).arc_beam)
+ this.enemy.(weaponentity).arc_beam.SendFlags |= ARC_SF_SETTINGS;
+ }
+ }
+
+ // needed to update spectator list
+ if(old_spectatee) { ClientData_Touch(old_spectatee); }
}
bool Spectate(entity this, entity pl)
{
TRANSMUTE(Player, this);
+ SetSpectatee(this, NULL);
+
if(autocvar_g_campaign || autocvar_g_balance_teams)
{ JoinBestTeam(this, false, true); }
this.prevorigin = this.origin;
bool do_crouch = PHYS_INPUT_BUTTON_CROUCH(this);
- .entity weaponentity = weaponentities[0]; // TODO: unhardcode
if (this.hook.state) {
do_crouch = false;
} else if (this.waterlevel >= WATERLEVEL_SWIMMING) {
do_crouch = false;
} else if (STAT(FROZEN, this)) {
do_crouch = false;
- } else if ((PS(this).m_weapon.spawnflags & WEP_TYPE_MELEE_PRI) && this.(weaponentity).wframe == WFRAME_FIRE1 && time < this.(weaponentity).weapon_nextthink) {
- do_crouch = false;
- } else if ((PS(this).m_weapon.spawnflags & WEP_TYPE_MELEE_SEC) && this.(weaponentity).wframe == WFRAME_FIRE2 && time < this.(weaponentity).weapon_nextthink) {
- do_crouch = false;
}
if (do_crouch) {
{
this.items &= ~this.items_added;
- W_WeaponFrame(this);
+ //for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ //{
+ //.entity weaponentity = weaponentities[slot];
+ //W_WeaponFrame(this, weaponentity);
+ //}
+ .entity weaponentity = weaponentities[0]; // TODO
+ W_WeaponFrame(this, weaponentity);
this.items_added = 0;
if (this.items & ITEM_Jetpack.m_itemid && (this.items & ITEM_JetpackRegen.m_itemid || this.ammo_fuel >= 0.01))
void Player_Physics(entity this)
{
- this.movetype = ((this.move_qcphysics) ? MOVETYPE_NONE : this.move_movetype);
+ set_movetype(this, ((this.move_qcphysics) ? MOVETYPE_NONE : this.move_movetype));
if(!this.move_qcphysics)
return;
if(mt == MOVETYPE_PUSH || mt == MOVETYPE_FAKEPUSH || mt == MOVETYPE_PHYSICS)
{
this.move_qcphysics = false;
- this.movetype = mt;
+ set_movetype(this, mt);
return;
}
CLASS(Client, Object)
/** Client name */
- ATTRIB(Client, netname, string, this.netname)
- ATTRIB(Client, colormap, int, this.colormap)
- ATTRIB(Client, team, int, this.team)
- ATTRIB(Client, clientcolors, int, this.clientcolors)
+ ATTRIB(Client, netname, string, this.netname);
+ ATTRIB(Client, colormap, int, this.colormap);
+ ATTRIB(Client, team, int, this.team);
+ ATTRIB(Client, clientcolors, int, this.clientcolors);
/** Client IP */
- ATTRIB(Client, netaddress, string, this.netaddress)
- ATTRIB(Client, playermodel, string, this.playermodel)
- ATTRIB(Client, playerskin, int, this.playerskin)
+ ATTRIB(Client, netaddress, string, this.netaddress);
+ ATTRIB(Client, playermodel, string, this.playermodel);
+ ATTRIB(Client, playerskin, int, this.playerskin);
/** fingerprint of CA key the player used to authenticate */
- ATTRIB(Client, crypto_keyfp, string, this.crypto_keyfp)
+ ATTRIB(Client, crypto_keyfp, string, this.crypto_keyfp);
/** fingerprint of CA key the server used to authenticate to the player */
- ATTRIB(Client, crypto_mykeyfp, string, this.crypto_mykeyfp)
+ ATTRIB(Client, crypto_mykeyfp, string, this.crypto_mykeyfp);
/** fingerprint of ID used by the player entity, or string_null if not identified */
- ATTRIB(Client, crypto_idfp, string, this.crypto_idfp)
+ ATTRIB(Client, crypto_idfp, string, this.crypto_idfp);
/** set if the player's ID has been signed */
- ATTRIB(Client, crypto_idfp_signed, bool, this.crypto_idfp_signed)
+ ATTRIB(Client, crypto_idfp_signed, bool, this.crypto_idfp_signed);
/** the string "AES128" if encrypting, and string_null if plaintext */
- ATTRIB(Client, crypto_encryptmethod, string, this.crypto_encryptmethod)
+ ATTRIB(Client, crypto_encryptmethod, string, this.crypto_encryptmethod);
/** the string "HMAC-SHA256" if signing, and string_null if plaintext */
- ATTRIB(Client, crypto_signmethod, string, this.crypto_signmethod)
+ ATTRIB(Client, crypto_signmethod, string, this.crypto_signmethod);
// custom
- ATTRIB(Client, playerid, int, this.playerid)
+ ATTRIB(Client, playerid, int, this.playerid);
METHOD(Client, m_unwind, bool(Client this));
#include "cl_impulse.qh"
#include "round_handler.qh"
-#include "bot/waypoints.qh"
+#include "bot/api.qh"
#include "weapons/throwing.qh"
#include "command/common.qh"
#include "cheats.qh"
-#include "bot/navigation.qh"
#include "weapons/selection.qh"
#include "weapons/tracing.qh"
#include "weapons/weaponsystem.qh"
{
if (this.vehicle) return;
if (IS_DEAD(this)) return;
- W_ThrowWeapon(this, W_CalculateProjectileVelocity(this, this.velocity, v_forward * 750, false), '0 0 0', true);
+ W_ThrowWeapon(this, weaponentities[0], W_CalculateProjectileVelocity(this, this.velocity, v_forward * 750, false), '0 0 0', true);
}
IMPULSE(weapon_reload)
if (forbidWeaponUse(this)) return;
Weapon w = PS(this).m_weapon;
entity actor = this;
- .entity weaponentity = weaponentities[0]; // TODO: unhardcode
- w.wr_reload(w, actor, weaponentity);
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ w.wr_reload(w, actor, weaponentity);
+ }
}
void ImpulseCommands(entity this)
WaypointSprite_ClearPersonal(this);
if (this.personal)
{
- remove(this.personal);
+ delete(this.personal);
this.personal = NULL;
}
sprint(this, "personal waypoint cleared\n");
WaypointSprite_ClearOwned(this);
if (this.personal)
{
- remove(this.personal);
+ delete(this.personal);
this.personal = NULL;
}
sprint(this, "all waypoints cleared\n");
#include "cl_player.qh"
-#include "bot/bot.qh"
+#include "bot/api.qh"
#include "cheats.qh"
#include "g_damage.qh"
#include "g_subs.qh"
// get rid of kill indicator
if(this.killindicator)
{
- remove(this.killindicator);
+ delete(this.killindicator);
this.killindicator = NULL;
if(this.killindicator_teamchange)
defer_ClientKill_Now_TeamChange = true;
excess = M_ARGV(4, float);
Weapon wep = PS(this).m_weapon;
- wep.wr_playerdeath(wep, this);
+ /*for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ wep.wr_playerdeath(wep, this, weaponentity);
+ }*/
+ .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+ wep.wr_playerdeath(wep, this, weaponentity);
RemoveGrapplingHook(this);
timeout_time = 0;
timeout_leadtime = 0;
- remove(this);
+ delete(this);
}
void timeout_handler_think(entity this)
c = trace_endpos;
}
- if (n > 200) LOG_TRACE("HOLY SHIT! FullTraceFraction: ", ftos(n), " total traces, ", ftos(m), " iterations\n");
+ if (n > 200) LOG_TRACE("HOLY SHIT! FullTraceFraction: ", ftos(n), " total traces, ", ftos(m), " iterations");
return white / (black + white);
}
localcmd(strcat("defer 1 \"sv_cmd radarmap --flags ", ftos(radarmapper.count), strcat(" --res ", ftos(radarmapper.size.x), " ", ftos(radarmapper.size.y), " --sharpen ", ftos(radarmapper.ltime), " --qual ", ftos(radarmapper.size.z)), "\"\n"));
GotoNextMap(0);
}
- remove(radarmapper);
+ delete(radarmapper);
radarmapper = NULL;
}
void RadarMap_Think(entity this)
if (this.cnt < 0)
{
LOG_INFO("Error writing ", this.netname, "\n");
- remove(this);
+ delete(this);
radarmapper = NULL;
return;
}
default:
i = argc;
- remove(radarmapper);
+ delete(radarmapper);
radarmapper = NULL;
break;
}
#include "../playerdemo.qh"
#include "../teamplay.qh"
-#include "../bot/bot.qh"
-#include "../bot/navigation.qh"
-#include "../bot/scripting.qh"
+#include "../bot/api.qh"
#include "../mutators/all.qh"
// used by GameCommand_make_mapinfo()
void make_mapinfo_Think(entity this)
{
- if (MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 0, 0, 1))
+ if (_MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 0, 0, 1))
{
LOG_INFO("Done rebuiling mapinfos.\n");
MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
- remove(this);
+ delete(this);
}
else
{
}
successful = strcat(successful, (successful ? ", " : ""), client.netname);
- LOG_TRACE("Message sent to ", client.netname, "\n");
+ LOG_TRACE("Message sent to ", client.netname);
continue;
}
if (argv(1) != "")
{
string s = argv(1);
- float t = MapInfo_Type_FromString(s), tsave = MapInfo_CurrentGametype();
+ Gametype t = MapInfo_Type_FromString(s), tsave = MapInfo_CurrentGametype();
if (t)
{
LOG_INFO("bone not found\n");
}
- remove(tmp_entity);
+ delete(tmp_entity);
return;
}
}
LOG_INFO("model ", tmp_entity.model, " frame ", ftos(f1), " animtime ", ftos(n / t1), "/s\n");
LOG_INFO("model ", tmp_entity.model, " frame ", ftos(f2), " animtime ", ftos(n / t2), "/s\n");
- remove(tmp_entity);
+ delete(tmp_entity);
return;
}
}
continue;
}
if (it.team_saved) it.team = it.team_saved;
- if (it.flags & FL_PROJECTILE) remove(it); // remove any projectiles left
+ if (it.flags & FL_PROJECTILE) delete(it); // remove any projectiles left
});
// Waypoints and assault start come LAST
restart_mapalreadyrestarted = true;
reset_map(true);
Score_ClearAll();
- remove(this);
+ delete(this);
}
// Forces a restart of the game without actually reloading the map // this is a mess...
float currentbots;
float bots_would_leave;
-void UpdateFrags(entity player, float f);
+void UpdateFrags(entity player, int f);
.float totalfrags;
float team1_score, team2_score, team3_score, team4_score;
IntrusiveList g_waypoints;
STATIC_INIT(g_waypoints) { g_waypoints = IL_NEW(); }
+
+IntrusiveList g_vehicles;
+STATIC_INIT(g_vehicles) { g_vehicles = IL_NEW(); }
+
+IntrusiveList g_turrets;
+STATIC_INIT(g_turrets) { g_turrets = IL_NEW(); }
+
+IntrusiveList g_mines;
+STATIC_INIT(g_mines) { g_mines = IL_NEW(); }
+
+IntrusiveList g_projectiles;
+STATIC_INIT(g_projectiles) { g_projectiles = IL_NEW(); }
#include "g_damage.qh"
-#include "bot/bot.qh"
+#include "bot/api.qh"
#include "g_hook.qh"
#include "mutators/all.qh"
#include "scores.qh"
#include "../lib/csqcmodel/sv_model.qh"
#include "../lib/warpzone/common.qh"
-void UpdateFrags(entity player, float f)
+void UpdateFrags(entity player, int f)
{
PlayerTeamScore_AddScore(player, f);
}
{
if(!STAT(FROZEN, this.owner) || this.owner.iceblock != this)
{
- remove(this);
+ delete(this);
return;
}
setorigin(this, this.owner.origin - '0 0 16');
// remove the ice block
if(targ.iceblock)
- remove(targ.iceblock);
+ delete(targ.iceblock);
targ.iceblock = NULL;
}
// for players, this is done in the regular loop
if(wasfreed(this.owner))
{
- remove(this);
+ delete(this);
return;
}
Fire_ApplyEffect(this.owner);
if(!Fire_IsBurning(this.owner))
{
this.owner.fire_burner = NULL;
- remove(this);
+ delete(this);
return;
}
Fire_ApplyDamage(this.owner);
float IsFlying(entity a);
-void UpdateFrags(entity player, float f);
+void UpdateFrags(entity player, int f);
// NOTE: f=0 means still count as a (positive) kill, but count no frags for it
void W_SwitchWeapon_Force(Player this, Weapon w);
{
if(pl.hook == NULL)
return;
- remove(pl.hook);
+ delete(pl.hook);
pl.hook = NULL;
if(pl.move_movetype == MOVETYPE_FLY)
set_movetype(pl, MOVETYPE_WALK);
if(this.realowner.hook == this)
RemoveGrapplingHook(this.owner);
else // in any case:
- remove(this);
+ delete(this);
}
void GrapplingHookThink(entity this);
missile.reset = GrapplingHookReset;
missile.classname = "grapplinghook";
missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
set_movetype(missile, ((autocvar_g_balance_grapplehook_gravity) ? MOVETYPE_TOSS : MOVETYPE_FLY));
PROJECTILE_MAKETRIGGER(missile);
void dynlight_think(entity this)
{
if(!this.owner)
- remove(this);
+ delete(this);
this.nextthink = time + 0.1;
}
spawnfunc(info_null)
{
- remove(this);
+ delete(this);
// if anything breaks, tell the mapper to fix his map! info_null is meant to remove itself immediately.
}
if(c == 50)
{
- LOG_TRACE("HOLY SHIT! When tracing from ", vtos(v1), " to ", vtos(v2), "\n");
- LOG_TRACE(" Nudging gets us nowhere at ", vtos(pos), "\n");
- LOG_TRACE(" trace_endpos is ", vtos(trace_endpos), "\n");
- LOG_TRACE(" trace distance is ", ftos(vlen(pos - trace_endpos)), "\n");
+ LOG_TRACE("HOLY SHIT! When tracing from ", vtos(v1), " to ", vtos(v2));
+ LOG_TRACE(" Nudging gets us nowhere at ", vtos(pos));
+ LOG_TRACE(" trace_endpos is ", vtos(trace_endpos));
+ LOG_TRACE(" trace distance is ", ftos(vlen(pos - trace_endpos)));
}
stopentity = trace_ent;
if(e)
{
this.lodmodel1 = e.model;
- remove(e);
+ delete(e);
}
}
if(this.lodtarget2 != "")
if(e)
{
this.lodmodel2 = e.model;
- remove(e);
+ delete(e);
}
}
#include "anticheat.qh"
#include "antilag.qh"
-#include "bot/bot.qh"
+#include "bot/api.qh"
#include "campaign.qh"
#include "cheats.qh"
#include "cl_client.qh"
}
}
- float fd, l;
- string s;
-
cvar = cvar_normal;
cvar_string = cvar_string_normal;
cvar_set = cvar_set_normal;
cvar_changes_init(); // do this very early now so it REALLY matches the server config
- compressShortVector_init();
-
maxclients = 0;
for (entity head = nextent(NULL); head; head = nextent(head))
{
// character set: ASCII 33-126 without the following characters: : ; ' " \ $
if(autocvar_sv_eventlog)
{
- s = sprintf("%d.%s.%06d", itos(autocvar_sv_eventlog_files_counter), strftime(false, "%s"), floor(random() * 1000000));
+ string s = sprintf("%d.%s.%06d", itos(autocvar_sv_eventlog_files_counter), strftime(false, "%s"), floor(random() * 1000000));
matchid = strzone(s);
GameLogEcho(strcat(":gamestart:", GetGametype(), "_", GetMapname(), ":", s));
if(whichpack(strcat("maps/", mapname, ".cfg")) != "")
{
- fd = fopen(strcat("maps/", mapname, ".cfg"), FILE_READ);
+ int fd = fopen(strcat("maps/", mapname, ".cfg"), FILE_READ);
if(fd != -1)
{
+ string s;
while((s = fgets(fd)))
{
- l = tokenize_console(s);
+ int l = tokenize_console(s);
if(l < 2)
continue;
if(argv(0) == "cd")
monsterlist_reply = strzone(getmonsterlist());
for(int i = 0; i < 10; ++i)
{
- s = getrecords(i);
+ string s = getrecords(i);
if (s)
records_reply[i] = strzone(s);
}
// fill sv_curl_serverpackages from .serverpackage files
if (autocvar_sv_curl_serverpackages_auto)
{
- s = "csprogs-" WATERMARK ".txt";
+ string s = "csprogs-" WATERMARK ".txt";
// remove automatically managed files from the list to prevent duplicates
for (int i = 0, n = tokenize_console(cvar_string("sv_curl_serverpackages")); i < n; ++i)
{
}
// add automatically managed files to the list
#define X(match) MACRO_BEGIN { \
- fd = search_begin(match, true, false); \
+ int fd = search_begin(match, true, false); \
if (fd >= 0) \
{ \
for (int i = 0, j = search_getsize(fd); i < j; ++i) \
spawnfunc(light)
{
//makestatic (this); // Who the f___ did that?
- remove(this);
+ delete(this);
}
string GetGametype()
LOG_TRACE("checkwp "); LOG_TRACE(map);
if(!fexists(strcat("maps/", map, ".waypoints")))
{
- LOG_TRACE(": no waypoints\n");
+ LOG_TRACE(": no waypoints");
return false;
}
- LOG_TRACE(": has waypoints\n");
+ LOG_TRACE(": has waypoints");
}
// open map size restriction file
fclose(fh);
if(player_count < mapmin)
{
- LOG_TRACE("not enough\n");
+ LOG_TRACE("not enough");
return false;
}
if(player_count > mapmax)
{
- LOG_TRACE("too many\n");
+ LOG_TRACE("too many");
return false;
}
- LOG_TRACE("right size\n");
+ LOG_TRACE("right size");
return true;
}
- LOG_TRACE(": not found\n");
+ LOG_TRACE(": not found");
return true;
}
return 0;
}
else
- LOG_DEBUG( "Couldn't select '", filename, "'...\n" );
+ LOG_DEBUG( "Couldn't select '", filename, "'..." );
return 0;
}
{
float pass, i;
- LOG_TRACE("Trying MaplistMethod_Iterate\n");
+ LOG_TRACE("Trying MaplistMethod_Iterate");
for(pass = 1; pass <= 2; ++pass)
{
float() MaplistMethod_Repeat = // fallback method
{
- LOG_TRACE("Trying MaplistMethod_Repeat\n");
+ LOG_TRACE("Trying MaplistMethod_Repeat");
if(Map_Check(Map_Current, 2))
return Map_Current;
{
float i, imax;
- LOG_TRACE("Trying MaplistMethod_Random\n");
+ LOG_TRACE("Trying MaplistMethod_Random");
imax = 42;
{
float i, j, imax, insertpos;
- LOG_TRACE("Trying MaplistMethod_Shuffle\n");
+ LOG_TRACE("Trying MaplistMethod_Shuffle");
imax = 42;
insertpos = pow(random(), 1 / exponent); // ]0, 1]
insertpos = insertpos * (Map_Count - 1); // ]0, Map_Count - 1]
insertpos = ceil(insertpos) + 1; // {2, 3, 4, ..., Map_Count}
- LOG_TRACE("SHUFFLE: insert pos = ", ftos(insertpos), "\n");
+ LOG_TRACE("SHUFFLE: insert pos = ", ftos(insertpos));
// insert the current map there
newlist = "";
FOREACH_ENTITY_FLOAT(pure_data, false,
{
- if(IS_CLIENT(it) || it.classname == "" || it.movetype == MOVETYPE_PUSH || it.movetype == MOVETYPE_FAKEPUSH || it.movetype == MOVETYPE_PHYSICS)
+ if(IS_CLIENT(it) || it.classname == "" || it.move_movetype == MOVETYPE_PUSH || it.move_movetype == MOVETYPE_FAKEPUSH || it.move_movetype == MOVETYPE_PHYSICS)
continue;
int mt = it.move_movetype;
if(mt == MOVETYPE_PUSH || mt == MOVETYPE_FAKEPUSH || mt == MOVETYPE_PHYSICS)
{
it.move_qcphysics = false;
- it.movetype = mt;
+ set_movetype(it, mt);
continue;
}
-
- it.movetype = ((it.move_qcphysics) ? MOVETYPE_NONE : it.move_movetype);
+
+ set_movetype(it, ((it.move_qcphysics) ? MOVETYPE_NONE : it.move_movetype));
if(it.move_movetype == MOVETYPE_NONE)
continue;
});
}
+void systems_update();
void EndFrame()
{
anticheat_endframe();
PlayerState s = PS(it);
s.ps_push(s, it);
});
+ systems_update();
IL_ENDFRAME();
}
if(world_initialized > 0)
{
world_initialized = 0;
- LOG_TRACE("Saving persistent data...\n");
+ LOG_TRACE("Saving persistent data...");
Ban_SaveBans();
// playerstats with unfinished match
CheatShutdown(); // must be after cheatcount check
db_close(ServerProgsDB);
db_close(TemporaryDB);
- LOG_TRACE("Saving persistent data... done!\n");
+ LOG_TRACE("Saving persistent data... done!");
// tell the bot system the game is ending now
bot_endgame();
LOG_TRACE("received ban list item ", ftos(i / 4), ": ip=", ip);
LOG_TRACE(" timeleft=", ftos(timeleft), " reason=", reason);
- LOG_TRACE(" serverip=", serverip, "\n");
+ LOG_TRACE(" serverip=", serverip);
timeleft -= 1.5 * autocvar_g_ban_sync_timeout;
if(timeleft < 0)
return;
LABEL(killme)
- remove(this);
+ delete(this);
}
const float BAN_MAX = 256;
if(time + bantime > ban_expire[i])
{
ban_expire[i] = time + bantime;
- LOG_TRACE(ip, "'s ban has been prolonged to ", ftos(bantime), " seconds from now\n");
+ LOG_TRACE(ip, "'s ban has been prolonged to ", ftos(bantime), " seconds from now");
}
else
- LOG_TRACE(ip, "'s ban is still active until ", ftos(ban_expire[i] - time), " seconds from now\n");
+ LOG_TRACE(ip, "'s ban is still active until ", ftos(ban_expire[i] - time), " seconds from now");
// and enforce
reason = Ban_Enforce(i, reason);
}
// okay, insert our new victim as i
Ban_Delete(i);
- LOG_TRACE(ip, " has been banned for ", ftos(bantime), " seconds\n");
+ LOG_TRACE(ip, " has been banned for ", ftos(bantime), " seconds");
ban_expire[i] = time + bantime;
ban_ip[i] = strzone(ip);
ban_count = max(ban_count, i + 1);
// reject this entity if more than one key was set!
if (this.itemkeys>0 && (this.itemkeys & (this.itemkeys-1)) != 0) {
objerror(this, "item_key.itemkeys must contain only 1 bit set specifying the key it represents!");
- remove(this);
+ delete(this);
return;
}
if (this.netname == "") {
objerror(this, "item_key doesn't have a default name for this key and a custom one was not specified!");
- remove(this);
+ delete(this);
return;
}
break;
_model = "models/keys/key.md3"; // FIXME: replace it by a keycard model!
} else if (this.model == "") {
objerror(this, "item_key doesn't have a default model for this key and a custom one was not specified!");
- remove(this);
+ delete(this);
return;
}
* Returns the gamtype ID from its name, if type_name isn't a real gametype it
* checks for sv_vote_gametype_(type_name)_type
*/
-float GameTypeVote_Type_FromString(string type_name)
+Gametype GameTypeVote_Type_FromString(string type_name)
{
- float type = MapInfo_Type_FromString(type_name);
- if ( type == 0 )
+ Gametype type = MapInfo_Type_FromString(type_name);
+ if (type == NULL)
type = MapInfo_Type_FromString(cvar_string(
strcat("sv_vote_gametype_",type_name,"_type")));
return type;
{
int flag = GTV_FORBIDDEN;
- float type = MapInfo_Type_FromString(type_name);
- if ( type == 0 )
+ Gametype type = MapInfo_Type_FromString(type_name);
+ if ( type == NULL )
{
type = MapInfo_Type_FromString(cvar_string(
strcat("sv_vote_gametype_",type_name,"_type")));
flag |= GTV_CUSTOM;
}
- if( type == 0 )
+ if( type == NULL )
return flag;
if ( autocvar_nextmap != "" )
{
- if ( !MapInfo_Get_ByName(autocvar_nextmap, false, 0) )
+ if ( !MapInfo_Get_ByName(autocvar_nextmap, false, NULL) )
return flag;
- if (!(MapInfo_Map_supportedGametypes & type))
+ if (!(MapInfo_Map_supportedGametypes & type.m_flags))
return flag;
}
n = min(MAPVOTE_COUNT, n);
gametype_mask = 0;
for(j = 0; j < n; ++j)
- gametype_mask |= GameTypeVote_Type_FromString(argv(j));
+ gametype_mask |= GameTypeVote_Type_FromString(argv(j)).m_flags;
return gametype_mask;
}
if ( autocvar_sv_vote_gametype )
{
MapInfo_Enumerate();
- MapInfo_FilterGametype(GameTypeVote_GetMask(), 0, MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
+ _MapInfo_FilterGametype(GameTypeVote_GetMask(), 0, MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
}
return MapInfo_FixName(m);
}
MapVote_Tick();
}
-float GameTypeVote_SetGametype(float type)
+float GameTypeVote_SetGametype(Gametype type)
{
if (MapInfo_CurrentGametype() == type)
return true;
- float tsave = MapInfo_CurrentGametype();
+ Gametype tsave = MapInfo_CurrentGametype();
MapInfo_SwitchGameType(type);
float GameTypeVote_AddVotable(string nextMode)
{
float j;
- if ( nextMode == "" || GameTypeVote_Type_FromString(nextMode) == 0 )
+ if ( nextMode == "" || GameTypeVote_Type_FromString(nextMode) == NULL )
return false;
for(j = 0; j < mapvote_count; ++j)
if(mapvote_maps[j] == nextMode)
{
LOG_TRACE("Nearest point (");
LOG_TRACE(nearest_entity[0].netname);
- LOG_TRACE(") is not visible, using a visible one.\n");
+ LOG_TRACE(") is not visible, using a visible one.");
}
return nearest_entity[i];
}
if (num_nearest == 0)
return NULL;
- LOG_TRACE("Not seeing any location point, using nearest as fallback.\n");
+ LOG_TRACE("Not seeing any location point, using nearest as fallback.");
/* DEBUGGING CODE:
dprint("Candidates were: ");
for(j = 0; j < num_nearest; ++j)
// these stop the projectile from moving, so...
if(trace_dphitcontents == 0)
{
- //dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
- LOG_TRACEF("A hit from a projectile happened with no hit contents! DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct. (edict: %d, classname: %s, origin: %s)\n", etof(this), this.classname, vtos(this.origin));
+ LOG_TRACEF("A hit from a projectile happened with no hit contents! DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct. (edict: %i, classname: %s, origin: %v)", this, this.classname, this.origin);
checkclient(this);
}
if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
traceline(this.origin - tic, this.origin + tic, MOVE_NORMAL, this);
if (trace_fraction >= 1)
{
- LOG_TRACE("Odd... did not hit...?\n");
+ LOG_TRACE("Odd... did not hit...?");
}
else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
{
- LOG_TRACE("Detected and prevented the sky-grapple bug.\n");
+ LOG_TRACE("Detected and prevented the sky-grapple bug.");
return true;
}
}
else if(this.classname == "spike")
{
W_Crylink_Dequeue(this);
- remove(this);
+ delete(this);
}
else
- remove(this);
+ delete(this);
return true;
}
if(trace_ent && trace_ent.solid > SOLID_TRIGGER)
{
setorigin(e, start);
e.angles = vectoangles(end - start);
- LOG_TRACE("Needed ", ftos(i + 1), " attempts\n");
+ LOG_TRACE("Needed ", ftos(i + 1), " attempts");
return true;
}
else
#include "all.qh"
STATIC_INIT_LATE(Gametype) {
- Gametype g = MapInfo_Type(MapInfo_CurrentGametype());
+ Gametype g = MapInfo_CurrentGametype();
if (g) {
for (string _s = g.m_mutators; _s != ""; _s = cdr(_s)) {
string s = car(_s);
MUTATOR_HOOKABLE(WantWeapon, EV_WantWeapon);
#define EV_AddPlayerScore(i, o) \
- /** score field */ i(int, MUTATOR_ARGV_0_int) \
+ /** score field */ i(PlayerScoreField, MUTATOR_ARGV_0_entity) \
/** score */ i(float, MUTATOR_ARGV_1_float) \
/**/ o(float, MUTATOR_ARGV_1_float) \
/** player */ i(entity, MUTATOR_ARGV_2_entity) \
#include <server/scores_rules.qh>
#include <server/teamplay.qh>
-#include <server/bot/bot.qh>
-#include <server/bot/navigation.qh>
-#include <server/bot/waypoints.qh>
-#include <server/bot/havocbot/roles.qh>
-
-#include <server/bot/havocbot/havocbot.qh>
+#include <server/bot/api.qh>
#include <server/command/vote.qh>
#include <server/scores.qh>
#include <server/scores_rules.qh>
-#include <server/bot/bot.qh>
-#include <server/bot/navigation.qh>
-#include <server/bot/waypoints.qh>
-
-#include <server/bot/havocbot/havocbot.qh>
-#include <server/bot/havocbot/roles.qh>
+#include <server/bot/api.qh>
#include <server/command/vote.qh>
#include <server/command/common.qh>
// scoreboard stuff
const float ST_ASSAULT_OBJECTIVES = 1;
-const float SP_ASSAULT_OBJECTIVES = 4;
// predefined spawnfuncs
void target_objective_decrease_activate(entity this);
// Eject players from vehicles
FOREACH_CLIENT(IS_PLAYER(it) && it.vehicle, vehicles_exit(it.vehicle, VHEF_RELEASE));
- FOREACH_ENTITY_FLAGS(vehicle_flags, VHF_ISVEHICLE, LAMBDA(
+ IL_EACH(g_vehicles, true,
+ {
vehicles_clearreturn(it);
vehicles_spawn(it);
- ));
+ });
// up round counter
this.winning = this.winning + 1;
// spawnfuncs
spawnfunc(info_player_attacker)
{
- if (!g_assault) { remove(this); return; }
+ if (!g_assault) { delete(this); return; }
this.team = NUM_TEAM_1; // red, gets swapped every round
spawnfunc_info_player_deathmatch(this);
spawnfunc(info_player_defender)
{
- if (!g_assault) { remove(this); return; }
+ if (!g_assault) { delete(this); return; }
this.team = NUM_TEAM_2; // blue, gets swapped every round
spawnfunc_info_player_deathmatch(this);
spawnfunc(target_objective)
{
- if (!g_assault) { remove(this); return; }
+ if (!g_assault) { delete(this); return; }
this.classname = "target_objective";
this.use = assault_objective_use;
spawnfunc(target_objective_decrease)
{
- if (!g_assault) { remove(this); return; }
+ if (!g_assault) { delete(this); return; }
this.classname = "target_objective_decrease";
spawnfunc(func_breakable);
spawnfunc(func_assault_destructible)
{
- if (!g_assault) { remove(this); return; }
+ if (!g_assault) { delete(this); return; }
this.spawnflags = 3;
this.classname = "func_assault_destructible";
spawnfunc(func_assault_wall)
{
- if (!g_assault) { remove(this); return; }
+ if (!g_assault) { delete(this); return; }
this.classname = "func_assault_wall";
this.mdl = this.model;
spawnfunc(target_assault_roundend)
{
- if (!g_assault) { remove(this); return; }
+ if (!g_assault) { delete(this); return; }
this.winning = 0; // round not yet won by attackers
this.classname = "target_assault_roundend";
spawnfunc(target_assault_roundstart)
{
- if (!g_assault) { remove(this); return; }
+ if (!g_assault) { delete(this); return; }
assault_attacker_team = NUM_TEAM_1;
this.classname = "target_assault_roundstart";
if(ctf_captureshield_max_ratio <= 0)
return false;
- s = PlayerScore_Add(p, SP_CTF_CAPS, 0);
+ s = PlayerScore_Add(p, SP_CTF_CAPS, 0);
s2 = PlayerScore_Add(p, SP_CTF_PICKUPS, 0);
s3 = PlayerScore_Add(p, SP_CTF_RETURNS, 0);
s4 = PlayerScore_Add(p, SP_CTF_FCKILLS, 0);
FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
if(DIFF_TEAM(it, p))
continue;
- se = PlayerScore_Add(it, SP_CTF_CAPS, 0);
+ se = PlayerScore_Add(it, SP_CTF_CAPS, 0);
se2 = PlayerScore_Add(it, SP_CTF_PICKUPS, 0);
se3 = PlayerScore_Add(it, SP_CTF_RETURNS, 0);
se4 = PlayerScore_Add(it, SP_CTF_FCKILLS, 0);
{
pickup_dropped_score = (autocvar_g_ctf_flag_return_time ? bound(0, ((flag.ctf_droptime + autocvar_g_ctf_flag_return_time) - time) / autocvar_g_ctf_flag_return_time, 1) : 1);
pickup_dropped_score = floor((autocvar_g_ctf_score_pickup_dropped_late * (1 - pickup_dropped_score) + autocvar_g_ctf_score_pickup_dropped_early * pickup_dropped_score) + 0.5);
- LOG_TRACE("pickup_dropped_score is ", ftos(pickup_dropped_score), "\n");
+ LOG_TRACE("pickup_dropped_score is ", ftos(pickup_dropped_score));
PlayerTeamScore_AddScore(player, pickup_dropped_score);
ctf_EventLog("pickup", flag.team, player);
break;
// sanity checks
if(this.mins != CTF_FLAG.m_mins || this.maxs != CTF_FLAG.m_maxs) { // reset the flag boundaries in case it got squished
- LOG_TRACE("wtf the flag got squashed?\n");
+ LOG_TRACE("wtf the flag got squashed?");
tracebox(this.origin, CTF_FLAG.m_mins, CTF_FLAG.m_maxs, this.origin, MOVE_NOMONSTERS, this);
if(!trace_startsolid || this.noalign) // can we resize it without getting stuck?
setsize(this, CTF_FLAG.m_mins, CTF_FLAG.m_maxs); }
default: // this should never happen
{
- LOG_TRACE("ctf_FlagThink(): Flag exists with no status?\n");
+ LOG_TRACE("ctf_FlagThink(): Flag exists with no status?");
return;
}
}
case FLAG_CARRY:
{
- LOG_TRACE("Someone touched a flag even though it was being carried?\n");
+ LOG_TRACE("Someone touched a flag even though it was being carried?");
break;
}
void havocbot_role_ctf_setrole(entity bot, int role)
{
- LOG_TRACE(strcat(bot.netname," switched to "));
+ string s = "(null)";
switch(role)
{
case HAVOCBOT_CTF_ROLE_CARRIER:
- LOG_TRACE("carrier");
+ s = "carrier";
bot.havocbot_role = havocbot_role_ctf_carrier;
bot.havocbot_role_timeout = 0;
bot.havocbot_cantfindflag = time + 10;
bot.bot_strategytime = 0;
break;
case HAVOCBOT_CTF_ROLE_DEFENSE:
- LOG_TRACE("defense");
+ s = "defense";
bot.havocbot_role = havocbot_role_ctf_defense;
bot.havocbot_role_timeout = 0;
break;
case HAVOCBOT_CTF_ROLE_MIDDLE:
- LOG_TRACE("middle");
+ s = "middle";
bot.havocbot_role = havocbot_role_ctf_middle;
bot.havocbot_role_timeout = 0;
break;
case HAVOCBOT_CTF_ROLE_OFFENSE:
- LOG_TRACE("offense");
+ s = "offense";
bot.havocbot_role = havocbot_role_ctf_offense;
bot.havocbot_role_timeout = 0;
break;
case HAVOCBOT_CTF_ROLE_RETRIEVER:
- LOG_TRACE("retriever");
+ s = "retriever";
bot.havocbot_previous_role = bot.havocbot_role;
bot.havocbot_role = havocbot_role_ctf_retriever;
bot.havocbot_role_timeout = time + 10;
bot.bot_strategytime = 0;
break;
case HAVOCBOT_CTF_ROLE_ESCORT:
- LOG_TRACE("escort");
+ s = "escort";
bot.havocbot_previous_role = bot.havocbot_role;
bot.havocbot_role = havocbot_role_ctf_escort;
bot.havocbot_role_timeout = time + 30;
bot.bot_strategytime = 0;
break;
}
- LOG_TRACE("\n");
+ LOG_TRACE(bot.netname, " switched to ", s);
}
MUTATOR_HOOKFUNCTION(ctf, DropSpecialItems)
{
entity frag_target = M_ARGV(0, entity);
-
+
if(frag_target.flagcarried)
ctf_Handle_Throw(frag_target, NULL, DROP_THROW);
}
"noise5" sound played when flag touches the ground... */
spawnfunc(item_flag_team1)
{
- if(!g_ctf) { remove(this); return; }
+ if(!g_ctf) { delete(this); return; }
ctf_FlagSetup(NUM_TEAM_1, this);
}
"noise5" sound played when flag touches the ground... */
spawnfunc(item_flag_team2)
{
- if(!g_ctf) { remove(this); return; }
+ if(!g_ctf) { delete(this); return; }
ctf_FlagSetup(NUM_TEAM_2, this);
}
"noise5" sound played when flag touches the ground... */
spawnfunc(item_flag_team3)
{
- if(!g_ctf) { remove(this); return; }
+ if(!g_ctf) { delete(this); return; }
ctf_FlagSetup(NUM_TEAM_3, this);
}
"noise5" sound played when flag touches the ground... */
spawnfunc(item_flag_team4)
{
- if(!g_ctf) { remove(this); return; }
+ if(!g_ctf) { delete(this); return; }
ctf_FlagSetup(NUM_TEAM_4, this);
}
"noise5" sound played when flag touches the ground... */
spawnfunc(item_flag_neutral)
{
- if(!g_ctf) { remove(this); return; }
- if(!cvar("g_ctf_oneflag")) { remove(this); return; }
+ if(!g_ctf) { delete(this); return; }
+ if(!cvar("g_ctf_oneflag")) { delete(this); return; }
ctf_FlagSetup(0, this);
}
"cnt" Scoreboard color of the team (for example 4 is red and 13 is blue)... */
spawnfunc(ctf_team)
{
- if(!g_ctf) { remove(this); return; }
+ if(!g_ctf) { delete(this); return; }
this.classname = "ctf_team";
this.team = this.cnt + 1;
CheckAllowedTeams(NULL);
ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, 0, true);
ScoreInfo_SetLabel_TeamScore (ST_CTF_CAPS, "caps", SFL_SORT_PRIO_PRIMARY);
- ScoreInfo_SetLabel_PlayerScore(SP_CTF_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
- ScoreInfo_SetLabel_PlayerScore(SP_CTF_CAPTIME, "captime", SFL_LOWER_IS_BETTER | SFL_TIME);
- ScoreInfo_SetLabel_PlayerScore(SP_CTF_PICKUPS, "pickups", 0);
- ScoreInfo_SetLabel_PlayerScore(SP_CTF_FCKILLS, "fckills", 0);
- ScoreInfo_SetLabel_PlayerScore(SP_CTF_RETURNS, "returns", 0);
- ScoreInfo_SetLabel_PlayerScore(SP_CTF_DROPS, "drops", SFL_LOWER_IS_BETTER);
+ ScoreInfo_SetLabel_PlayerScore(SP_CTF_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
+ ScoreInfo_SetLabel_PlayerScore(SP_CTF_CAPTIME, "captime", SFL_LOWER_IS_BETTER | SFL_TIME);
+ ScoreInfo_SetLabel_PlayerScore(SP_CTF_PICKUPS, "pickups", 0);
+ ScoreInfo_SetLabel_PlayerScore(SP_CTF_FCKILLS, "fckills", 0);
+ ScoreInfo_SetLabel_PlayerScore(SP_CTF_RETURNS, "returns", 0);
+ ScoreInfo_SetLabel_PlayerScore(SP_CTF_DROPS, "drops", SFL_LOWER_IS_BETTER);
ScoreRules_basics_end();
}
// if no teams are found, spawn defaults
if(find(NULL, classname, "ctf_team") == NULL)
{
- LOG_TRACE("No \"ctf_team\" entities found on this map, creating them anyway.\n");
+ LOG_TRACE("No \"ctf_team\" entities found on this map, creating them anyway.");
if(ctf_teams & BIT(0))
ctf_SpawnTeam("Red", NUM_TEAM_1);
if(ctf_teams & BIT(1))
// score rule declarations
const int ST_CTF_CAPS = 1;
-const int SP_CTF_CAPS = 4;
-const int SP_CTF_CAPTIME = 5;
-const int SP_CTF_PICKUPS = 6;
-const int SP_CTF_DROPS = 7;
-const int SP_CTF_FCKILLS = 8;
-const int SP_CTF_RETURNS = 9;
CLASS(Flag, Pickup)
- ATTRIB(Flag, m_mins, vector, PL_MIN_CONST + '0 0 -13')
- ATTRIB(Flag, m_maxs, vector, PL_MAX_CONST + '0 0 -13')
+ ATTRIB(Flag, m_mins, vector, PL_MIN_CONST + '0 0 -13');
+ ATTRIB(Flag, m_maxs, vector, PL_MAX_CONST + '0 0 -13');
ENDCLASS(Flag)
Flag CTF_FLAG; STATIC_INIT(Flag) { CTF_FLAG = NEW(Flag); }
void ctf_FlagTouch(entity this, entity toucher) { ITEM_HANDLE(Pickup, CTF_FLAG, this, toucher); }
// scores
const float ST_CTS_LAPS = 1;
-const float SP_CTS_LAPS = 4;
-const float SP_CTS_TIME = 5;
-const float SP_CTS_FASTEST = 6;
#endif
#ifdef IMPLEMENTATION
MUTATOR_HOOKFUNCTION(cts, PlayerPhysics)
{
entity player = M_ARGV(0, entity);
+ float dt = M_ARGV(1, float);
- player.race_movetime_frac += PHYS_INPUT_TIMELENGTH;
+ player.race_movetime_frac += dt;
float f = floor(player.race_movetime_frac);
player.race_movetime_frac -= f;
player.race_movetime_count += f;
MUTATOR_HOOKFUNCTION(cts, PlayerDies)
{
entity frag_target = M_ARGV(2, entity);
-
+
frag_target.respawn_flags |= RESPAWN_FORCE;
race_AbandonRaceCheck(frag_target);
}
if(player.killindicator && player.killindicator.health == 1) // player.killindicator.health == 1 means that the kill indicator was spawned by CTS_ClientKill
{
- remove(player.killindicator);
+ delete(player.killindicator);
player.killindicator = NULL;
ClientKill_Now(player); // allow instant kill in this case
// score rule declarations
const float ST_DOM_TICKS = 1;
-const float SP_DOM_TICKS = 4;
-const float SP_DOM_TAKES = 5;
const float ST_DOM_CAPS = 1;
-const float SP_DOM_CAPS = 4;
// pps: points per second
.float dom_total_pps = _STAT(DOM_TOTAL_PPS);
{
if(!g_domination)
{
- remove(this);
+ delete(this);
return;
}
setthink(this, dom_controlpoint_setup);
{
if(!g_domination || autocvar_g_domination_teams_override >= 2)
{
- remove(this);
+ delete(this);
return;
}
precache_model(this.model);
// if no teams are found, spawn defaults
if(find(NULL, classname, "dom_team") == NULL || autocvar_g_domination_teams_override >= 2)
{
- LOG_TRACE("No \"dom_team\" entities found on this map, creating them anyway.\n");
+ LOG_TRACE("No \"dom_team\" entities found on this map, creating them anyway.");
domination_teams = bound(2, ((autocvar_g_domination_teams_override < 2) ? autocvar_g_domination_default_teams : autocvar_g_domination_teams_override), 4);
dom_spawnteams(domination_teams);
}
int autocvar_g_freezetag_teams_override;
float autocvar_g_freezetag_warmup;
-const float SP_FREEZETAG_REVIVALS = 4;
void freezetag_ScoreRules(int teams)
{
ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, true); // SFL_SORT_PRIO_PRIMARY
// If only one left on team or if role has timed out then start trying to free players.
if (((unfrozen == 0) && (!STAT(FROZEN, this))) || (time > this.havocbot_role_timeout))
{
- LOG_TRACE("changing role to freeing\n");
+ LOG_TRACE("changing role to freeing");
this.havocbot_role = havocbot_role_ft_freeing;
this.havocbot_role_timeout = 0;
return;
if (time > this.havocbot_role_timeout)
{
- LOG_TRACE("changing role to offense\n");
+ LOG_TRACE("changing role to offense");
this.havocbot_role = havocbot_role_ft_offense;
this.havocbot_role_timeout = 0;
return;
spawnfunc(invasion_spawnpoint)
{
- if(!g_invasion) { remove(this); return; }
+ if(!g_invasion) { delete(this); return; }
this.classname = "invasion_spawnpoint";
if(spawn_point == NULL)
{
- LOG_TRACE("Warning: couldn't find any invasion_spawnpoint spawnpoints, attempting to spawn monsters in random locations\n");
+ LOG_TRACE("Warning: couldn't find any invasion_spawnpoint spawnpoints, attempting to spawn monsters in random locations");
entity e = spawn();
setsize(e, (get_monsterinfo(mon)).mins, (get_monsterinfo(mon)).maxs);
entity ka_ball;
-const float SP_KEEPAWAY_PICKUPS = 4;
-const float SP_KEEPAWAY_CARRIERKILLS = 5;
-const float SP_KEEPAWAY_BCTIME = 6;
-
void(entity this) havocbot_role_ka_carrier;
void(entity this) havocbot_role_ka_collector;
MUTATOR_HOOKFUNCTION(ka, DropSpecialItems)
{
entity frag_target = M_ARGV(0, entity);
-
+
if(frag_target.ballcarried)
ka_DropEvent(frag_target);
}
void ka_ScoreRules()
{
ScoreRules_basics(0, SFL_SORT_PRIO_PRIMARY, 0, true); // SFL_SORT_PRIO_PRIMARY
- ScoreInfo_SetLabel_PlayerScore(SP_KEEPAWAY_PICKUPS, "pickups", 0);
- ScoreInfo_SetLabel_PlayerScore(SP_KEEPAWAY_CARRIERKILLS, "bckills", 0);
- ScoreInfo_SetLabel_PlayerScore(SP_KEEPAWAY_BCTIME, "bctime", SFL_SORT_PRIO_SECONDARY);
+ ScoreInfo_SetLabel_PlayerScore(SP_KEEPAWAY_PICKUPS, "pickups", 0);
+ ScoreInfo_SetLabel_PlayerScore(SP_KEEPAWAY_CARRIERKILLS, "bckills", 0);
+ ScoreInfo_SetLabel_PlayerScore(SP_KEEPAWAY_BCTIME, "bctime", SFL_SORT_PRIO_SECONDARY);
ScoreRules_basics_end();
}
void kh_StartRound();
void kh_Controller_SetThink(float t, kh_Think_t func);
-entity kh_worldkeylist;
-.entity kh_worldkeynext;
#endif
#ifdef IMPLEMENTATION
float kh_key_dropped, kh_key_carried;
const float ST_KH_CAPS = 1;
-const float SP_KH_CAPS = 4;
-const float SP_KH_PUSHES = 5;
-const float SP_KH_DESTROYS = 6;
-const float SP_KH_PICKUPS = 7;
-const float SP_KH_KCKILLS = 8;
-const float SP_KH_LOSSES = 9;
void kh_ScoreRules(int teams)
{
ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, true);
}
}
- remove(key);
+ delete(key);
kh_update_state();
}
{
// to be called before intermission
kh_FinishRound();
- remove(kh_controller);
+ delete(kh_controller);
kh_controller = NULL;
}
if (!(this.kh_next))
{
- LOG_TRACE("changing role to freelancer\n");
+ LOG_TRACE("changing role to freelancer");
this.havocbot_role = havocbot_role_kh_freelancer;
this.havocbot_role_timeout = 0;
return;
if (this.kh_next)
{
- LOG_TRACE("changing role to carrier\n");
+ LOG_TRACE("changing role to carrier");
this.havocbot_role = havocbot_role_kh_carrier;
this.havocbot_role_timeout = 0;
return;
this.havocbot_role_timeout = time + random() * 10 + 20;
if (time > this.havocbot_role_timeout)
{
- LOG_TRACE("changing role to freelancer\n");
+ LOG_TRACE("changing role to freelancer");
this.havocbot_role = havocbot_role_kh_freelancer;
this.havocbot_role_timeout = 0;
return;
if (this.kh_next)
{
- LOG_TRACE("changing role to carrier\n");
+ LOG_TRACE("changing role to carrier");
this.havocbot_role = havocbot_role_kh_carrier;
this.havocbot_role_timeout = 0;
return;
this.havocbot_role_timeout = time + random() * 10 + 20;
if (time > this.havocbot_role_timeout)
{
- LOG_TRACE("changing role to freelancer\n");
+ LOG_TRACE("changing role to freelancer");
this.havocbot_role = havocbot_role_kh_freelancer;
this.havocbot_role_timeout = 0;
return;
if (this.kh_next)
{
- LOG_TRACE("changing role to carrier\n");
+ LOG_TRACE("changing role to carrier");
this.havocbot_role = havocbot_role_kh_carrier;
this.havocbot_role_timeout = 0;
return;
{
if (random() < 0.5)
{
- LOG_TRACE("changing role to offense\n");
+ LOG_TRACE("changing role to offense");
this.havocbot_role = havocbot_role_kh_offense;
}
else
{
- LOG_TRACE("changing role to defense\n");
+ LOG_TRACE("changing role to defense");
this.havocbot_role = havocbot_role_kh_defense;
}
this.havocbot_role_timeout = 0;
MUTATOR_HOOKFUNCTION(kh, DropSpecialItems)
{
entity frag_target = M_ARGV(0, entity);
-
+
kh_Key_DropAll(frag_target, false);
}
return 0;
}
-// scoreboard stuff
-const float SP_LMS_LIVES = 4;
-const float SP_LMS_RANK = 5;
-
// lives related defs
float lms_lowest_lives;
float lms_next_place;
{
// SNAFU (maybe a draw game?)
ClearWinners();
- LOG_TRACE("No players, ending game.\n");
+ LOG_TRACE("No players, ending game.");
return WINNING_YES;
}
}
MUTATOR_HOOKFUNCTION(lms, PlayerDies)
{
entity frag_target = M_ARGV(2, entity);
-
+
frag_target.respawn_flags |= RESPAWN_FORCE;
}
MUTATOR_HOOKFUNCTION(lms, AddPlayerScore)
{
if(gameover)
- if(M_ARGV(0, int) == SP_LMS_RANK) // score field
+ if(M_ARGV(0, entity) == SP_LMS_RANK) // score field
return true; // allow writing to this field in intermission as it is needed for newly joining players
}
ScoreRules_basics(race_teams, 0, 0, false);
if(race_teams)
{
- ScoreInfo_SetLabel_TeamScore( ST_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
+ ScoreInfo_SetLabel_TeamScore( ST_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
ScoreInfo_SetLabel_PlayerScore(SP_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
ScoreInfo_SetLabel_PlayerScore(SP_RACE_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME);
MUTATOR_HOOKFUNCTION(rc, PlayerPhysics)
{
entity player = M_ARGV(0, entity);
+ float dt = M_ARGV(1, float);
- player.race_movetime_frac += PHYS_INPUT_TIMELENGTH;
+ player.race_movetime_frac += dt;
float f = floor(player.race_movetime_frac);
player.race_movetime_frac -= f;
player.race_movetime_count += f;
MUTATOR_HOOKFUNCTION(rc, PlayerDies)
{
entity frag_target = M_ARGV(2, entity);
-
+
frag_target.respawn_flags |= RESPAWN_FORCE;
race_AbandonRaceCheck(frag_target);
}
"cnt" Scoreboard color of the team (for example 4 is red and 13 is blue)... */
spawnfunc(tdm_team)
{
- if(!g_tdm || !this.cnt) { remove(this); return; }
+ if(!g_tdm || !this.cnt) { delete(this); return; }
this.classname = "tdm_team";
this.team = this.cnt + 1;
// if no teams are found, spawn defaults
if(find(NULL, classname, "tdm_team") == NULL)
{
- LOG_TRACE("No \"tdm_team\" entities found on this map, creating them anyway.\n");
+ LOG_TRACE("No \"tdm_team\" entities found on this map, creating them anyway.");
int numteams = autocvar_g_tdm_teams_override;
if(inwater(parent.origin))
{
- LOG_TRACE("FromWater\n");
+ LOG_TRACE("FromWater");
pathlib_expandnode = pathlib_expandnode_box;
pathlib_movenode = pathlib_swimnode;
}
{
if(inwater(to))
{
- LOG_TRACE("ToWater\n");
+ LOG_TRACE("ToWater");
pathlib_expandnode = pathlib_expandnode_box;
pathlib_movenode = pathlib_walknode;
}
else
{
- LOG_TRACE("LandToLoand\n");
+ LOG_TRACE("LandToLoand");
//if(edge_check(parent.origin))
// return 0;
node = pathlib_nodeatpoint(to);
if(node)
{
- LOG_TRACE("NodeAtPoint\n");
+ LOG_TRACE("NodeAtPoint");
++pathlib_merge_cnt;
if(node.owner == openlist)
{
//pathlib_showsquare(where, 0 ,30);
//pathlib_showsquare(parent.origin, 1 ,30);
- LOG_TRACE("pathlib_movenode_goodnode = 0\n");
+ LOG_TRACE("pathlib_movenode_goodnode = 0");
return 0;
}
if(pathlib_nodeatpoint(where))
{
- LOG_TRACE("NAP WHERE :",vtos(where),"\n");
- LOG_TRACE("not NAP TO:",vtos(to),"\n");
- LOG_TRACE("NAP-NNAP:",ftos(vlen(to-where)),"\n\n");
+ LOG_TRACE("NAP WHERE :",vtos(where));
+ LOG_TRACE("not NAP TO:",vtos(to));
+ LOG_TRACE("NAP-NNAP:",ftos(vlen(to-where)));
return 0;
}
if(doedge)
if (!tile_check(parent, where))
{
- LOG_TRACE("tile_check fail\n");
+ LOG_TRACE("tile_check fail");
#if DEBUGPATHING
pathlib_showsquare(where, 0 ,30);
#endif
if(node.owner == closedlist)
{
- LOG_TRACE("Pathlib: Tried to close a closed node!\n");
+ LOG_TRACE("Pathlib: Tried to close a closed node!");
return;
}
}
if(openlist)
- remove(openlist);
+ delete(openlist);
if(closedlist)
- remove(closedlist);
+ delete(closedlist);
openlist = NULL;
closedlist = NULL;
to.y = fsnap(to.y, pathlib_gridsize);
//to_z += 32;
- LOG_TRACE("AStar init\n");
+ LOG_TRACE("AStar init");
path = pathlib_mknode(from, NULL);
pathlib_close_node(path, to);
if(pathlib_foundgoal)
{
- LOG_TRACE("AStar: Goal found on first node!\n");
+ LOG_TRACE("AStar: Goal found on first node!");
open = new(path_end);
open.owner = open;
if(pathlib_expandnode(path, from, to) <= 0)
{
- LOG_TRACE("AStar path fail.\n");
+ LOG_TRACE("AStar path fail.");
pathlib_cleanup();
return NULL;
{
if((gettime(GETTIME_REALTIME) - pathlib_starttime) > pathlib_maxtime)
{
- LOG_TRACE("Path took to long to compute!\n");
- LOG_TRACE("Nodes - created: ", ftos(pathlib_made_cnt),"\n");
- LOG_TRACE("Nodes - open: ", ftos(pathlib_open_cnt),"\n");
- LOG_TRACE("Nodes - merged: ", ftos(pathlib_merge_cnt),"\n");
- LOG_TRACE("Nodes - closed: ", ftos(pathlib_closed_cnt),"\n");
+ LOG_TRACE("Path took to long to compute!");
+ LOG_TRACE("Nodes - created: ", ftos(pathlib_made_cnt));
+ LOG_TRACE("Nodes - open: ", ftos(pathlib_open_cnt));
+ LOG_TRACE("Nodes - merged: ", ftos(pathlib_merge_cnt));
+ LOG_TRACE("Nodes - closed: ", ftos(pathlib_closed_cnt));
pathlib_cleanup();
return NULL;
if(pathlib_foundgoal)
{
- LOG_TRACE("Target found. Rebuilding and filtering path...\n");
+ LOG_TRACE("Target found. Rebuilding and filtering path...");
ftime = gettime(GETTIME_REALTIME);
ptime = ftime - ptime;
#if DEBUGPATHING
pathlib_showpath2(start);
- LOG_TRACE("Time used - pathfinding: ", ftos(ptime),"\n");
- LOG_TRACE("Time used - rebuild & filter: ", ftos(ftime),"\n");
- LOG_TRACE("Time used - cleanup: ", ftos(ctime),"\n");
- LOG_TRACE("Time used - total: ", ftos(ptime + ftime + ctime),"\n");
- LOG_TRACE("Time used - # frames: ", ftos(ceil((ptime + ftime + ctime) / sys_frametime)),"\n\n");
- LOG_TRACE("Nodes - created: ", ftos(pathlib_made_cnt),"\n");
- LOG_TRACE("Nodes - open: ", ftos(pathlib_open_cnt),"\n");
- LOG_TRACE("Nodes - merged: ", ftos(pathlib_merge_cnt),"\n");
- LOG_TRACE("Nodes - closed: ", ftos(pathlib_closed_cnt),"\n");
- LOG_TRACE("Nodes - searched: ", ftos(pathlib_searched_cnt),"\n");
- LOG_TRACE("Nodes bestopen searched: ", ftos(pathlib_bestopen_searched),"\n");
- LOG_TRACE("Nodes bestcash - hits: ", ftos(pathlib_bestcash_hits),"\n");
- LOG_TRACE("Nodes bestcash - save: ", ftos(pathlib_bestcash_saved),"\n");
- LOG_TRACE("AStar done.\n");
+ LOG_TRACE("Time used - pathfinding: ", ftos(ptime));
+ LOG_TRACE("Time used - rebuild & filter: ", ftos(ftime));
+ LOG_TRACE("Time used - cleanup: ", ftos(ctime));
+ LOG_TRACE("Time used - total: ", ftos(ptime + ftime + ctime));
+ LOG_TRACE("Time used - # frames: ", ftos(ceil((ptime + ftime + ctime) / sys_frametime)));
+ LOG_TRACE("Nodes - created: ", ftos(pathlib_made_cnt));
+ LOG_TRACE("Nodes - open: ", ftos(pathlib_open_cnt));
+ LOG_TRACE("Nodes - merged: ", ftos(pathlib_merge_cnt));
+ LOG_TRACE("Nodes - closed: ", ftos(pathlib_closed_cnt));
+ LOG_TRACE("Nodes - searched: ", ftos(pathlib_searched_cnt));
+ LOG_TRACE("Nodes bestopen searched: ", ftos(pathlib_bestopen_searched));
+ LOG_TRACE("Nodes bestcash - hits: ", ftos(pathlib_bestcash_hits));
+ LOG_TRACE("Nodes bestcash - save: ", ftos(pathlib_bestcash_saved));
+ LOG_TRACE("AStar done.");
#endif
return start;
}
}
- LOG_TRACE("A* Faild to find a path! Try a smaller gridsize.\n");
+ LOG_TRACE("A* Faild to find a path! Try a smaller gridsize.");
pathlib_cleanup();
{
te_lightning1(this,this.origin, this.pos1);
if(this.cnt < time)
- remove(this);
+ delete(this);
else
this.nextthink = time + 0.2;
}
vector direction,point,last_point,s,e;
float steps, distance, i;
- LOG_TRACE("Walking node from ", vtos(start), " to ", vtos(end), "\n");
+ LOG_TRACE("Walking node from ", vtos(start), " to ", vtos(end));
pathlib_movenode_goodnode = 0;
//start - movenode_maxdrop
a.cnt = time + 10;
- LOG_TRACE("I cant walk on air!\n");
+ LOG_TRACE("I cant walk on air!");
return trace_endpos;
}
#include "path_waypoint.qh"
-#include "../bot/waypoints.qh"
+#include "../bot/api.qh"
#include "pathlib.qh"
#include "main.qh"
pathlib_searched_cnt = 0;
pathlib_foundgoal = false;
- LOG_TRACE("pathlib_waypointpath init\n");
+ LOG_TRACE("pathlib_waypointpath init");
// Initialize waypoint grid
IL_EACH(g_waypoints, true,
start_node = wp_from;
start_node.pathlib_list = closedlist;
- LOG_TRACE("Expanding ",ftos(pathlib_wpp_expand(start_node))," links\n");
+ LOG_TRACE("Expanding ",ftos(pathlib_wpp_expand(start_node))," links");
if(pathlib_open_cnt <= 0)
{
- LOG_TRACE("pathlib_waypointpath: Start waypoint not linked! aborting.\n");
+ LOG_TRACE("pathlib_waypointpath: Start waypoint not linked! aborting.");
return NULL;
}
n = pathlib_wpp_bestopen();
if(!n)
{
- LOG_TRACE("Cannot find best open node, abort.\n");
+ LOG_TRACE("Cannot find best open node, abort.");
return NULL;
}
pathlib_wpp_close(n);
- LOG_TRACE("Expanding ",ftos(pathlib_wpp_expand(n))," links\n");
+ LOG_TRACE("Expanding ",ftos(pathlib_wpp_expand(n))," links");
if(pathlib_foundgoal)
{
entity start, end, open, ln;
- LOG_TRACE("Target found. Rebuilding and filtering path...\n");
+ LOG_TRACE("Target found. Rebuilding and filtering path...");
buildpath_nodefilter = buildpath_nodefilter_none;
start = path_build(NULL, start_node.origin, NULL, NULL);
fixedmakevectors(portal.mangle);
sound(portal, CH_SHOTS, SND_PORTO_EXPLODE, VOL_BASE, ATTEN_NORM);
Send_Effect(EFFECT_ROCKET_EXPLODE, portal.origin + v_forward * 16, v_forward * 1024, 4);
- remove(portal);
+ delete(portal);
}
else
{
if(!Portal_FindSafeOrigin(portal))
{
- remove(portal);
+ delete(portal);
return NULL;
}
#include "../server/_mod.inc"
#include "bot/_mod.inc"
-#include "bot/havocbot/_mod.inc"
#include "command/_mod.inc"
#include "mutators/_mod.inc"
#include "pathlib/_all.inc"
#include "portals.qh"
#include "scores.qh"
#include "spawnpoints.qh"
-#include "bot/waypoints.qh"
-#include "bot/navigation.qh"
+#include "bot/api.qh"
#include "command/getreplies.qh"
#include "../common/deathtypes/all.qh"
#include "../common/notifications/all.qh"
spawnfunc(trigger_race_checkpoint)
{
vector o;
- if(!g_race && !g_cts) { remove(this); return; }
+ if(!g_race && !g_cts) { delete(this); return; }
EXACTTRIGGER_INIT;
spawnfunc(target_checkpoint) // defrag entity
{
vector o;
- if(!g_race && !g_cts) { remove(this); return; }
+ if(!g_race && !g_cts) { delete(this); return; }
defrag_ents = 1;
EXACTTRIGGER_INIT;
spawnfunc(info_player_race)
{
- if(!g_race && !g_cts) { remove(this); return; }
+ if(!g_race && !g_cts) { delete(this); return; }
++race_spawns;
spawnfunc_info_player_deathmatch(this);
// scores
const float ST_RACE_LAPS = 1;
-const float SP_RACE_LAPS = 4;
-const float SP_RACE_TIME = 5;
-const float SP_RACE_FASTEST = 6;
bool g_race_qualifying;
void round_handler_Remove()
{
- remove(round_handler);
+ delete(round_handler);
round_handler = NULL;
}
.entity scorekeeper;
entity teamscorekeepers[16];
-string scores_label[MAX_SCORE];
-float scores_flags[MAX_SCORE];
-string teamscores_label[MAX_TEAMSCORE];
-float teamscores_flags[MAX_TEAMSCORE];
float teamscores_entities_count;
var .float scores_primary;
var .float teamscores_primary;
longflags = 0;
for(i = 0, p = 1; i < MAX_TEAMSCORE; ++i, p *= 2)
- if(this.(teamscores[i]) > 127 || this.(teamscores[i]) <= -128)
+ if(this.(teamscores(i)) > 127 || this.(teamscores(i)) <= -128)
longflags |= p;
#if MAX_TEAMSCORE <= 8
if(sendflags & p)
{
if(longflags & p)
- WriteInt24_t(MSG_ENTITY, this.(teamscores[i]));
+ WriteInt24_t(MSG_ENTITY, this.(teamscores(i)));
else
- WriteChar(MSG_ENTITY, this.(teamscores[i]));
+ WriteChar(MSG_ENTITY, this.(teamscores(i)));
}
return true;
error("Adding score to unknown team!");
}
if(score)
- if(teamscores_label[scorefield] != "")
+ if(teamscores_label(scorefield) != "")
s.SendFlags |= pow(2, scorefield);
- return (s.(teamscores[scorefield]) += score);
+ return (s.(teamscores(scorefield)) += score);
}
float TeamScore_Add(entity player, float scorefield, float score)
for(i = 0; i < MAX_TEAMSCORE; ++i)
{
var .float f;
- f = teamscores[i];
- result = ScoreField_Compare(t1, t2, f, teamscores_flags[i], result, strict);
+ f = teamscores(i);
+ result = ScoreField_Compare(t1, t2, f, teamscores_flags(i), result, strict);
}
if (result.x == 0 && strict)
* the scoreinfo entity
*/
-void ScoreInfo_SetLabel_PlayerScore(float i, string label, float scoreflags)
+void ScoreInfo_SetLabel_PlayerScore(PlayerScoreField i, string label, float scoreflags)
{
- scores_label[i] = label;
- scores_flags[i] = scoreflags;
+ scores_label(i) = label;
+ scores_flags(i) = scoreflags;
if((scoreflags & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_PRIMARY)
{
- scores_primary = scores[i];
+ scores_primary = scores(i);
scores_flags_primary = scoreflags;
}
if(label != "")
void ScoreInfo_SetLabel_TeamScore(float i, string label, float scoreflags)
{
- teamscores_label[i] = label;
- teamscores_flags[i] = scoreflags;
+ teamscores_label(i) = label;
+ teamscores_flags(i) = scoreflags;
if((scoreflags & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_PRIMARY)
{
- teamscores_primary = teamscores[i];
+ teamscores_primary = teamscores(i);
teamscores_flags_primary = scoreflags;
}
if(label != "")
{
float i;
WriteHeader(MSG_ENTITY, ENT_CLIENT_SCORES_INFO);
- WriteInt24_t(MSG_ENTITY, MapInfo_LoadedGametype);
- for(i = 0; i < MAX_SCORE; ++i)
- {
- WriteString(MSG_ENTITY, scores_label[i]);
- WriteByte(MSG_ENTITY, scores_flags[i]);
- }
+ WriteRegistered(Gametypes, MSG_ENTITY, MapInfo_LoadedGametype);
+ FOREACH(Scores, true, {
+ WriteString(MSG_ENTITY, scores_label(it));
+ WriteByte(MSG_ENTITY, scores_flags(it));
+ });
for(i = 0; i < MAX_TEAMSCORE; ++i)
{
- WriteString(MSG_ENTITY, teamscores_label[i]);
- WriteByte(MSG_ENTITY, teamscores_flags[i]);
+ WriteString(MSG_ENTITY, teamscores_label(i));
+ WriteByte(MSG_ENTITY, teamscores_flags(i));
}
return true;
}
bool PlayerScore_SendEntity(entity this, entity to, float sendflags)
{
- float i, p, longflags;
-
WriteHeader(MSG_ENTITY, ENT_CLIENT_SCORES);
WriteByte(MSG_ENTITY, etof(this.owner));
- longflags = 0;
- for(i = 0, p = 1; i < MAX_SCORE; ++i, p *= 2)
- if(this.(scores[i]) > 127 || this.(scores[i]) <= -128)
+ int longflags = 0;
+ FOREACH(Scores, true, {
+ int p = 1 << (i % 16);
+ if (this.(scores(it)) > 127 || this.(scores(it)) <= -128)
longflags |= p;
+ });
-#if MAX_SCORE <= 8
- WriteByte(MSG_ENTITY, sendflags);
- WriteByte(MSG_ENTITY, longflags);
-#else
WriteShort(MSG_ENTITY, sendflags);
WriteShort(MSG_ENTITY, longflags);
-#endif
- for(i = 0, p = 1; i < MAX_SCORE; ++i, p *= 2)
- if(sendflags & p)
+ FOREACH(Scores, true, {
+ int p = 1 << (i % 16);
+ if (sendflags & p)
{
if(longflags & p)
- WriteInt24_t(MSG_ENTITY, this.(scores[i]));
+ WriteInt24_t(MSG_ENTITY, this.(scores(it)));
else
- WriteChar(MSG_ENTITY, this.(scores[i]));
+ WriteChar(MSG_ENTITY, this.(scores(it)));
}
+ });
return true;
}
float PlayerScore_Clear(entity player)
{
entity sk;
- float i;
if(teamscores_entities_count)
return 0;
if(MUTATOR_CALLHOOK(ForbidPlayerScore_Clear)) return 0;
sk = player.scorekeeper;
- for(i = 0; i < MAX_SCORE; ++i)
- {
- if(sk.(scores[i]) != 0)
- if(scores_label[i] != "")
- sk.SendFlags |= pow(2, i);
- sk.(scores[i]) = 0;
- }
+ FOREACH(Scores, true, {
+ if(sk.(scores(it)) != 0)
+ if(scores_label(it) != "")
+ sk.SendFlags |= pow(2, i % 16);
+ sk.(scores(it)) = 0;
+ });
return 1;
}
{
entity sk;
float t;
- FOREACH_CLIENTSLOT(true,
- {
+ FOREACH_CLIENTSLOT(true, {
sk = it.scorekeeper;
- if(!sk)
- continue;
- for(int j = 0; j < MAX_SCORE; ++j)
- {
- if(sk.(scores[j]) != 0)
- if(scores_label[j] != "")
- sk.SendFlags |= pow(2, j);
- sk.(scores[j]) = 0;
- }
+ if (!sk) continue;
+ FOREACH(Scores, true, {
+ if(sk.(scores(it)) != 0)
+ if(scores_label(it) != "")
+ sk.SendFlags |= pow(2, i % 16);
+ sk.(scores(it)) = 0;
+ });
});
for(t = 0; t < 16; ++t)
{
continue;
for(int j = 0; j < MAX_TEAMSCORE; ++j)
{
- if(sk.(teamscores[j]) != 0)
- if(teamscores_label[j] != "")
+ if(sk.(teamscores(j)) != 0)
+ if(teamscores_label(j) != "")
sk.SendFlags |= pow(2, j);
- sk.(teamscores[j]) = 0;
+ sk.(teamscores(j)) = 0;
}
}
}
{
if(!player.scorekeeper)
error("player has no scorekeeper");
- remove(player.scorekeeper);
+ delete(player.scorekeeper);
player.scorekeeper = NULL;
}
-float PlayerScore_Add(entity player, float scorefield, float score)
+float PlayerScore_Add(entity player, PlayerScoreField scorefield, float score)
{
bool mutator_returnvalue = MUTATOR_CALLHOOK(AddPlayerScore, scorefield, score, player);
score = M_ARGV(1, float);
{
if(gameover)
return 0;
- LOG_WARNING("Adding score to unknown player!");
+ LOG_WARN("Adding score to unknown player!");
return 0;
}
if(score)
- if(scores_label[scorefield] != "")
- s.SendFlags |= pow(2, scorefield);
+ if(scores_label(scorefield) != "")
+ s.SendFlags |= pow(2, scorefield.m_id % 16);
if(!warmup_stage)
- PS_GR_P_ADDVAL(s.owner, strcat(PLAYERSTATS_TOTAL, scores_label[scorefield]), score);
- return (s.(scores[scorefield]) += score);
+ PS_GR_P_ADDVAL(s.owner, strcat(PLAYERSTATS_TOTAL, scores_label(scorefield)), score);
+ return (s.(scores(scorefield)) += score);
}
-float PlayerTeamScore_Add(entity player, float pscorefield, float tscorefield, float score)
+float PlayerTeamScore_Add(entity player, PlayerScoreField pscorefield, float tscorefield, float score)
{
float r;
r = PlayerScore_Add(player, pscorefield, score);
if(!t1 || !t2) return (!t2) - !t1;
vector result = '0 0 0';
- float i;
- for(i = 0; i < MAX_SCORE; ++i)
- {
- var .float f;
- f = scores[i];
- result = ScoreField_Compare(t1, t2, f, scores_flags[i], result, strict);
- }
+ FOREACH(Scores, true, {
+ var .float f = scores(it);
+ result = ScoreField_Compare(t1, t2, f, scores_flags(it), result, strict);
+ });
if (result.x == 0 && strict)
result.x = etof(t1.owner) - etof(t2.owner);
{
string out;
entity sk;
- float i, f;
+ float f;
string l;
out = "";
if(!pl)
{
// label
- for(i = 0; i < MAX_SCORE; ++i)
- if((scores_flags[i] & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_PRIMARY)
+ FOREACH(Scores, true, {
+ if ((scores_flags(it) & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_PRIMARY)
{
- f = scores_flags[i];
- l = scores_label[i];
+ f = scores_flags(it);
+ l = scores_label(it);
out = strcat(out, GetScoreLogLabel(l, f), ",");
}
+ });
if(shortString < 2)
- for(i = 0; i < MAX_SCORE; ++i)
- if((scores_flags[i] & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_SECONDARY)
+ FOREACH(Scores, true, {
+ if((scores_flags(it) & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_SECONDARY)
{
- f = scores_flags[i];
- l = scores_label[i];
+ f = scores_flags(it);
+ l = scores_label(it);
out = strcat(out, GetScoreLogLabel(l, f), ",");
}
+ });
if(shortString < 1)
- for(i = 0; i < MAX_SCORE; ++i)
- if((scores_flags[i] & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_PRIMARY)
- if((scores_flags[i] & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_SECONDARY)
+ FOREACH(Scores, true, {
+ if((scores_flags(it) & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_PRIMARY)
+ if((scores_flags(it) & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_SECONDARY)
{
- f = scores_flags[i];
- l = scores_label[i];
+ f = scores_flags(it);
+ l = scores_label(it);
out = strcat(out, GetScoreLogLabel(l, f), ",");
}
+ });
out = substring(out, 0, strlen(out) - 1);
}
else if((sk = pl.scorekeeper))
{
- for(i = 0; i < MAX_SCORE; ++i)
- if((scores_flags[i] & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_PRIMARY)
- out = strcat(out, ftos(sk.(scores[i])), ",");
+ FOREACH(Scores, true, {
+ if ((scores_flags(it) & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_PRIMARY)
+ out = strcat(out, ftos(sk.(scores(it))), ",");
+ });
if(shortString < 2)
- for(i = 0; i < MAX_SCORE; ++i)
- if((scores_flags[i] & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_SECONDARY)
- out = strcat(out, ftos(sk.(scores[i])), ",");
+ FOREACH(Scores, true, {
+ if ((scores_flags(it) & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_SECONDARY)
+ out = strcat(out, ftos(sk.(scores(it))), ",");
+ });
if(shortString < 1)
- for(i = 0; i < MAX_SCORE; ++i)
- if((scores_flags[i] & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_PRIMARY)
- if((scores_flags[i] & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_SECONDARY)
- out = strcat(out, ftos(sk.(scores[i])), ",");
+ FOREACH(Scores, true, {
+ if((scores_flags(it) & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_PRIMARY)
+ if((scores_flags(it) & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_SECONDARY)
+ out = strcat(out, ftos(sk.(scores(it))), ",");
+ });
out = substring(out, 0, strlen(out) - 1);
}
return out;
{
// label
for(i = 0; i < MAX_TEAMSCORE; ++i)
- if((teamscores_flags[i] & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_PRIMARY)
+ if((teamscores_flags(i) & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_PRIMARY)
{
- f = teamscores_flags[i];
- l = teamscores_label[i];
+ f = teamscores_flags(i);
+ l = teamscores_label(i);
out = strcat(out, GetScoreLogLabel(l, f), ",");
}
if(shortString < 2)
for(i = 0; i < MAX_TEAMSCORE; ++i)
- if((teamscores_flags[i] & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_SECONDARY)
+ if((teamscores_flags(i) & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_SECONDARY)
{
- f = teamscores_flags[i];
- l = teamscores_label[i];
+ f = teamscores_flags(i);
+ l = teamscores_label(i);
out = strcat(out, GetScoreLogLabel(l, f), ",");
}
if(shortString < 1)
for(i = 0; i < MAX_TEAMSCORE; ++i)
- if((teamscores_flags[i] & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_PRIMARY)
- if((teamscores_flags[i] & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_SECONDARY)
+ if((teamscores_flags(i) & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_PRIMARY)
+ if((teamscores_flags(i) & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_SECONDARY)
{
- f = teamscores_flags[i];
- l = teamscores_label[i];
+ f = teamscores_flags(i);
+ l = teamscores_label(i);
out = strcat(out, GetScoreLogLabel(l, f), ",");
}
out = substring(out, 0, strlen(out) - 1);
else if((sk = teamscorekeepers[tm - 1]))
{
for(i = 0; i < MAX_TEAMSCORE; ++i)
- if((teamscores_flags[i] & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_PRIMARY)
- out = strcat(out, ftos(sk.(teamscores[i])), ",");
+ if((teamscores_flags(i) & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_PRIMARY)
+ out = strcat(out, ftos(sk.(teamscores(i))), ",");
if(shortString < 2)
for(i = 0; i < MAX_TEAMSCORE; ++i)
- if((teamscores_flags[i] & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_SECONDARY)
- out = strcat(out, ftos(sk.(teamscores[i])), ",");
+ if((teamscores_flags(i) & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_SECONDARY)
+ out = strcat(out, ftos(sk.(teamscores(i))), ",");
if(shortString < 1)
for(i = 0; i < MAX_TEAMSCORE; ++i)
- if((teamscores_flags[i] & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_PRIMARY)
- if((teamscores_flags[i] & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_SECONDARY)
- out = strcat(out, ftos(sk.(teamscores[i])), ",");
+ if((teamscores_flags(i) & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_PRIMARY)
+ if((teamscores_flags(i) & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_SECONDARY)
+ out = strcat(out, ftos(sk.(teamscores(i))), ",");
out = substring(out, 0, strlen(out) - 1);
}
return out;
{
s = strcat(s, Team_ColoredFullName(t));
for(i = 0; i < MAX_TEAMSCORE; ++i)
- if(teamscores_label[i] != "")
+ if(teamscores_label(i) != "")
{
- fl = teamscores_flags[i];
- sc = sk.(teamscores[i]);
+ fl = teamscores_flags(i);
+ sc = sk.(teamscores(i));
s = strcat(s, " ", Score_NicePrint_ItemColor(fl), ScoreString(fl, sc));
}
}
s = strcat(s, strpad(max(0, NAMEWIDTH - strlennocol(s)), ""));
- for(i = 0; i < MAX_SCORE; ++i)
- if(scores_label[i] != "")
+ FOREACH(Scores, true, {
+ if(scores_label(it) != "")
{
- fl = scores_flags[i];
- s2 = scores_label[i];
+ fl = scores_flags(it);
+ s2 = scores_label(it);
s = strcat(s, " ", Score_NicePrint_ItemColor(fl), strpad(-w, substring(s2, 0, w)));
}
+ });
print_to(to, s);
}
}
}
- for(i = 0; i < MAX_SCORE; ++i)
- if(scores_label[i] != "")
+ FOREACH(Scores, true, {
+ if(scores_label(it) != "")
{
- fl = scores_flags[i];
- sc = sk.(scores[i]);
+ fl = scores_flags(it);
+ sc = sk.(scores(it));
s = strcat(s, " ", Score_NicePrint_ItemColor(fl), strpad(-w, ScoreString(fl, sc)));
}
+ });
print_to(to, s);
}
void Score_NicePrint(entity to)
{
entity p;
- float i;
float w;
int t = 0;
- for(i = 0; i < MAX_SCORE; ++i)
- if(scores_label[i] != "")
+ FOREACH(Scores, true, {
+ if(scores_label(it) != "")
++t;
+ });
w = bound(6, floor(SCORESWIDTH / t - 1), 9);
p = PlayerScore_Sort(score_dummyfield, 1, 1, 0);
void PlayerScore_PlayerStats(entity p)
{
- entity s;
- float i;
- s = p.scorekeeper;
-
- for(i = 0; i < MAX_SCORE; ++i)
- if(s.(scores[i]) != 0)
- if(scores_label[i] != "")
- PS_GR_P_ADDVAL(s.owner, strcat(PLAYERSTATS_SCOREBOARD, scores_label[i]), s.(scores[i]));
+ entity s = p.scorekeeper;
+ FOREACH(Scores, true, {
+ if(s.(scores(it)) != 0)
+ if(scores_label(it) != "")
+ PS_GR_P_ADDVAL(s.owner, strcat(PLAYERSTATS_SCOREBOARD, scores_label(it)), s.(scores(it)));
+ });
}
void PlayerScore_TeamStats()
if(!sk)
continue;
for(i = 0; i < MAX_TEAMSCORE; ++i)
- if(sk.(teamscores[i]) != 0)
- if(teamscores_label[i] != "")
+ if(sk.(teamscores(i)) != 0)
+ if(teamscores_label(i) != "")
// the +1 is important here!
- PS_GR_T_ADDVAL(t+1, strcat(PLAYERSTATS_SCOREBOARD, teamscores_label[i]), sk.(teamscores[i]));
+ PS_GR_T_ADDVAL(t+1, strcat(PLAYERSTATS_SCOREBOARD, teamscores_label(i)), sk.(teamscores(i)));
}
}
#include <common/constants.qh>
entity scores_initialized; // non-NULL when scores labels/rules have been set
-.float scores[MAX_SCORE];
-.float teamscores[MAX_TEAMSCORE];
.float scoreboard_pos;
/**
* Means: FIXME make players unable to join the game when not called ClientConnect yet.
* Returns the new score.
*/
-float PlayerScore_Add(entity player, float scorefield, float score);
+float PlayerScore_Add(entity player, PlayerScoreField scorefield, float score);
/**
* Initialize the score of this player if needed.
* Adds a score to both the player and the team. Returns the team score if
* possible, otherwise the player score.
*/
-float PlayerTeamScore_Add(entity player, float pscorefield, float tscorefield, float score);
+float PlayerTeamScore_Add(entity player, PlayerScoreField pscorefield, float tscorefield, float score);
/**
* Adds to the generic score fields for both the player and the team.
*/
-#define PlayerTeamScore_AddScore(p,s) PlayerTeamScore_Add(p, SP_SCORE, ST_SCORE, s)
+#define PlayerTeamScore_AddScore(p, s) PlayerTeamScore_Add(p, SP_SCORE, ST_SCORE, s)
/**
* Set the label of a team score item, as well as the scoring flags.
/**
* Set the label of a player score item, as well as the scoring flags.
*/
-void ScoreInfo_SetLabel_PlayerScore(float i, string label, float scoreflags);
+void ScoreInfo_SetLabel_PlayerScore(PlayerScoreField i, string label, float scoreflags);
/**
* Initialize the scores info for the given number of teams.
//return boolean(c1 >= 0) + boolean(c2 >= 0) + boolean(c3 >= 0) + boolean(c4 >= 0);
}
-// NOTE: SP_ constants may not be >= MAX_SCORE; ST_constants may not be >= MAX_TEAMSCORE
+// NOTE: ST_constants may not be >= MAX_TEAMSCORE
// scores that should be in all modes:
void ScoreRules_basics(int teams, float sprio, float stprio, float score_enabled)
{
- float i;
- for(i = 0; i < MAX_SCORE; ++i)
- ScoreInfo_SetLabel_PlayerScore(i, "", 0);
- for(i = 0; i < MAX_TEAMSCORE; ++i)
+ FOREACH(Scores, true, {
+ ScoreInfo_SetLabel_PlayerScore(it, "", 0);
+ });
+ for(int i = 0; i < MAX_TEAMSCORE; ++i)
ScoreInfo_SetLabel_TeamScore(i, "", 0);
ScoreRules_teams = teams;
ScoreInfo_SetLabel_PlayerScore(SP_DMG, "damage", 0);
ScoreInfo_SetLabel_PlayerScore(SP_DMGTAKEN, "damagetaken", SFL_LOWER_IS_BETTER);
+ ScoreInfo_SetLabel_PlayerScore(SP_ELO, "elo", 0);
}
void ScoreRules_basics_end()
{
if(!found)
{
- LOG_TRACE("WARNING: spawnpoint at ", vtos(spot.origin), " could not find its target ", spot.target, "\n");
+ LOG_TRACE("WARNING: spawnpoint at ", vtos(spot.origin), " could not find its target ", spot.target);
return '-1 0 0';
}
}
#include "g_hook.qh"
#include "g_world.qh"
-#include "bot/bot.qh"
-#include "bot/waypoints.qh"
+#include "bot/api.qh"
#include "command/common.qh"
bool autocvar_sv_autopause = false;
float RedirectionThink();
-void PM_Main(Client this);
+void systems_update();
+void sys_phys_update(entity this, float dt);
void StartFrame()
{
// TODO: if move is more than 50ms, split it into two moves (this matches QWSV behavior and the client prediction)
- FOREACH_ENTITY_CLASS(STR_PLAYER, IS_FAKE_CLIENT(it), PM_Main(it));
+ FOREACH_ENTITY_CLASS(STR_PLAYER, IS_FAKE_CLIENT(it), sys_phys_update(it, frametime));
FOREACH_ENTITY_CLASS(STR_PLAYER, IS_FAKE_CLIENT(it), PlayerPreThink(it));
execute_next_frame();
if (this.gametypefilter != "")
if (!isGametypeInFilter(MapInfo_LoadedGametype, teamplay, have_team_spawns, this.gametypefilter))
{
- remove(this);
+ delete(this);
__spawnfunc_expecting = false;
return;
}
if (!inv)
{
//print("cvarfilter fail\n");
- remove(this);
+ delete(this);
__spawnfunc_expecting = false;
return;
}
if(DoesQ3ARemoveThisEntity(this))
{
- remove(this);
+ delete(this);
__spawnfunc_expecting = false;
return;
}
- this.move_movetype = this.movetype;
+ set_movetype(this, this.movetype);
// support special -1 and -2 angle from radiant
if (this.angles == '0 -1 0')
if(MUTATOR_CALLHOOK(OnEntityPreSpawn, this))
{
- remove(this);
+ delete(this);
__spawnfunc_expecting = false;
return;
}
#undef droptofloor
#undef sound
-#undef remove
#undef cvar_set
#undef cvar_string
#undef cvar
#include "scores.qh"
#include "scores_rules.qh"
-#include "bot/bot.qh"
+#include "bot/api.qh"
#include "command/vote.qh"
void test_weapons_hurt(entity this)
{
EXPECT_NE(100, this.health);
- remove(this.enemy);
- remove(this);
+ delete(this.enemy);
+ delete(this);
}
TEST(Weapons, Hurt)
void accuracy_free(entity e)
{
- remove(e.accuracy);
+ delete(e.accuracy);
}
// force a resend of a player's accuracy stats
continue;
entity wp = WaypointSprite_Spawn(
WP_Weapon,
- 1, 0,
+ -2, 0,
NULL, it.origin + ('0 0 1' * it.maxs.z) * 1.2,
cl, 0,
NULL, enemy,
// always allow selecting the Mine Layer if we placed mines, so that we can detonate them
if(wpn == WEP_MINE_LAYER)
- FOREACH_ENTITY_CLASS("mine", it.owner == this,
+ IL_EACH(g_mines, it.owner == this,
{
f = 1;
break; // no need to continue
if (weaponsInMap & WepSet_FromWeapon(wpn))
{
Send_WeaponComplain(this, wpn.m_id, 1);
- Weapon_whereis(wpn, this);
+ if(autocvar_g_showweaponspawns < 3)
+ Weapon_whereis(wpn, this);
+ else
+ {
+ FOREACH(Weapons, it.impulse == wpn.impulse,
+ {
+ Weapon_whereis(it, this);
+ });
+ }
}
else
{
}
else if(!forbidWeaponUse(this)) {
entity actor = this;
- .entity weaponentity = weaponentities[0]; // TODO: unhardcode
- w.wr_reload(w, actor, weaponentity);
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ w.wr_reload(w, actor, weaponentity);
+ }
}
}
s = M_ARGV(2, string);
if (s == "")
{
- remove(this);
+ delete(this);
startitem_failed = true;
return;
}
}
if (wpn == WEP_Null)
{
- remove(this);
+ delete(this);
startitem_failed = true;
return;
}
wep.owner = wep.enemy = own;
wep.flags |= FL_TOSSED;
wep.colormap = own.colormap;
+ wep.glowmod = weaponentity_glowmod(info, own.clientcolors);
W_DropEvent(wr_drop,own,wpn,wep);
weapon_defaultspawnfunc(wep, info);
if(startitem_failed)
return string_null;
- wep.glowmod = weaponentity_glowmod(info, own.clientcolors);
setthink(wep, thrown_wep_think);
wep.savenextthink = wep.nextthink;
wep.nextthink = min(wep.nextthink, time + 0.5);
}
// toss current weapon
-void W_ThrowWeapon(entity this, vector velo, vector delta, float doreduce)
+void W_ThrowWeapon(entity this, .entity weaponentity, vector velo, vector delta, float doreduce)
{
Weapon w = PS(this).m_weapon;
if (w == WEP_Null)
return;
if(!autocvar_g_weapon_throwable)
return;
- .entity weaponentity = weaponentities[0]; // TODO: unhardcode
if(this.(weaponentity).state != WS_READY)
return;
if(!W_IsWeaponThrowable(this, w.m_id))
bool W_IsWeaponThrowable(entity this, int w);
// toss current weapon
-void W_ThrowWeapon(entity this, vector velo, vector delta, float doreduce);
+void W_ThrowWeapon(entity this, .entity weaponentity, vector velo, vector delta, float doreduce);
void SpawnThrownWeapon(entity this, vector org, float w);
// this function calculates w_shotorg and w_shotdir based on the weapon model
// offset, trueaim and antilag, and won't put w_shotorg inside a wall.
// make sure you call makevectors first (FIXME?)
-void W_SetupShot_Dir_ProjectileSize_Range(entity ent, vector s_forward, vector mi, vector ma, float antilag, float recoil, Sound snd, float chan, float maxdamage, float range)
+void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vector s_forward, vector mi, vector ma, float antilag, float recoil, Sound snd, float chan, float maxdamage, float range)
{
- TC(Sound, snd);
+ TC(Sound, snd);
float nudge = 1; // added to traceline target and subtracted from result TOOD(divVerent): do we still need this? Doesn't the engine do this now for us?
float oldsolid;
vector vecs, dv;
if(IS_PLAYER(ent))
W_HitPlotAnalysis(ent, v_forward, v_right, v_up);
- .entity weaponentity = weaponentities[0]; // TODO: unhardcode
vector md = ent.(weaponentity).movedir;
if(md.x > 0)
vecs = md;
));
if(pseudoprojectile)
- remove(pseudoprojectile);
+ delete(pseudoprojectile);
}
// find all the entities the railgun hit and hurt them
break;
float dist_taken = max(autocvar_g_ballistics_mindistance, vlen(trace_endpos - start));
- solid_penetration_left *= (dist_taken / maxdist);
+ // fraction_used_of_what_is_left = dist_taken / maxdist
+ // solid_penetration_left = solid_penetration_left - solid_penetration_left * fraction_used_of_what_is_left
+ solid_penetration_left *= 1 - dist_taken / maxdist;
+ solid_penetration_left = max(solid_penetration_left, 0);
// Only show effect when going through a player (invisible otherwise)
if (hit && (hit.solid != SOLID_BSP))
// this function calculates w_shotorg and w_shotdir based on the weapon model
// offset, trueaim and antilag, and won't put w_shotorg inside a wall.
// make sure you call makevectors first (FIXME?)
-void W_SetupShot_Dir_ProjectileSize_Range(entity ent, vector s_forward, vector mi, vector ma, float antilag, float recoil, Sound snd, float chan, float maxdamage, float range);
+void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vector s_forward, vector mi, vector ma, float antilag, float recoil, Sound snd, float chan, float maxdamage, float range);
-#define W_SetupShot_Dir_ProjectileSize(ent,s_forward,mi,ma,antilag,recoil,snd,chan,maxdamage) W_SetupShot_Dir_ProjectileSize_Range(ent, s_forward, mi, ma, antilag, recoil, snd, chan, maxdamage, MAX_SHOT_DISTANCE)
-#define W_SetupShot_ProjectileSize(ent,mi,ma,antilag,recoil,snd,chan,maxdamage) W_SetupShot_Dir_ProjectileSize(ent, v_forward, mi, ma, antilag, recoil, snd, chan, maxdamage)
-#define W_SetupShot_Dir(ent,s_forward,antilag,recoil,snd,chan,maxdamage) W_SetupShot_Dir_ProjectileSize(ent, s_forward, '0 0 0', '0 0 0', antilag, recoil, snd, chan, maxdamage)
-#define W_SetupShot(ent,antilag,recoil,snd,chan,maxdamage) W_SetupShot_ProjectileSize(ent, '0 0 0', '0 0 0', antilag, recoil, snd, chan, maxdamage)
-#define W_SetupShot_Range(ent,antilag,recoil,snd,chan,maxdamage,range) W_SetupShot_Dir_ProjectileSize_Range(ent, v_forward, '0 0 0', '0 0 0', antilag, recoil, snd, chan, maxdamage, range)
+#define W_SetupShot_Dir_ProjectileSize(ent,wepent,s_forward,mi,ma,antilag,recoil,snd,chan,maxdamage) W_SetupShot_Dir_ProjectileSize_Range(ent, wepent, s_forward, mi, ma, antilag, recoil, snd, chan, maxdamage, MAX_SHOT_DISTANCE)
+#define W_SetupShot_ProjectileSize(ent,wepent,mi,ma,antilag,recoil,snd,chan,maxdamage) W_SetupShot_Dir_ProjectileSize(ent, wepent, v_forward, mi, ma, antilag, recoil, snd, chan, maxdamage)
+#define W_SetupShot_Dir(ent,wepent,s_forward,antilag,recoil,snd,chan,maxdamage) W_SetupShot_Dir_ProjectileSize(ent, wepent, s_forward, '0 0 0', '0 0 0', antilag, recoil, snd, chan, maxdamage)
+#define W_SetupShot(ent,wepent,antilag,recoil,snd,chan,maxdamage) W_SetupShot_ProjectileSize(ent, wepent, '0 0 0', '0 0 0', antilag, recoil, snd, chan, maxdamage)
+#define W_SetupShot_Range(ent,wepent,antilag,recoil,snd,chan,maxdamage,range) W_SetupShot_Dir_ProjectileSize_Range(ent, wepent, v_forward, '0 0 0', '0 0 0', antilag, recoil, snd, chan, maxdamage, range)
vector W_CalculateProjectileVelocity(entity actor, vector pvelocity, vector mvelocity, float forceAbsolute);
CL_WeaponEntity_SetModel(e, wi.mdl, false);
vector ret = e.movedir;
CL_WeaponEntity_SetModel(e, "", false);
- remove(e);
+ delete(e);
return ret;
}
if (this.owner.(weaponentity) != this)
{
// owner has new gun; remove old one
- if (this.weaponchild) remove(this.weaponchild);
- remove(this);
+ if (this.weaponchild) delete(this.weaponchild);
+ delete(this);
return;
}
if (IS_DEAD(this.owner))
this.nextthink = time;
if (this.owner.exteriorweaponentity != this)
{
- remove(this);
+ delete(this);
return;
}
if (IS_DEAD(this.owner))
// always keep the Mine Layer if we placed mines, so that we can detonate them
if (thiswep == WEP_MINE_LAYER)
{
- FOREACH_ENTITY_ENT(owner, actor,
+ IL_EACH(g_mines, it.owner == actor,
{
- if(it.classname != "mine") continue;
- if(it.owner == actor) return false;
+ return false;
});
}
.bool hook_switchweapon;
-void W_WeaponFrame(Player actor)
+void W_WeaponFrame(Player actor, .entity weaponentity)
{
TC(Player, actor);
TC(PlayerState, PS(actor));
- .entity weaponentity = weaponentities[0]; // TODO: unhardcode
entity this = actor.(weaponentity);
if (frametime) actor.weapon_frametime = frametime;
switch (this.state)
{
default:
- LOG_WARNINGF("unhandled weaponentity (%i) state for player (%i): %d\n", this, actor, this.state);
+ LOG_WARNF("unhandled weaponentity (%i) state for player (%i): %d", this, actor, this.state);
break;
case WS_INUSE:
case WS_RAISE:
}
else if (e)
{
- e.wr_gonethink(e, actor);
+ e.wr_gonethink(e, actor, weaponentity);
}
}
}
}
-void W_AttachToShotorg(entity actor, entity flash, vector offset)
+void W_AttachToShotorg(entity actor, .entity weaponentity, entity flash, vector offset)
{
- .entity weaponentity = weaponentities[0];
flash.owner = actor;
flash.angles_z = random() * 360;
w_ready(wpn, actor, weaponentity, PHYS_INPUT_BUTTON_ATCK(actor) | (PHYS_INPUT_BUTTON_ATCK2(actor) << 1));
}
-void W_Reload(entity actor, float sent_ammo_min, Sound sent_sound)
+void W_Reload(entity actor, .entity weaponentity, float sent_ammo_min, Sound sent_sound)
{
TC(Sound, sent_sound);
- .entity weaponentity = weaponentities[0];
// set global values to work with
Weapon e = PS(actor).m_weapon;
float forbidWeaponUse(entity player);
-void W_AttachToShotorg(entity actor, entity flash, vector offset);
+void W_AttachToShotorg(entity actor, .entity weaponentity, entity flash, vector offset);
void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use);
void W_DropEvent(.void(Weapon, entity actor) event, entity player, float weapon_type, entity weapon_item);
-void W_Reload(entity actor, float sent_ammo_min, Sound sent_sound);
+void W_Reload(entity actor, .entity weaponentity, float sent_ammo_min, Sound sent_sound);
-void W_WeaponFrame(Player actor);
+void W_WeaponFrame(Player actor, .entity weaponentity);
float W_WeaponRateFactor(entity this);
--- /dev/null
+QC
+ filter call_regexp_common C++
+ filter remove_inline //.*$
+ extension qc
+ extension inc
+ 3rd_gen_scale 0.5
+ end_of_line_continuation \\$
+QC Header
+ filter call_regexp_common C++
+ filter remove_inline //.*$
+ extension qh
+ 3rd_gen_scale 0.5
+ end_of_line_continuation \\$
-#!/bin/bash
+#!/usr/bin/env bash
set -eu
-cd "$(dirname "$0")"
+cd ${0%/*}
cd ..
function startswith() {
-#!/bin/bash
+#!/usr/bin/env bash
set -eu
-cd "$(dirname "$0")"
+cd ${0%/*}
cd ..
function check() {
check lib
check common
+check ecs
check client
check server
check menu
sp_permit_cpp11_shift = false # false/true
# Add or remove space before '(' of 'if', 'for', 'switch', and 'while'
-sp_before_sparen = add # ignore/add/remove/force #force
+sp_before_sparen = force # ignore/add/remove/force #force
# Add or remove space inside if-condition '(' and ')'
# NOTE: is 68 worse than ignore
sp_inside_sparen_open = ignore # ignore/add/remove/force #force
# Add or remove space after ')' of 'if', 'for', 'switch', and 'while'
-sp_after_sparen = add # ignore/add/remove/force
+sp_after_sparen = force # ignore/add/remove/force
# Add or remove space between ')' and '{' of 'if', 'for', 'switch', and 'while'
-sp_sparen_brace = add # ignore/add/remove/force
+sp_sparen_brace = force # ignore/add/remove/force
# Add or remove space between 'invariant' and '(' in the D language.
sp_invariant_paren = ignore # ignore/add/remove/force #ignore
sp_macro_func = remove # ignore/add/remove/force #force
# Add or remove space between 'else' and '{' if on the same line
-sp_else_brace = add # ignore/add/remove/force
+sp_else_brace = force # ignore/add/remove/force
# Add or remove space between '}' and 'else' if on the same line
# WARNING: Code doesn't seem to use this feature - delete from the config?
-sp_brace_else = ignore # ignore/add/remove/force
+sp_brace_else = force # ignore/add/remove/force
# Add or remove space between '}' and the name of a typedef on the same line
sp_brace_typedef = add # ignore/add/remove/force
# Add or remove newline between 'if' and '{'
# NOTE: is 136 worse than ignore
-nl_if_brace = add # ignore/add/remove/force
+nl_if_brace = remove # ignore/add/remove/force
# Add or remove newline between '}' and 'else'
-nl_brace_else = add # ignore/add/remove/force
+nl_brace_else = remove # ignore/add/remove/force
# Add or remove newline between 'else if' and '{'
# If set to ignore, nl_if_brace is used instead
-nl_elseif_brace = add # ignore/add/remove/force
+nl_elseif_brace = remove # ignore/add/remove/force
# Add or remove newline between 'else' and '{'
-nl_else_brace = add # ignore/add/remove/force
+nl_else_brace = remove # ignore/add/remove/force
# Add or remove newline between 'else' and 'if'
nl_else_if = remove # ignore/add/remove/force
# Add or remove newline between 'finally' and '{'
# WARNING: Code doesn't seem to use this feature - delete from the config?
-nl_finally_brace = ignore # ignore/add/remove/force
+nl_finally_brace = remove # ignore/add/remove/force
# Add or remove newline between 'try' and '{'
# WARNING: Code doesn't seem to use this feature - delete from the config?
# Add or remove newline between 'for' and '{'
# NOTE: is 109 worse than ignore
-nl_for_brace = add # ignore/add/remove/force
+nl_for_brace = remove # ignore/add/remove/force
# Add or remove newline between 'catch' and '{'
# WARNING: Code doesn't seem to use this feature - delete from the config?
# Add or remove newline between 'while' and '{'
# NOTE: is 22 worse than ignore
-nl_while_brace = add # ignore/add/remove/force
+nl_while_brace = remove # ignore/add/remove/force
# Add or remove newline between 'scope (x)' and '{' (D)
# WARNING: Code doesn't seem to use this feature - delete from the config?
#
# Add or remove braces on single-line 'do' statement
-mod_full_brace_do = add # ignore/add/remove/force
+mod_full_brace_do = force # ignore/add/remove/force
# Add or remove braces on single-line 'for' statement
# NOTE: is 3 worse than ignore
-mod_full_brace_for = remove # ignore/add/remove/force
+mod_full_brace_for = force # ignore/add/remove/force
# Add or remove braces on single-line function definitions. (Pawn)
mod_full_brace_function = ignore # ignore/add/remove/force #ignore
# Add or remove braces on single-line 'if' statement. Will not remove the braces if they contain an 'else'.
-mod_full_brace_if = add # ignore/add/remove/force
+mod_full_brace_if = force # ignore/add/remove/force
# Make all if/elseif/else statements in a chain be braced or not. Overrides mod_full_brace_if.
# If any must be braced, they are all braced. If all can be unbraced, then the braces are removed.
-mod_full_brace_if_chain = true # false/true #force
+mod_full_brace_if_chain = false # false/true #force
# Don't remove braces around statements that span N newlines
mod_full_brace_nl = 2 # number #force
# Add or remove braces on single-line 'while' statement
-mod_full_brace_while = remove # ignore/add/remove/force
+mod_full_brace_while = force # ignore/add/remove/force
# Add or remove braces on single-line 'using ()' statement
# WARNING: Code doesn't seem to use this feature - delete from the config?
mod_full_paren_if_bool = false # false/true
# Whether to remove superfluous semicolons
-mod_remove_extra_semicolon = false # false/true
+mod_remove_extra_semicolon = true # false/true
# If a function body exceeds the specified number of newlines and doesn't have a comment after
# the close brace, a comment will be added.